# eval()函数
eval() 函数可计算某个字符串,并执行其中的代码。 它的功能是把对应的字符串解析成JS代码并运行; 应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)。
eval(string)
//string 必需。要计算的字符串,其中含有要计算的 JavaScript 表达式或要执行的语句。
返回值: 通过计算 string 得到的值(如果有的话)。
欺骗词法作用域会导致性能下降。
eval(..) 函数可以接受一个字符串为参数,可以在写的代码中用程序生成代码并运行,就好像代码是写在那个位置的一样。
在执行 eval(..) 之后的代码时,引擎并不“知道”或“在意”前面的代码是以动态形式插入进来,并对词法作用域的环境进行修改的。引擎只会如往常地进行词法作用域查找。
根据这个原理来理解 eval(..),它是如何通过代码欺骗和假装成书写时(也就是词法期)代码就在那,来实现修改词法作用域环境的,这个原理就变得清晰易懂了。
function foo(str, a) {
eval( str ); // 欺骗!
console.log( a, b );
}
var b = 2;
foo( "var b = 3;", 1 ); // 1, 3
//在严格模式下, eval(..) 在运行时有其自己的词法作用域,意味着其
//的声明无法修改所在的作用域。
function foo(str) {
"use strict";
eval( str );
console.log( a ); // ReferenceError: a is not defined
}
foo( "var a = 2" );
eval(..) 调用中的 "var b = 3;" 这段代码会被当作本来就在那里一样来处理。由于那段代码声明了一个新的变量 b ,因此它对已经存在的 foo(..) 的词法作用域进行了修改。
警告
JS中还有其他一些效果 eval()相似。setTimeout(..)和setInterval(..)的第一个参数可以是字符串,字符串的内容可以被解释为一段动态生成的函数代码。这些功能已经过时且并不被提倡。
new Function(..) 函数的行为也很类似,最后一个参数可以接受代码字符串,并将其转化为动态生成的函数(前面的参数是这个新生成的函数的形参)。这种构建函数的语法比eval(..) 略微安全一些,但也要尽量避免使用。
# 解析json对象
var dataObj=eval("("+data+")");
# 为什么eval这里要添加("("+data+")") ?
由于json是以{ }的方式来开始以及结束的,在eval中会被当成一个语句块来处理,故必须强制将它转换成一种表达式。 加上圆括号是使eval函数在处理时强制将括号内的表达式(expression)转化为对象而不作为语句(statement)来执行。若不加外层的括号,eval会将大括号识别为js代码块的开始和结束标记,{ }将会被认为执行了一句空语句。
不建议在开发中使用eval:
- 代码的可读性非常的差(代码的可读性是高质量代码的重要原则);
- eval是一个字符串,那么有可能在执行的过程中被刻意篡改,那么可能会造成被攻击的风险;
eval的执行必须经过JS解释器,不能被JS引擎优化;