eval和new Function均可以将一段字符串解析成一段JS脚本并执行。javascript
① eval: java
eval做为一个方法,直接传入要解析的字符串便可。app
const foo = "foo"; // 定义了一个变量foo const str = "console.log(foo)"; eval(str); // 解析str字符串中包含JS脚本并执行,输出foo
② new Function:
JS中的每一个函数都是 Function 类型的实例,即JS中全部的函数的proto都指向Function的prototype,或者说,JS中全部的函数都是由Function构造出来的。函数
new Function() 能够接n个参数,最后一个参数做为函数体。this
let func = new Function ([arg1[, arg2[, ...argN]],] functionBody);
let foo = new Function("name", "console.log(name)"); // 建立的函数指向Function的原型 console.log(foo.__proto__ === Function.prototype); // true // 等价于 function foo(name) { console.log(name); }
能够看到Function的最后一个参数字符串"console.log(name)"也被解析成了JS脚本,而且做为函数体执行了。prototype
须要注意的是,传入的字符串不是任意的,必须是能当作JS脚本正常执行的字符串。code
const str = "{'foo': '123'}"; const obj = eval(str); console.log(obj); // 报错信息以下 VM1061:1 Uncaught SyntaxError: Unexpected token ':' at <anonymous>:2:18
由于传入"{'foo': foo}"的时候,{}会被解析为代码块,至关于直接执行const str = "'foo': foo";解决方法能够在外层加上一个括号,如:token
const str = "({'foo': '123'})"; const obj = eval(str); console.log(obj);// {foo: '123'}
eval中的代码执行时的做用域为当前做用域。它能够访问到函数中的局部变量。
new Function中的代码执行时的做用域为全局做用域,不论它的在哪一个地方调用的,它访问的都是全局变量。ip
let foo = "foo"; function bar() { let foo = "bar"; eval("console.log(foo)"); // 输出bar new Function("console.log(foo)")(); // 输出foo } bar();
从输出结果能够看出,new Function访问到的始终是全局做用域中的变量;eval访问到的则是当前做用域中的变量。
固然若是使用的是window.eval()或者global.eval()那么访问到的也始终是全局做用域中的变量作用域
let foo = "foo"; function bar() { let foo = "bar"; window.eval("console.log(foo)"); // 输出foo new Function("console.log(foo)")(); // 输出foo } bar();
此时输出都是foo了
若是全局做用域中没有指定的变量,那么将会报错,提示该变量没有定义。
function bar() { let foo = "bar"; window.eval("console.log(foo)"); // 报错 new Function("console.log(foo)")(); // 报错 } bar(); // 报错信息以下 VM1051:1 Uncaught ReferenceError: foo is not defined at eval (eval at bar ((index):3), <anonymous>:1:13) at eval (<anonymous>) at bar (<anonymous>:3:12) at <anonymous>:6:1
在Vue生成渲染函数的时候会使用到,Vue中进行模板编译的时候,最终会将模板编译成一段可执行JS字符串,而后传递给new Function生成渲染函数,渲染(挂载)的时候,执行这个渲染函数拿到对应的虚拟DOM节点,如:
// template模板 <div id="app" style="color: red;background: blue;"><p>hello {{name}}</p>{{msg}}</div>
// 解析模板生成一段字符串,即渲染函数要执行的字符串 let code = _c("div", {id: "app",style: {"color":" red","background":" blue"}},_c("p", undefined,_v("hello"+_s(name))),_v(_s(msg)))
// 将渲染函数要执行的字符串传入new Function()生成渲染函数 let renderFn = new Function(`with(this) {return ${code}}`);
等到渲染的时候,就会执行渲染函数,即renderFn(),此时就会执行code所指的字符串,拿到对应的虚拟DOM节点,进行patch最终更新真实的DOM节点。