当前位置: 首页 > news >正文

深入理解new Function

基础语法

let func = new Function([arg1,arg2,arg3,...argN],functionBody)

函数是通过使用参数 arg1…argN 和给定的 functionBody 创建。

调用 Function 时可以使用或不使用 new,两者都会创建一个新的 Function 实例

举例1: 带有两个参数的函数

let sum = new Function('a', 'b', 'return a + b');
console.log(sum(1, 2)); // 3let sum1 = new Function('a', ' b', 'return a + b');
console.log(sum1(1, 2)); // 3let sum2 = new Function('a,b', 'return a + b');
console.log(sum2(1, 2)); // 3let sum3 = new Function('a , b', 'return a + b');
console.log(sum3(1, 2)); // 3let sum4 = new Function(['a,b'], 'return a + b');
console.log(sum4(1, 2)); // 3

Function函数最后一个参数永远都是函数体,由于历史原因函数的参数部分支持以逗号分割的形式展示

举例2: 一个没有参数的函数,自由函数体,没有参数的函数,在函数被调用的时候,等价于调用函数体里面的函数

const sumOfArray = new Function("const sumArray = (arr) => arr.reduce((previousValue, currentValue) => previousValue + currentValue); return sumArray",
)();// 调用函数 调用的是sumOfArray函数 但实际执行的是sumArray函数
console.log(sumOfArray([1, 2, 3, 4]))
// 10

new Function 没有参数的时候,实际上返回的是一个匿名函数(就是你传入的函数体)

解析过程

new Function的解析过程是先解析参数部分再解析函数体部分,如果参数部分有异常就会直接抛出异常,函数体就不会被执行,只有参数部分没有异常,才会解析函数体部分。这种解析方式确保了逐步验证的过程,可以防止通过传递非法参数或函数体的方式进行代码注入攻击。比如,不允许通过参数注入注释符号 /* 来破坏整个函数的结构。也就在一定程度上防止代码注入的逻辑

匿名函数

使用 new Function 后,传递的参数和函数体会被动态编译(下文会详细讲)为一个函数表达式,其编译后的代码组装方式如下

`function anonymous(${args.join(",")}
) {
${functionBody}
}`;

与普通的函数表达式不同,anonymous 这个名字不会被添加到 functionBody 的作用域中,因为 functionBody 只能访问全局作用域

anonymous 的这种编译后的组装格式,可以通过 toString() 函数查看。举个例子

const queryCondition = "return obj.age > 30 && obj.country === 'USA';"; 
const queryFunc = new Function('obj', queryCondition);
console.log(queryFunc.toString());
// function anonymous(obj
) {
return obj.age > 30 && obj.country === 'USA';
}

作用域

闭包是指使用一个特殊的属性 [[Environment]] 来记录函数自身的创建时的环境的函数。它具体指向了函数创建时的词法环境。

但是 new Function 创建一个函数,那么该函数的 [[Environment]] 并不指向当前的词法环境,而是指向全局环境,Function 构造函数创建的函数仅在全局作用域中执行。因此,此类函数无法访问外部(outer)变量,只能访问全局变量。

let a = 1
let fn = function () {let a = 2let result1 = new Function('console.log(a)')let result2 = function () {console.log(a)}result1() //打印出1,访问的是全局变量aresult2() //打印出2
}
fn()
// new Function这样的函数不能访问外部变量,只能访问全局变量
// 虽然这段代码可以在浏览器中正常运行,但在 Node.js 中,result1() 执行会报错,因为找不到变量 a。
// 这是因为,在 Node 中,顶级作用域不是全局作用域

严格模式下或Node中

let value2 = "芝士outer";
function getFunc() {let value = "芝士inter";let func = new Function('alert(value)');return func;
}
function getFunc2() {let func = new Function('alert(value2)');return func;
}// getFunc()(); // error: value is not defined
getFunc2()();   // error: value2 is not defined

new Function和eval的区别

与Function只能访问全局作用域不同的是,eval中的代码执行时的作用域为当前作用域。它可以访问到函数中的局部变量。

let a = 1
let fn = function () {let a = 2console.log(eval('a+8')); //10let result2 = function () {console.log(a)}result2() //打印出2
}
fn()

eval是一个危险的函数,它使用与调用者相同的权限执行代码。如果你用eval运行的字符串被 不怀好意的进行恶意修改,可能会造成全局污染或者一些不同方式的代码攻击。

eval函数通常比其他函数方法解析的更慢,因为它必须调用js解析器进行解析,而其他的函数可能被现代js引擎直接优化。

应用场景

new Function 应用场景其实还蛮多的,主要涉及的方面是动态代码执行、沙箱环境以及性能优化等。

1、动态执行代码
在一些低代码或无代码平台中,用户可能会输入自定义的 JavaScript 代码,平台需要即时执行这些代码。通过 new Function,可以将用户输入的字符串直接解析并执行。例如:

const userInput = "return a + b;";
const dynamicFunction = new Function('a', 'b', userInput);
console.log(dynamicFunction(2, 3)); // 输出 5

这种场景常见于表单计算器、在线编程环境或数据分析工具中,允许用户定义自定义的计算公式或规则。

2、模版引擎中的表达式解析

在一些模板引擎(如 Vue.js 的 v-bind、Angular 的模板表达式)中,开发者可能会通过字符串表达式绑定数据或属性。为了提高执行效率和灵活性,框架有时会通过 new Function 来生成一个能够动态计算表达式的函数。例如:

const expression = "data.a + data.b";
const compute = new Function('data', `return ${expression}`);
console.log(compute({a: 1, b: 2})); // 输出 3

通过 new Function 动态编译模板表达式,可以避免每次都对表达式重新进行解析和计算,提高性能。

3、JSONPath或XPath解析器

在数据查询场景中,像 JSONPath 或 XPath这种解析器,用户的查询条件通常是通过字符串输入的。 解析器需要根据用户输入的查询条件动态执行查询操作。这类解析器中,new Function 有时用于生成查询逻辑的动态函数,以便在大规模数据上进行快速计算和过滤。

/ 用户输入的查询条件
const queryCondition = "return obj.age > 30 && obj.country === 'USA';";
// 动态生成一个查询函数
const queryFunc = new Function('obj', queryCondition);// 用于查询的JSON数据
const data = [{ name: 'Alice', age: 35, country: 'USA' },{ name: 'Bob', age: 28, country: 'UK' },{ name: 'Charlie', age: 40, country: 'USA' }
];// 动态过滤数据
const result = data.filter(queryFunc);
console.log(result); // [{ name: 'Alice', age: 35, country: 'USA' }, { name: 'Charlie', age: 40, country: 'USA' }]

4、性能优化避免eval

new Function 与 eval 类似,可以动态执行字符串代码,但相比于 eval,new Function 的作用域更为严格。它只允许访问全局作用域,不能直接访问当前上下文的局部变量。因此,new Function 在某些需要动态执行代码的场景下比 eval 更安全,也更快,常用于替代 eval

5、表单验证或计算

在复杂的动态表单中,可能需要根据用户的输入动态生成验证规则或者计算结果。new Function 可以根据用户定义的规则生成函数,实时验证表单字段或计算结果:

const rule = "return value > 10;";
const validate = new Function('value', rule);
console.log(validate(15)); // 输出 true

6、JavaScript沙箱实现

某些框架需要隔离用户输入的代码与主应用逻辑,创建安全的沙箱环境。通过 new Function,可以限制代码的作用域,防止访问不安全的全局变量。这种方式在在线 IDE 或某些插件系统中较为常见。

new Function 不太合适的场景和弊端注意点*

在将 JavaScript 发布到生产环境之前,需要使用 压缩程序(minifier) 对其进行压缩。

压缩程序(minifier)工作原理:

  • 压缩程序用于优化 JavaScript 代码,将变量名压缩成更短的名称,并删除注释、空格等无关内容。这样做能减少代码体积,提升性能。
  • 压缩时,局部变量(如 let userName)会被替换为较短的变量名(如 let a),所有引用该变量的地方也会同步替换。

new Function 访问外部变量的限制

  • 使用 new Function 创建的函数不会像普通函数那样能够访问外部的词法作用域(即闭包环境)。它只能访问传递给它的参数和全局变量
  • 在 new Function 中,即使我们尝试引用外部定义的变量(如 userName),由于新函数的词法作用域与外部环境隔离,它是无法直接访问这些变量的

压缩程序的影响:

  • 假设代码在开发时有一个变量 let userName,而你在 new Function 中尝试访问它。压缩后,userName 可能会变成 a。但 new Function 在代码压缩后才被执行,它不会知道压缩后变量名的变化,因此会导致访问出错
  • 例如,如果你的代码中有:
  • let userName = "John"; const func = new Function("return userName;");
    压缩后,userName 可能被替换为 a,但是 new Function 生成的函数依然试图访问 userName,结果会报错,因为压缩程序不会知道 new Function 中定义的内容。

正确方式:显式传递数据:

  • 因为 new Function 无法访问外部变量,并且会受到压缩影响,推荐的做法是显式通过函数参数传递需要使用的数据,而不是依赖外部变量
  • 例如:
  • let userName = "John"; const func = new Function('name', 'return name;'); console.log(func(userName)); // 这样可以正常工作 返回John

相关文章:

深入理解new Function

基础语法 let func new Function([arg1,arg2,arg3,...argN],functionBody)函数是通过使用参数 arg1…argN 和给定的 functionBody 创建。 调用 Function 时可以使用或不使用 new,两者都会创建一个新的 Function 实例 举例1: 带有两个参数的函数 let sum new Fun…...

服务器训练神经网络必备工具Screen使用教程

使用服务器训练网络时,不敢关闭终端窗口?用screen~ 服务器训练神经网络必备工具Screen使用教程 使用服务器训练网络时,不敢关闭终端窗口?用screen~一、Screen常用命令1. 启动新会话2. 重新连接会话3. 列出所有会话4. 窗口管理5. 断…...

跨越数字鸿沟,FileLink文件摆渡系统——您的数据安全高效传输新选择

在这个信息爆炸的时代,数据的流通与共享已成为推动各行各业发展的关键力量。然而,随着数据量的激增,如何在保证数据安全的前提下,实现高效、便捷的文件传输,成为了众多企业和个人用户面临的重大挑战。正是在这样的背景…...

递归之吃桃问题

题目如下: XXX买了一堆桃子不知道个数,第一天吃了一半的桃子,还不过瘾,又多吃了一个。以后他每天吃剩下的桃子的一半还多一个,到 n 天只剩下一个桃子了。XXX想知道一开始买了多少桃子。 首先我们看到题目就应该想边界…...

CZX前端秘籍2

vue生命周期( 组件从创建到销毁的过程就是它的生命周期) 创建前 beforeCreat( 在这个阶段属性和方法都不能使用) 创建时 created( 这里时实例创建完成之后, 在这里完成了数据监测, 可以使用数…...

CAD图纸防泄密用什么加密软软件?2024年10款图纸加密软件排行榜

在当今数字化时代,企业对于CAD图纸的保护越来越重视,因为图纸往往包含着公司的核心技术和商业机密。选择合适的加密软件对于防止数据泄露、维护企业利益至关重要。以下是2024年10款备受推崇的CAD图纸加密软件排行榜,帮助您更好地保护您的设计…...

WebGL编程指南 - WebGL入门

初识绘图流程、缓冲区、着色器、attribute和uniform变量 先画一个蓝色的正方形 html代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content&…...

mysql--数据类型

目录 搞定所有数据类型 一、常见数据类型分类 二、数值类型 1、bit类型 2、float类型 ​编辑3、decimal类型 4、字符类型 &#xff08;1&#xff09;char &#xff08;2&#xff09;varchar &#xff08;3&#xff09;varchar和char有甚区别&#xff1f; &#xff0…...

代码随想录第40天|

#include <bits/stdc.h> using namespace std;vector<list<int>> graph; // 删除局部 graph&#xff0c;使用全局 graph vector<vector<int>> res; vector<int> path; int N, M;void dfs(int index) {if (index N) {res.push_back(path);…...

Turn-it:优化线材重构雕塑制造

&#x1f428;文章摘要abstract 电线雕塑在工业应用和日常生活中都很重要。 本文提出了一种新的制造策略&#xff0c;通过调整目标形状以适应电线弯曲机&#xff0c;然后由人工将其弯曲回目标形状。&#xff08;机器弯曲人工弯曲&#xff09; 该方法通过两阶段弯曲策略实现&a…...

微深节能 堆取料机动作综合检测系统 格雷母线

微深节能的堆取料机动作综合检测系统结合了格雷母线定位系统&#xff0c;是工业自动化领域的一项重要创新。该系统通过集成多种传感器和控制设备&#xff0c;实现对堆取料机的全面监控和精确控制&#xff0c;包括位置、速度、力度、振动以及工作状态等。格雷母线定位系统作为一…...

【JAVA面试题】什么是Springboot的自动配置以及注意事项

文章目录 强烈推荐核心概念&#xff1a;自动配置的关键特点&#xff1a;示例&#xff1a; 需要注意的点1.默认配置可能不适合所有场景2.Bean 冲突与覆盖3.应用启动慢的问题4.过度依赖自动配置5.安全性问题6.依赖冲突与版本兼容7.过多不必要的自动配置8.调试困难 专栏集锦 强烈推…...

华为鸿蒙开发笔记

记在前面 官方文档链接 因无法直接使用chatgpt进行编程(悲,2024/10),故记录笔记,方便查阅,基于arkts语言 DevEco 中文 deveco是默认有中文包的,所以在市场里面搜不错,而应该在已安装里面搜索,然后启用就行了 测试 对ts进行单独测试 打开entry/src/test/LocalUnit.test.…...

Go语言Gin框架的常规配置和查询数据返回json示例

文章目录 路由文件分组查询数据库并返回jsonservice层controller路由运行效果 启动多个服务 在 上一篇文章《使用Go语言的gorm框架查询数据库并分页导出到Excel实例》 中主要给大家分享了较多数据的时候如何使用go分页导出多个Excel文件并合并的实现方案&#xff0c;这一篇文章…...

JavaEE----多线程(二)

文章目录 1.进程的状态2.线程的安全引入3.线程安全的问题产生原因4.synchronized关键字的引入4.1修饰代码块4.2修饰实例方法4.3修饰静态方法4.4对象头介绍4.5死锁-可重入的特性 5.关于死锁的分析总结5.1死锁的分析5.2死锁成因的必要条件5.3死锁的解决方案 1.进程的状态 public…...

【K8S】快速入门Kubernetes

之前企业都是使用容器化和来构建自己的服务和应用程序&#xff0c;其中容器化优点有很多&#xff1a;提升了部署效率、稳定性、提高了资源的利用率降低了成本。 但是也带来了一些新的问题&#xff1a;容器的数量变得很多&#xff0c;管理就是一个新的问题。所以Kubernetes就出…...

如何在 MySQL 中处理大量的 DELETE 操作??

全文目录&#xff1a; 开篇语前言摘要简介概述DELETE 操作的基本概念常用的 DELETE 方法 核心源码解读简单 DELETE 语句批量 DELETE 示例 案例分析案例1&#xff1a;使用简单 DELETE 删除用户数据案例2&#xff1a;使用分批 DELETE 应用场景演示场景1&#xff1a;用户管理系统场…...

LabVIEW中句柄与引用

在LabVIEW中&#xff0c;句柄&#xff08;Handle&#xff09; 是一种用于引用特定资源或对象的标识符。它类似于指针&#xff0c;允许程序在内存中管理和操作复杂的资源&#xff0c;而不需要直接访问资源本身。句柄用于管理动态分配的资源&#xff0c;如队列、文件、网络连接、…...

【三十四】【QT开发应用】音量图标以及滑动条,没有代码补全的小技巧

效果展示 鼠标位于音量图标区域内&#xff0c;显示出滑动条。鼠标移出音量图标区域内滑动条隐藏。鼠标点击音量图标&#xff0c;如果此时音量为0&#xff0c;音量变成50&#xff0c;如果此时音量不为零&#xff0c;音量变为0。 CVolumeButton.h 音量图标头文件 #pragma once …...

Android修改第三方应用相机方向

以下修改基于Android7.1 diff --git a/frameworks/base/core/java/android/hardware/Camera.java b/frameworks/base/core/java/android/hardware/Camera.java index 8c7434b..7201481 100755 --- a/frameworks/base/core/java/android/hardware/Camera.java b/frameworks/ba…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA

浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求&#xff0c;本次涉及的主要是收费汇聚交换机的配置&#xff0c;浪潮网络设备在高速项目很少&#xff0c;通…...

深度学习水论文:mamba+图像增强

&#x1f9c0;当前视觉领域对高效长序列建模需求激增&#xff0c;对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模&#xff0c;以及动态计算优势&#xff0c;在图像质量提升和细节恢复方面有难以替代的作用。 &#x1f9c0;因此短时间内&#xff0c;就有不…...