本博客 hjy-xh,转载请申明出处
相关定义和描述
eval 是全局对象上的一个函数,会把传入的字符串当做 JavaScript 代码执行,它通常被用来执行动态创建的代码。
语法很简单:
1 >eval(string) // 一个表示 JavaScript 表达式、语句或一系列语句的字符串。表达式可以包含变量与已存在对象的属性。
举个🌰
1 | const string = "console.log('hello, eval')"; |
先提出问题:eval这个方法很强大,且兼容性很好,但是为什么很少使用?
一些特性
返回最后一个表达式的值
1 | console.log(eval('1+1+1')); // 3 |
1 | let string1 = 'let x; x = 1;'; |
函数作为字符串被定义时需要”(“和”)“作为前缀和后缀
1 | const funcStr1 = 'function test() {}'; |
直接调用和间接调用
1 | let x = 1, y = 1; |
1 | (0, eval)('this') |
逗号操作符:对它的每个操作数求值(从左到右),并返回最后一个操作数的值
这里使用逗号操作符,于是返回表达式中的最后一项,然后为eval传入’this’字符串,来立即执行这个表达式,这里其实就是把全局对象给打印出来
黑魔法
欺骗词法作用域
原理:JavaScript中的eval(str)函数可以接受一个字符串为参数,并将字符串内容视为好像在书写时就存在于eval()函数所在位置的代码。
1 | function foo(str, a) { |
这个例子中var b = 3;
这条语句会被当做本来就在那里,因此foo函数内部的变量b遮蔽了外部的变量b
严格模式下的表现
在严格模式下,eval在运行时会有自己的词法作用域,意味着其中的声明无法修改所在的作用域
1 | function foo(str, a) { |
使用时有哪些坑
eval不容易调试
调试困难,且可读性非常差(没有行号)
用chromeDev、VSCode等工具无法打断点调试
性能问题
JavaScript 通常被认为是一门解释型的语言,但是现代的 JavaScript 引擎不再只是解释 JavaScript,也会对其进行编译。
V8 为了提高 JS的运行性能,在运行之前会先将JS编译为本地的机器码,然后再去执行机器码(JIT)。
现代JavaScript解释器将javascript转换为机器代码。 这意味着任何变量命名的概念都会被删除。 因此,任意一个eval的使用都会强制浏览器进行冗长的变量名称查找,以确定变量在机器代码中的位置并设置其值。 另外,新内容将会通过 eval() 引进给变量, 比如更改该变量的类型,因此会强制浏览器重新执行所有已经生成的机器代码以进行补偿。
eval破坏了JS引擎优化
安全问题
当使用来源不可靠的第三方代码时,无法保证不碰到恶意代码
参考
《你不知道的JavaScript》 上卷