用Function代替eval

一个eval()的运用栗子

1
2
3
4
5
// 求数组中的最大值
var arr = [6, 4, 1, 8, 2, 11, 23];
// 这里的arr隐式转换了一下
var max = eval("Math.max(" + arr + ")");
console.log(max)

eval() 是全局对象的一个函数属性

参数是一个字符串。如果字符串表示的是表达式,eval() 会对表达式进行求值。

如果 eval() 的参数不是字符串, eval() 会将参数原封不动地返回。

1
2
3
4
5
eval(new String("2 + 2")); // 返回了包含"2 + 2"的字符串对象
eval("2 + 2"); // returns 4
// 绕过限制
var expression = new String("2 + 2");
eval(expression.toString());

但是,不建议用eval()

  • 它使用与调用者相同的权限执行代码,第三方代码可以看到某一个 eval() 被调用时的作用域; 字符串代码被恶意方(不怀好意的人)修改。
  • 比其他替代方法更慢,因为它必须调用 JS 解释器,而许多其他结构则可被现代 JS 引擎进行优化。

Function代替eval

1
new Function ([arg1[, arg2[, ...argN]],] functionBody)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// eval
function looseJsonParse(obj){
return eval(obj);
}
console.log(looseJsonParse(
"{a:(4-1), b:function(){}, c:new Date()}"
))
// 代替
function looseJsonParse(obj){
return Function('"use strict";return (' + obj + ')')();
}
console.log(looseJsonParse(
"{a:(4-1), b:function(){}, c:new Date()}"
))

上面代码eval()要慢得多。

1
2
3
4
5
6
// 我们回到最初那个求max的eval
const max = (...rest) => {
let _arr = Array.isArray(rest) ? rest : [];
const fn = new Function("arr", `${"return Math.max("+ _arr.toString() + ")"}`);
return fn();
}
1
2
3
4
5
6
7
8
9
10
11
12
// 一个更复杂栗子
function Date(n){
return ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"][n%7 || 0];
}
function runCodeWithDateFunction(obj){
return Function('"use strict";return (' + obj + ')')()(
Date
);
}
console.log(runCodeWithDateFunction(
"function(Date){ return Date(5) }"
))
-------------要说再见啦感谢大佬的光临~-------------