【问题标题】:Why use "with" keyword in JavaScript? [duplicate]为什么在 JavaScript 中使用“with”关键字? [复制]
【发布时间】:2010-12-28 05:17:36
【问题描述】:

可能重复:
Are there legitimate uses for JavaScript’s “with” statement?

我最近发现在 JavaScript 中,可以执行以下操作:

with (document) {
    write('foo');
    body.scrollTop = x;
}

这样做的缺点是需要检查每个变量是否属于文档对象,从而产生很大的开销。

或者,可以这样做:

var d = document;
d.write('foo');
d.body.scrollTop = x;

在哪些情况下使用'with'关键字是合理的?

【问题讨论】:

标签: javascript


【解决方案1】:

只是不要使用它: http://yuiblog.com/blog/2006/04/11/with-statement-considered-harmful/

JavaScript 的with 语句旨在为编写对对象的重复访问提供简写。所以不要写

ooo.eee.oo.ah_ah.ting.tang.walla.walla.bing = true;
ooo.eee.oo.ah_ah.ting.tang.walla.walla.bang = true;

你可以写

with (ooo.eee.oo.ah_ah.ting.tang.walla.walla) {
    bing = true;
    bang = true;
}

这样看起来好多了。除了一件事。您无法通过查看 bingbang 将被修改的代码来判断。 ooo.eee.oo.ah_ah.ting.tang.walla.walla 会被修改吗?或者全局变量bingbang 会被破坏吗?不可能确定...

如果您无法阅读程序并确信您知道它会做什么,那么您就无法确信它会正确运行。因此,应避免使用with 语句...

【讨论】:

  • 我无法充分表达这一点:任何类似“with”的语法,例如 JavaScript 和 Delphi 的语法,您没有明确指定哪些标识符属于“作用域”对象,并且哪个不是,是邪恶,不要在那些语言中使用那种语法。特别是,未来的更改可能会在没有警告的情况下更改该代码的行为。如果这不是等待发生的错误,那么我不知道是什么。
  • 例如,Visual Basic.NET 做对了,msdn.microsoft.com/en-us/library/wc500chb(VS.80).aspx,它们强制您在属于范围对象的所有标识符前面加上一个点。
  • 是的,VB(.NET 和之前的版本)做对了,但他们也弄错了:如果你使用后期绑定,你仍然会遇到同样的问题。使用with 的性能比没有使用时要慢(出于任何奇怪的原因)。
  • @John:我能找到的唯一理由是使用它时代码变得更清晰。如果您发现自己处于这种情况,您可以使用它...
  • @John (2):关于理由,请查看 Annie 的回答:stackoverflow.com/questions/1931186/with-keyword-in-javascript/…
【解决方案2】:

尽管几乎到处都有相反的建议,但我认为“with”是有用途的。例如,我正在为 Javascript 开发一个域模型框架,它使用下划线字符的方式与 jQuery 使用“$”的方式非常相似。这意味着如果没有“with”,我的代码中有很多下划线分散在代码中,从而降低了可读性。这是使用该框架的应用程序中的随机行:

_.People().sort(_.score(_.isa(_.Parent)),'Surname','Forename');

而“with”看起来像

with (_) {
    ...

    People().sort(score(isa(Parent)),'Surname','Forename');

    ...
}

真正有用的是只读版本的“with”。

【讨论】:

  • 并不总是 SLOWER 运行时会给您带来副作用。如果你不运行它一千次,它可以忽略不计。
  • 如今,使用 ES6 对象解构,您可以改为使用 const { People, score, isa, Parent } = _;,而不会带来 with (_) 的所有令人讨厌的风险。
  • @CamJackson 是的,但人们必须注意解构会克隆属性的值。因此,如果属性的值是原始的,那么它实际上不会写入原始对象。这不会影响具有对象值的属性,因为它们只是对该数据的引用:``` const person = { name: "Harry Potter", };让{姓名}=人; name = "德拉科马尔福"; // 分配给临时原语 console.log(person.name); // Harry Potter ``` 因此,最好使用const { ... } = foo
【解决方案3】:

我会避免在生产代码中使用它,因为它不明确,但是对于 for-loop-closure 解决方案有另一种解决方案,即使用 with 模仿 let 绑定,这是我之前回答的副本:

在 for 循环中使用函数的标准闭包解决方案的替代方案:

<a  href="#">blah</a><br>
<a  href="#">blah</a><br>
<a  href="#">foo</a><br>
<script>
    (function() {
    var anchors = document.getElementsByTagName('a');
        for ( var i = anchors.length; i--; ) {
            var link = anchors[i];
            with ({ number: i }) {
                link.onclick = function() {
                    alert(number);
                };
            }
        }
    })();
</script>

感谢nlogax 提供的解决方案,我几乎抄袭了: Javascript infamous Loop issue?

这是标准解决方案:

<script>
    (function() {
    var anchors = document.getElementsByTagName('a');
    for ( var i = anchors.length; i--; ) {
        var link = anchors[i];
        (function(i) {
            link.onclick = function() {
                alert(i)
            }
        })(i);
    }
    })();
</script>

【讨论】:

  • 请确保说明哪一部分是“模棱两可的”,因为 JavaScript 解释器和/或编译器永远不会混淆标识符的用途。问题在于未来的变化和/或程序员可能将标识符解释为什么。
  • 现在有了现代的const 范围规则,您不需要两者中的任何一个。只需说for (var i=anchors.length; i--;) { const ii = i; .. alert(ii) ..。甚至更好:for (let i=..) .. alert(i) .. 因为let 引入了它自己的循环范围。请注意,在现代浏览器中,像您这样的简单示例可以进一步缩短:document.getElementsByTagName('a').forEach((link,i) =&gt; link.onclick = () =&gt; alert(i)) 但这是完全不同的故事。
猜你喜欢
  • 2010-11-25
  • 1970-01-01
  • 2011-06-28
  • 2014-01-09
  • 2019-12-07
  • 2017-11-21
  • 1970-01-01
  • 2011-05-25
  • 2013-10-12
相关资源
最近更新 更多