如果你现在的代码中使用了 eval()
,记住该咒语“eval()
是魔鬼”。此方法接受任意的字符串,并当作 JavaScript 代码来处理。当有问题的代码是事先知道的(不是运行时确定的),没有理由使用 eval()
。如果代码是在运行时动态生成,有一个更好的方式不使用 eval
而达到同样的目标。例如,用方括号表示法来访问动态属性会更好更简单:
// 反面示例
var property = 'name'
alert(eval('obj.' + property))
// 更好的
var property = 'name'
alert(obj[property])
使用 eval()
也带来了安全隐患,因为被执行的代码(例如从网络来)可能已被篡改。这是个很常见的反面教材,当处理 Ajax 请求得到的 JSON 相应的时候。在这些情况下,最好使用 JavaScript 内置方法来解析 JSON 相应,以确保安全和有效。若浏览器不支持 JSON.parse()
,你可以使用来自 JSON.org 的库。
同样重要的是要记住,给 setInterval()
,setTimeout()
和 Function()
构造函数传递字符串,大部分情况下,与使用 eval()
是类似的,因此要避免。在幕后,JavaScript 仍需要评估和执行你给程序传递的字符串:
// 反面示例
setTimeout('myFunc()', 1000)
setTimeout('myFunc(1, 2, 3)', 1000)
// 更好的
setTimeout(myFunc, 1000)
setTimeout(function () {
myFunc(1, 2, 3)
}, 1000)
使用新的 Function()
构造就类似于 eval()
,应小心接近。这可能是一个强大的构造,但往往被误用。如果你绝对必须使用 eval()
,你可以考虑使用 new Function()
代替。有一个小的潜在好处,因为在新 Function()
中作代码评估是在局部函数作用域中运行,所以代码中任何被评估的通过 var
定义的变量都不会自动变成全局变量。另一种方法来阻止自动全局变量是封装 eval()
调用到一个即时函数中。
考虑下面这个例子,这里仅 un
作为全局变量污染了命名空间。
console.log(typeof un) // "undefined"
console.log(typeof deux) // "undefined"
console.log(typeof trois) // "undefined"
var jsstring = 'var un = 1; console.log(un);'
eval(jsstring) // logs "1"
jsstring = 'var deux = 2; console.log(deux);'
new Function(jsstring)() // logs "2"
jsstring = 'var trois = 3; console.log(trois);'
;(function () {
eval(jsstring)
})() // logs "3"
console.log(typeof un) // number
console.log(typeof deux) // "undefined"
console.log(typeof trois) // "undefined"
另一间 eval()
和 Function
构造不同的是 eval()
可以干扰作用域链,而 Function()
更安分守己些。不管你在哪里执行 Function()
,它只看到全局作用域。所以其能很好的避免本地变量污染。在下面这个例子中,eval()
可以访问和修改它外部作用域中的变量,这是 Function
做不来的(注意到使用 Function
和 new Function
是相同的)。
;(function () {
var local = 1
eval('local = 3; console.log(local)') // logs "3"
console.log(local) // logs "3"
})()
;(function () {
var local = 1
Function('console.log(typeof local);')() // logs undefined
})()