Alan Storm对我关于with声明的回答的评论引起了我的思考。我很少找到使用这个特殊语言特性的理由,也从来没有想过它可能会带来什么麻烦。现在,我很好奇如何有效地利用with,同时避免它的陷阱。

你觉得with语句在哪里有用?


当前回答

我只是不明白使用with比直接输入object。member有什么更好读的地方。我不认为它的可读性有任何下降,但我也不认为它的可读性有任何提高。

就像lassevk说的,我可以肯定地看到使用with比使用非常显式的“object”更容易出错。成员”语法。

其他回答

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

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

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

如果不仔细研究这些函数调用,就无法知道这段代码运行后程序的状态是什么。如果user.name已经设置,它现在将是Bob。如果没有设置,全局名称将被初始化或更改为Bob,用户对象将保持没有name属性。

错误发生。如果你使用with,你最终会这样做,增加你的程序失败的机会。更糟糕的是,您可能会遇到在with块中设置全局变量的工作代码,或者是故意的,或者是作者不知道这个构造的怪处。这很像在开关上遇到了故障,你不知道作者是否有意这样做,也没有办法知道“修复”代码是否会引入回归。

现代编程语言充满了特性。一些特性,在使用多年后,被发现是不好的,应该避免使用。Javascript的with就是其中之一。

不推荐使用with,在ECMAScript 5严格模式下禁止使用。推荐的替代方法是将您想要访问其属性的对象分配给一个临时变量。

来源:Mozilla.org

对于一些简短的代码片段,我想在度模式中使用sin, cos等三角函数,而不是在辐射模式中。为此,我使用了一个AngularDegreeobject:

AngularDegree = new function() {
this.CONV = Math.PI / 180;
this.sin = function(x) { return Math.sin( x * this.CONV ) };
this.cos = function(x) { return Math.cos( x * this.CONV ) };
this.tan = function(x) { return Math.tan( x * this.CONV ) };
this.asin = function(x) { return Math.asin( x ) / this.CONV };
this.acos = function(x) { return Math.acos( x ) / this.CONV };
this.atan = function(x) { return Math.atan( x ) / this.CONV };
this.atan2 = function(x,y) { return Math.atan2(x,y) / this.CONV };
};

然后我可以使用三角函数在度模式没有进一步的语言噪音在一个with块:

function getAzimut(pol,pos) {
  ...
  var d = pos.lon - pol.lon;
  with(AngularDegree) {
    var z = atan2( sin(d), cos(pol.lat)*tan(pos.lat) - sin(pol.lat)*cos(d) );
    return z;
    }
  }

这意味着:我使用一个对象作为函数的集合,我在有限的代码区域中启用它以便直接访问。我发现这很有用。

Visual Basic。NET有一个类似的With语句。我使用它的一个比较常见的方法是快速设置一些属性。而不是:

someObject.Foo = ''
someObject.Bar = ''
someObject.Baz = ''

,我可以这样写:

With someObject
    .Foo = ''
    .Bar = ''
    .Baz = ''
End With

这不仅仅是懒惰的问题。它还使代码可读性更强。与JavaScript不同的是,它不会出现歧义,因为您必须在受语句影响的所有内容前加上a。(点)。所以,下面两个是明显不同的:

With someObject
    .Foo = ''
End With

vs.

With someObject
    Foo = ''
End With

前者是someObject.Foo;后者是someObject作用域外的Foo。

我发现JavaScript缺乏区分使得它远不如Visual Basic的变体有用,因为歧义的风险太高了。除此之外,with仍然是一个强大的想法,可以提高可读性。

当您需要将对象结构从平面转换为层次结构时,With与简写对象表示法结合使用非常有用。如果你有:

var a = {id: 123, name: 'abc', attr1: 'efg', attr2: 'zxvc', attr3: '4321'};

所以不要:

var b = {
    id: a.id,
    name: a.name
    metadata: {name: a.name, attr1: a.attr1}
    extrastuff: {attr2: a.attr2, attr3: a.attr3}
}

你可以简单地写:

with (a) {
    var b = {
        id,
        name,
        metadata: {name, attr1}
        extrastuff: {attr2, attr3}
    }
}