4

我仍然觉得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);
}

所以我可以直接引用 --like Math--的属性PI,不用说Math.PI. 这很好,但有点没用。

谁能提供一个有趣的用法示例with

4

6 回答 6

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臭名昭著的循环问题?

这是标准解决方案:

<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>
于 2009-11-04T19:27:35.263 回答
4

这里应该说with,JavaScript 中的声明已被广泛弃用。

参见 Douglas Crockford 的With Statement Considered Harmful

我不能说比他做得更好(说真的,请点击链接),但简而言之,如果你这样做:

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

如果您正在为 mySuperLongObjectReferenceThatIHateTyping 对象或全局对象(窗口)的属性分配值,则无法通过查看该代码来知道。

克罗克福德建议这样做:

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

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

(function(o) {
  o.propertyAlpha = 'a';
  o.propertyBeta = 2;
  o.propertyGamma = false;
})(mySuperLongObjectReferenceThatIHateTyping);
于 2009-11-04T19:35:18.383 回答
3

John Resig 的 javascript 微模板展示了 with 的一些有趣用途。

于 2009-11-04T19:41:17.943 回答
2

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

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

此外,我至少使用过一次将对象的属性分配给局部变量,而不必存储对对象本身的引用。

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

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会严重影响性能,因为在解析任何变量名称时必须首先检查您添加到词法环境的对象的原型链。

于 2009-11-04T19:39:55.377 回答
1

JS 中的 with 语句类似于 VB.net 中的 with 语句。这只是一种避免重复对象的属性/方法的方法。

例如,假设标签控件正在根据事件/动作进行修改。该标签控件具有诸如 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
于 2009-11-04T19:26:24.437 回答
1

我在 Javascript 方面没有经验,刚刚开始了解应该如何使用它,所以我的意见不应该与有特定语言经验的人一样重要。我会对我的想法的回应感兴趣。

我一直在尝试一种定义类对象的风格,这种对象依赖于 Javascript with语句。我认为这是合法使用。

这种风格中的每个类对象都作为对象的工厂来满足某些目的。

这种风格没有在实例方法中使用this关键字。

这种风格认为从这些类对象之一生成的每个对象都具有公共方面和私有方面。一个 Javascript 对象代表了这些方面中的每一个。对象引用的持有者实际上只指公共方面。然而,这些方法知道这两个方面,我用闭包来实现这一点。

我不会假装这种风格适用于我们非常关心运行时间或内存性能的情况。我故意牺牲了其中的相当一部分来提高编程效率。我希望找到很多我想要快速编程并且几乎没有错误机会的情况,并且运行时的需求并不重要。

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

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

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

最终,当我开始使用类对象作为其实例的工厂时,每当我向它请求新实例时,它都会为实例创建公共和私有方面,将私有方面链接到公共方面,然后调用所有已定义的初始化程序,将新实例的私有方面传递给它们。

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

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

初始化器可以做的另一件事是在公共端或私有端添加一个方法。

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

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

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

于 2012-04-14T20:15:32.567 回答