深入理解Js里new Function语法

简介: 深入理解Js里new Function语法

一般我们不会使用用 new Function 构造函数的,因为没必要,直接使用 function 或者 箭头函数写法更简单。但并不是说new Function 构造函数无用。在一些特别的场景,比如函数体的数据格式是字符串的时候,new Function 构造函数的作用就显示出来了。之前也是仅仅知道此方法,但是没有具体的研究搞懂,但是最近一两年一直在倒腾低代码的项目,原理上来说,低代码都是一堆字符串,为了解析字符串就使用了new Function 构造函数(eval方法也是可以的),在此在记录一下,加深理解。详情参见:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions

1、语法

备注: 不推荐使用 Function 构造函数创建函数,因为它需要的函数体作为字符串可能会阻止一些 JS 引擎优化,也会引起其他问题。把 Function 的构造函数当作函数一样调用 (不使用 new 操作符) 的效果与作为 Function 的构造函数调用一样。

let func = new Function ([arg1, arg2, ...argN], functionBody);
//等价于 let func = Function ([arg1, arg2, ...argN], functionBody);

<font color="red">Function构造函数所有的参数都是字符串类型。除了最后一个参数, 其余的参数都作为生成函数的参数即形参。这里可以没有参数。最后一个参数, 表示的是要创建函数的函数体。</font>

//传入参数
let sum = new Function('a', 'b', 'return a + b');
console.log( sum(1, 2) ); // 3
//不传入参数
let sum = new Function('console.log(1)');
console.log( sum() ); // 1

由于历史原因,new Function参数也可以以逗号分隔的列表形式给出。下边这三个声明的含义相同:

new Function('a', 'b', 'return a + b'); 
new Function('a,b', 'return a + b'); 
new Function('a , b', 'return a + b');

2、作用域

Function()构造函数和函数有一点就是:使用构造函数Function()创建的函数不使用当前的词法作用域,相反的,它们总是被顶级函数来编译,因此在运行时它们只能访问全局变量和自己的局部变量.

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

想象一下,我们必须从一个字符串创建一个函数。该函数的代码在编写脚本时是未知的,但是会在执行过程中知道。我们可能会从服务器或其他地方接收到它。此时我们的新函数需要与主脚本交互,如果它此时它可以访问外部变量,那么就可以操作外部变量,改变外部变量,这样就会引发不可预估的风险。

3、使用

假如有一个非合法 JSON 对象字符串,如下:

let str = "{ name: '小坦克', code: 100 }" 
  JSON.parse(str) // 会报错,因为str字段是不符合规范的对象字符串(key,value都必须是"",双引号包裹)

可以使用new Function

let str = "{ name: '小坦克', code: 100 }" 
  let result =  JSON.parse(new Function('return ' + str)()) // result = { name: '小坦克', code: 100 }

4、new Function和eval的区别

eval中的代码执行时的作用域为当前作用域。它可以访问到函数中的局部变量。

let a = 1
let fn = function(){
  let a = 2
  let result1 = new Function('console.log(a)')
  let result2 = eval('console.log(a)') //打印出2
  result1() //打印出1,访问的是全局变量a
}
fn()

永远不要使用 eval !!!

eval() 是一个危险的函数, 它使用与调用者相同的权限执行代码。如果你用 eval() 运行的字符串代码被恶意方(不怀好意的人)修改,您最终可能会在您的网页/扩展程序的权限下,在用户计算机上运行恶意代码。更重要的是,第三方代码可以看到某一个 eval() 被调用时的作用域,这也有可能导致一些不同方式的攻击。相似的 Function 就不容易被攻击

eval() 通常比其他替代方法更慢,因为它必须调用 JS 解释器,而许多其他结构则可被现代 JS 引擎进行优化。

此外,现代 JavaScript 解释器将 JavaScript 转换为机器代码。这意味着任何变量命名的概念都会被删除。因此,任意一个 eval 的使用都会强制浏览器进行冗长的变量名称查找,以确定变量在机器代码中的位置并设置其值。另外,新内容将会通过 eval() 引进给变量,比如更改该变量的类型,因此会强制浏览器重新执行所有已经生成的机器代码以进行补偿。但是(谢天谢地)存在一个非常好的 eval 替代方法:只需使用 window.Function。这有个例子方便你了解如何将eval()的使用转变为Function()。

相关文章
|
3月前
|
JavaScript
ES6学习(9)js中的new实现
ES6学习(9)js中的new实现
|
4月前
|
存储 JavaScript 前端开发
Node.js的基本语法
【8月更文挑战第12天】Node.js的基本语法
156 1
|
1月前
|
设计模式 JavaScript 前端开发
js中new和object.creat区别
【10月更文挑战第29天】`new` 关键字和 `Object.create()` 方法在创建对象的方式、原型链继承、属性初始化以及适用场景等方面都存在差异。在实际开发中,需要根据具体的需求和设计模式来选择合适的方法来创建对象。
|
2月前
|
JavaScript 前端开发
JavaScript 函数语法
JavaScript 函数是使用 `function` 关键词定义的代码块,可在调用时执行特定任务。函数可以无参或带参,参数用于传递值并在函数内部使用。函数调用可在事件触发时进行,如用户点击按钮。JavaScript 对大小写敏感,函数名和关键词必须严格匹配。示例中展示了如何通过不同参数调用函数以生成不同的输出。
构造函数(function)可以使用 new 生成实例,箭头函数可以吗
构造函数使用 `new` 关键字可以生成实例对象,而箭头函数则不能用作构造函数,因为它没有自己的 `this` 上下文,使用 `new` 调用会抛出错误。
|
2月前
|
JavaScript 前端开发 大数据
在JavaScript中,Object.assign()方法或展开语法(...)来合并对象,Object.freeze()方法来冻结对象,防止对象被修改
在JavaScript中,Object.assign()方法或展开语法(...)来合并对象,Object.freeze()方法来冻结对象,防止对象被修改
40 0
|
3月前
|
JavaScript 前端开发
一个js里可以有多少个async function,如何用最少的async function实现多个异步操作
在 JavaScript 中,可以通过多种方法实现多个异步操作并减少 `async` 函数的数量。
|
4月前
|
JavaScript 前端开发
JavaScript基础&实战(1)js的基本语法、标识符、数据类型
这篇文章是JavaScript基础与实战教程的第一部分,涵盖了JavaScript的基本语法、标识符、数据类型以及如何进行强制类型转换,通过代码示例介绍了JS的输出语句、编写位置和数据类型转换方法。
JavaScript基础&实战(1)js的基本语法、标识符、数据类型
|
4月前
|
SQL JavaScript 前端开发
【Azure 应用服务】Azure JS Function 异步方法中执行SQL查询后,Callback函数中日志无法输出问题
【Azure 应用服务】Azure JS Function 异步方法中执行SQL查询后,Callback函数中日志无法输出问题
|
4月前
|
前端开发 JavaScript 程序员
前端 JavaScript 的 _ 语法是个什么鬼?
前端 JavaScript 的 _ 语法是个什么鬼?