JavaScript中,为什么eval和with会有性能问题?

Posted dora-zc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript中,为什么eval和with会有性能问题?相关的知识,希望对你有一定的参考价值。

词法作用域

词法作用域意味着作用域是由书写代码时函数声明的位置来决定的。编译的词法分析阶段 基本能够知道全部标识符在哪里以及是如何声明的,从而能够预测在执行过程中如何对它 们进行查找。

eval(..) 和 with

javascript 中有两个机制可以“欺骗”词法作用域:eval(..) 和 with。前者可以对一段包 含一个或多个声明的“代码”字符串进行演算,并借此来修改已经存在的词法作用域(在 运行时)。后者本质上是通过将一个对象的引用当作作用域来处理,将对象的属性当作作 用域中的标识符来处理,从而创建了一个新的词法作用域(同样是在运行时)。

这两个机制的副作用是引擎无法在编译时对作用域查找进行优化,因为引擎只能谨慎地认 为这样的优化是无效的。使用这其中任何一个机制都将导致代码运行变慢。不要使用它们。

性能

eval(..) 和 with 会在运行时修改或创建新的作用域,以此来欺骗其他在书写时定义的词法作用域。 你可能会问,那又怎样呢?如果它们能实现更复杂的功能,并且代码更具有扩展性,难道不是非常好的功能吗?答案是否定的。

JavaScript 引擎会在编译阶段进行数项的性能优化。其中有些优化依赖于能够根据代码的 词法进行静态分析,并预先确定所有变量和函数的定义位置,才能在执行过程中快速找到标识符。

但如果引擎在代码中发现了 eval(..) 或 with,它只能简单地假设关于标识符位置的判断 都是无效的,因为无法在词法分析阶段明确知道 eval(..) 会接收到什么代码,这些代码会如何对作用域进行修改,也无法知道传递给 with 用来创建新词法作用域的对象的内容到底是什么。

最悲观的情况是如果出现了 eval(..) 或 with,所有的优化可能都是无意义的,因此最简 单的做法就是完全不做任何优化。

如果代码中大量使用 eval(..) 或 with,那么运行起来一定会变得非常慢。无论引擎多聪 明,试图将这些悲观情况的副作用限制在最小范围内,也无法避免如果没有这些优化,代码会运行得更慢这个事实。

摘抄自《你不知道的JavaScript上卷》

以上是关于JavaScript中,为什么eval和with会有性能问题?的主要内容,如果未能解决你的问题,请参考以下文章

被嫌弃的eval和with

被嫌弃的eval和with

JS高级——with语句eval函数严格模式

JavaScript语言精粹_鸡肋

JS额外知识补充:with语句&eval语句&严格模式

JavaScript中eval()和$.parseJSON()的区别和联系以及JSON.stringify()的区别