本文主要是介绍eval is evil!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
http://www.guhaodi.com/2014/06/29/eval-is-evil/
eval 函数传递一个字符串给 JavaScript 编译器,并且执行其结果.
上面是 JavaScript eval() 函数的定义.语法如下:
eval( string )
用法说明:
- 向
eval()
传递一个包含一个或者多个表达式的字符串,eval()
会调用 JavaScript 编译器,计算并返回表达式的值. - 不用给
eval()
传递一个只包含算术表达式的字符串,因为 JavaScript 会自动计算算术表达式. - 如果
evla()
的参数不是一个字符串,那么,函数不会对参数做任何改变,并且原封不动地返回它.
从上面的介绍看,貌似 eval()
的功能还蛮强大的,它能执行任何传入的 JavaScript 表达式!
那么,为什么大家都建议代码里不要使用 eval()
,甚至不适用它都已经成为一个标准(JSLint中不允许出现eval())了.
主要有下面两个原因:
- 安全性太差.尽管
eval()
功能很强大,但恰恰因为它能执行传入的 JavaScript 表达式,并且用户通常能使用第三方插件找到你的代码中什么地方调用了eval()
,这样就极大增加了你被攻击的可能性. - 性能低.
eval()
在执行的时候需要调用 JavaScript 编辑器,这会影响程序的性能.JSON.parse vs eval 解析 JSON 的性能对比
基于以上原因, eval()
并不受开发者欢迎.甚至,国外的 JavaScript 大师 Douglas Crockford(JSON 和 JSLint 都是他提出和创建的) 在他的畅销书 JavaScript: The Good Parts(JavaScript 语言精粹)中明确把 eval()
列为 JavaScript 语言中的糟粕…而且在他的编程规范里禁用 eval()
.
那么,既然我们要尽量不使用 eval()
,又有哪些方式可以代替它呢?
可以针对 eval()
常用的情形给出下面两个方法:
1. 解析 JSON 的时候
我以前在处理一个 JSON 字符串的时候,如果要把它解析成一个对象,通常会使用 eval(‘(‘ + jsonStr + ‘)’)
的方式解析.
在了解到 eval()
的可怕后,开始改用 JSON.parse
(对应的,还有 JSON.stringify
方法用来解析成JSON字符串)的方法.
JSON.parse 的优点:
- 只是把 JSON 字符串解析成对象,不执行表达式,没有像
eval()
那样的安全性问题. - 不调用 JavaScript 编译器,性能完爆 eval()
JSON.parse 的缺点: 只有主流浏览器支持原生 JSON 对象,老的,过时的浏览器没有这个方法.
所以,要想在解析 JSON 的时候,用 JSON.parse
完全取代 eval()
,你必须解决浏览器支持的问题.
Note: 事实上, JSON.parse 是基于 Douglas Crockford 对 JSON 的安全解析方法.JSON.parse 的方法中也使用了 eval(),只不过在使用 eval() 之前,验证了传入 eval() 的字符串是一个合法,安全的字符串,这使得 JSON.parse 能够安全解析 JSON.
为了解决这个问题,推荐你直接引用 Douglas Crockford 在 GitHub 上分享的解决方案,选一个作为你的代码的依赖文件.
或者,也可以自己写一个模拟的 JSON 对象,一个 polyfill:
if (!window.JSON) {window.JSON = {parse: function (sJSON) { return eval("(" + sJSON + ")"); },stringify: function (vContent) {if (vContent instanceof Object) {var sOutput = "";if (vContent.constructor === Array) {for (var nId = 0; nId < vContent.length; sOutput += this.stringify(vContent[nId]) + ",", nId++);return "[" + sOutput.substr(0, sOutput.length - 1) + "]";}if (vContent.toString !== Object.prototype.toString) { return "\"" + vContent.toString().replace(/"/g, "\\$&") + "\"";}for (var sProp in vContent) { sOutput += "\"" + sProp.replace(/"/g, "\\$&") + "\":" + this.stringify(vContent[sProp]) + ",";}return "{" + sOutput.substr(0, sOutput.length - 1) + "}";}return typeof vContent === "string" ? "\"" + vContent.replace(/"/g, "\\$&") + "\"" : String(vContent);}};
}
上面这段代码是从这里搬运来的.只要把它放在你代码的最前面就好了.
可惜的是,这段代码还是使用了 eval()
,而且没有对传入的字符串加任何安全验证.效果跟直接使用 eval()
是一样的.
再或者,你如果放弃治疗的话,还可以这样…
if(window.JSON){// 用 JSON.parse
}else{// 用 eval()
}
2. 使用类似 eval() 的方法的时候
JavaScript 中还有其他函数,比如 Function()构造函数, setTimeout() 和 setInterval()
也跟 eval()
一样会执行字符串中的表达式.
比如:
setTimeout('window.location.reload()',1000); // 1秒后刷新页面
上面的代码中 setTimeout()
执行了字符串中的代码.实际上跟 eval()
是一样的.
为了解决这个问题,可以用函数来代替字符串传入 setTimeout()
:
setTimeout(function(){window.location.reload(); // 同样能在1秒后刷新页面
},1000);
总结
eval()
低效又不安全,能不用的话,尽量就别用它吧~改成用上面的方式取代它.
这篇关于eval is evil!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!