【问题标题】:Performance Implications of With StatementsWith 语句的性能影响
【发布时间】:2015-04-23 12:37:38
【问题描述】:

好的,所以,在过去的 48 小时里,我已经看到了这个问题,我需要将其作为一个问题提出来。在“JavaScript for Professional Web Developers”(2012 年)中,它与MDN 中的含义相同:

不建议使用 with 语句,因为它可能是来源 令人困惑的错误和兼容性问题。

不过,Zakas 的书中还指出(没有进一步的实质性阐述)“[出于性能原因,不应使用它们”。这个问题显然“已经够糟糕了”,以至于在Strict 模式下,ECMAScript 不允许使用with 语句。

这真的是出于性能原因吗?还是因为人们实在受不了?

如果实际上部分是由于性能,它们如何以及为什么会对性能产生负面影响?

【问题讨论】:

  • 可能反过来,有人在 MDN 上引用了这本书,但没有注明出处。

标签: javascript with-statement


【解决方案1】:

with 语句的问题都源于同一个问题:使用with 时,作用域变得复杂

考虑以下示例:

with (foo) {
    with (bar) {
        return x;
    }
}

这看起来很简单,但实际上可以有各种可能的结果。

  1. 如果定义了foo并且它有一个名为bar的属性并且bar有一个名为x的属性,则返回foo.bar.x .
  2. 如果未定义foo,但定义了bar,并且它有一个名为x 的属性,则返回bar.x
  3. 如果定义了foo,但它没有名为bar 的属性,则使用window 查找来检索bar

名单还在继续。所以行为有各种各样的可能性,所有这些都是脆弱的,因此可能存在错误,但为什么这是一个性能问题?

好吧,考虑一下:

return foo.bar.x;

没有任何with 语句,这对于JavaScript 引擎来说很容易优化。范围内是否有一个名为 foo 的变量(使用 var 声明)?如果是这样,请使用它。如果没有,请执行window 查找。这几乎可以静态确定。

使用with 时,每一个变量查找都需要在运行时动态确定。如果您指的是with 块内的全局变量,引擎仍然必须检查该属性是否存在于与with 一起使用的对象上。如果with 块是嵌套的,那就更糟了。

使用with 会使行为变得如此复杂,以至于在大多数情况下,JavaScript 优化器只会放弃,因为它会抛出大量编译时保证。 如果范围是动态确定的,而不是词法确定的,就很难推理了。

所以是的,这也是为什么使用with 是一个坏主意的另一个原因。不惜一切代价避免它。

【讨论】:

  • 我认为你有点过于复杂了。传递给 with 的对象位于作用域链的顶部,因此标识符首先在对象上解析,然后在作用域链上解析。不过,变量声明变得更有趣了。
  • @RobG 是的,当然。关键是我用粗体包含的内容。如果没有with,许多变量引用可以静态执行,因为一切都是词法范围的。使用 with 有效地为 所有 可能的变量引用引入了动态范围,这会抛弃所有潜在的优化。
猜你喜欢
  • 2012-10-05
  • 2021-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-15
  • 2018-01-06
  • 1970-01-01
相关资源
最近更新 更多