“with”关键字的任何非平凡且有用的示例示例?

时间:2009-11-04 19:15:46

标签: javascript with-statement

我仍然找到with关键字...... 神秘

简而言之,with的行为如下:

with (obj) {
    // do stuff
}

这会将obj添加到作用域链的头部,然后执行with-block。当块完成时,它会从作用域链的头部移除obj

根据MDC,这可以让你做像

这样的事情
var a, x;
var r = 10;
with(Math) {
    a = PI * r * r;
    x = r * cos(PI / 2);
}

所以我可以直接引用Math的属性 - 例如PI - 而不是Math.PI。哪个好,但有点无用。

任何人都可以提供with的有趣用法示例吗?

6 个答案:

答案 0 :(得分:5)

使用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>

答案 1 :(得分:4)

这里应该说JavaScript中的with语句被广泛弃用。

见Douglas Crockford的With Statement Considered Harmful

我不能说比他做得更好(严肃地说,按照链接),但总之如果你这样做:

with (mySuperLongObjectReferenceThatIHateTyping) {
  propertyAlpha = 'a';
  propertyBeta = 2;
  propertyGamma = false;
}

如果要为mySuperLongObjectReferenceThatIHateTyping对象或全局对象(窗口)的属性赋值,则无法通过查看该代码来了解。

Crockford建议:

var o = mySuperLongObjectReferenceThatIHateTyping;
o.propertyAlpha = 'a';
o.propertyBeta = 2;
o.propertyGamma = false;

这是明确的。或者你甚至可以使用一个函数,因此你有范围而不创建另一个全局变量:

(function(o) {
  o.propertyAlpha = 'a';
  o.propertyBeta = 2;
  o.propertyGamma = false;
})(mySuperLongObjectReferenceThatIHateTyping);

答案 2 :(得分:3)

John Resig's javascript microtemplating显示了一些有趣的用途。

答案 3 :(得分:2)

我经常使用它为style对象添加多个CSS属性,例如

with(document.body.style) {
    color = 'green';
    background = 'red';
}

此外,我使用它at least once将对象的属性分配给局部变量,而不必存储对象本身的引用。

当您想要获取变量值的“快照”时,它也是闭包的替代方法:

var foo = [];
for(var i = 10; i--;)
    with({ i : i }) foo[i] = function() { document.writeln(i); };

// prints 0..9
for(var i = 0; i < foo.length; ++i)
    foo[i]();

请记住,with会严重影响性能,因为在解析任何变量名时,必须先检查添加到词法环境中的对象的原型链。

答案 4 :(得分:1)

JS中的with语句就像VB.net中的with语句一样。 它只是一种避免重复使用对象的属性/方法的方法。

例如,假设正在根据事件/操作修改标签控件。那 label控件具有FontColor,CSSClass,Visibility等属性。

而不是程序员写作:

myLabel.FontColor=Color.Blue
myLabel.CSSClass="SomeCSSClass"
myLabel.Visiblity=True
myLabel.Text = "Hello World"

我们可以将其缩短为:

With myLabel
  .Text = "Hello World"
  .FontColor = Color.Blue
  .CssClass="SomeCSSClass"
  .Visibility=True
End With

答案 5 :(得分:1)

我对Javascript没有经验,只是开始明白如何认为应该使用它,所以我的意见不应该与具有特定语言经验的人相同。我会对我的想法做出回应。

我一直在试验一种定义类似对象的风格,这些对象依赖于带有语句的Javascript 。我认为这是合法用途。

此样式中的每个类类对象都充当对象的工厂以满足某些目的。

此样式不会在实例方法中使用 this 关键字。

这种风格认为,由这些类类对象之一生成的每个对象都具有公共方面和私有方面。 Javascript对象表示这些方面中的每一个。对象的引用持有者实际上只涉及公共方面。但是,这些方法都知道这两个方面,我用闭包实现了这个方法。

我并不假装此样式适用于我们非常关心运行时或内存性能的情况。我故意牺牲了每一个编程效率。我希望能找到很多我希望快速编程并且几乎没有错误机会的情况,以及运行时的需求并不重要的地方。

由于我一直在浏览器而不是node.js中尝试代码,因此对我来说开发环境的实际考虑是大型源文件中的语法错误很难确定并纠正。我通过以小增量添加代码来解决这个问题。因此,我希望类类对象能够一次接受实例方法定义,而不是要求所有方法定义都出现在一个源文件中。

我最初在没有定义任何实例方法的情况下声明了一个类类对象,并将类类对象放在我编程的任何命名空间中。

然后我在一个名为“init”的方法中重复调用类类对象,每次都传递一个初始化器,这是一个在实例初始化期间调用的函数。 / p>

最后,当我开始使用类类对象作为其实例的工厂时,每当我要求它为一个新实例时,它会为实例创建公共和私有方面,将私有方面链接到公共方面,然后调用已定义的所有初始值设定项,向它们传递新实例的私有方面。

在我的风格中,每个公共属性都是一种方法。其值不是函数的所有变量都应该存在于私有端。

初始化程序可以做的一件事是在私有端建立一个变量。

初始化程序可以做的另一件事是在公共或私有方面添加方法。

顺序对于执行初始化程序很重要 - 类似于类的对象需要按照定义它们的相同顺序执行它们。因此,每个初始化程序都可以依赖具有由早期初始化程序建立的属性的实例的公共和私有方面。对于程序员来说,这实际上创建了一对词法范围,因为初始化器不是由任何类型的条件或动态代码建立的;它们的建立是因为浏览器在读取和解析源文件后立即执行它们。

现在在某些语言中,特别是Ruby语言和Self语言,您可以编写一个裸标识符,并将其解释为对当前对象的方法调用。所以在Ruby中,“foo”可以表示“self.foo”,而在“自我”中,“foo”可以表示“自我foo”(方法调用的语法在这些语言之间有所不同,但达到我所说的详细程度)现在的语义,Ruby中的“self.foo”和Self中的“self foo”是相同的)。这个“self”存在的缩写对于调用私有方法和实例变量特别方便。 Javascript语言不提供这种便利。

在实例方法中的上下文中,我想使用私有或公共方面的属性作为其值(注意,而不是在赋值的左侧),我喜欢通过引用属性的方便性只是它的名字而不必写“vars”。或“自我”。在它的左边找到它(我使用“vars”表示私有方面,“self”表示公共方面)。出于这个原因,我将每个初始化程序包装在带有语句的Javascript 中。这对我来说似乎是合法的,因为在我的风格中,目标对象的数量是通过词汇法建立的。要查看属性,程序员只需要查看源文件中前面提供的初始化器到同一个类的对象(它本身在源代码中用名称标识,因此出于软件工程目的,我们可以将其视为一个词法实体,即使没有Javascript解析器检测到这个)。