模板解析和执行字符串有以下几种方法eval、new Function()、setTimeout、setInterval。这些方法在不考虑使用场景时,主要区别在运行环境的判断上。
作用域
eval中的代码执行时的作用域为当前作用域。它可以访问到函数中的局部变量。
var s = 'global';
function a() {
eval('var s = "local"');
console.log(s); // local
console.log(eval('s')); // local
console.log(window.eval('s')); // global
}
new Function中的代码执行时的作用域为全局作用域,不论它的在哪个地方调用的。所以它访问的是全局变量a。它根本无法访问b函数内的局部变量。
let a = 'global'
let b = () => {
let a = 'local'
eval('console.log(a)') //local
(new Function('console.log(a)'))() //global
}
b()
eval和new Function()解析json字符串
-
eval
var jsonStr = '{ "age": 20, "name": "jack" }'; var a = eval(`(${jsonStr})`);//加上括号会变成表达式,不加会吧{}当成代码块直接返回'{}'中的结果 console.log(a) //{age: 20, name: "jack"}
-
new Function()
JSON.parse使用的是 new Function()
var jsonStr = '{ "age": 20, "name": "jack" }'; var a = (new Function('return ' + jsonStr))() console.log(a) //{age: 20, name: "jack"}
eval
eval和new Function中均可以使用debugger打断点
eval存在性能问题且eval不可预测,所以浏览器将会使用slow path模式 ,所以会慢
new Function()
-
没参数
创建一个空的函数
-
只有一个参数
参数就是函数体
let func = new Function('console.log(111)') func() //111
-
多个参数
最后一个为函数体,前面的参数为函数的形参
let func = new Function('a','b','return a+b') func(1,2) //3
setInterval()、setTimeout()
- 第一个参数可以试函数名、匿名函数、函数引用以及可执行的代码
eval和new Function()面试题
var a,b,c;
(function(){
eval('var b = 2');
(1, eval)('var c = 3'); 逗号操作符,括号表达式,返回的是最后一个挂载在window上的eval
(new Function('var a = 4'))();
console.log('<br>a: ' + a); //undefined
console.log('<br>b: ' + b); //2
console.log('<br>c: ' + c); //3
})()
console.log('<br>a: ' + a); //undefined
console.log('<br>b: ' + b); //undefined
console.log('<br>c: ' + c); //3