JavaScript的“with”语句是否有合法用途?

艾伦风暴的响应我的回答有关意见with说法让我思考。 我很少找到使用这种特定语言功能的理由,也从未考虑过它会如何引起麻烦。 现在,我很好奇,我怎么可能有效利用with ,同时避免其陷阱。

你在哪里发现with语句有用?


今天我发现了另一种用法,所以我兴奋地搜索了网页,并发现了一个现有的内容:在块范围内定义变量。

背景

尽管JavaScript与C和C ++表面相似,但它并没有将变量的范围限制在它们所定义的块中:

var name = "Joe";
if ( true )
{
   var name = "Jack";
}
// name now contains "Jack"

在循环中声明闭包是一个常见的任务,这可能会导致错误:

for (var i=0; i<3; ++i)
{
   var num = i;
   setTimeout(function() { alert(num); }, 10);
}

由于for循环没有引入新的作用域,因此所有三个函数都会共享相同的num - 值为2

一个新的范围: letwith

通过在ES6中引入let语句,在必要时引入一个新范围以避免这些问题变得很容易:

// variables introduced in this statement 
// are scoped to each iteration of the loop
for (let i=0; i<3; ++i)
{
   setTimeout(function() { alert(i); }, 10);
}

甚至:

for (var i=0; i<3; ++i)
{
   // variables introduced in this statement 
   // are scoped to the block containing it.
   let num = i;
   setTimeout(function() { alert(num); }, 10);
}

在ES6普遍可用之前,这种用法仍然局限于最新的浏览器和愿意使用转发器的开发人员。 不过,我们可以使用易于模仿这种行为with

for (var i=0; i<3; ++i)
{
   // object members introduced in this statement 
   // are scoped to the block following it.
   with ({num: i})
   {
      setTimeout(function() { alert(num); }, 10);
   }
}

循环现在按预期工作,创建三个单独的变量,其值在0到2之间。请注意,在块内声明的变量没有作用域,与C ++中块的行为不同(在C中,变量必须在一个块,所以它是相似的)。 这种行为实际上与早期版本的Mozilla浏览器中引入的let语法非常相似,但在其他地方尚未广泛采用。


我一直使用with语句作为范围导入的简单形式。 假设你有某种标记生成器。 而不是写作:

markupbuilder.div(
  markupbuilder.p('Hi! I am a paragraph!',
    markupbuilder.span('I am a span inside a paragraph')
  )
)

你可以改为写:

with(markupbuilder){
  div(
    p('Hi! I am a paragraph!',
      span('I am a span inside a paragraph')
    )
  )
}

对于这个用例,我没有做任何任务,所以我没有与之相关的模糊问题。


正如我先前的评论指出,我不认为你可以使用with安全无论多么诱人它可能在任何给定的情况。 由于这里没有直接涉及这个问题,所以我会重复一遍。 考虑下面的代码

user = {};
someFunctionThatDoesStuffToUser(user);
someOtherFunction(user);

with(user){
    name = 'Bob';
    age  = 20;
}

在仔细研究这些函数调用的情况下,在代码运行后无法确定程序的状态。 如果user.name已经设置,它现在将是Bob 。 如果未设置,全局name将被初始化或更改为Bob ,并且user对象将保持不带name属性。

错误发生。 如果你和你一起使用,最终会这样做,并增加你的程序失败的几率。 更糟糕的是,你可能会遇到工作代码,它会在block中设置一个全局的地方,或者故意地或者通过作者不知道构造的这个怪癖。 这很像在交换机上遇到问题,你不知道作者是否打算这样做,也无法知道“修复”代码是否会引入回归。

现代编程语言充斥着各种功能。 经过多年使用后,有些功能被发现是不好的,应该避免。 Javascript的with是其中之一。

链接地址: http://www.djcxy.com/p/40841.html

上一篇: Are there legitimate uses for JavaScript's "with" statement?

下一篇: What does it mean that Javascript is a prototype based language?