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

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


当前回答

你可以在W3schools http://www.w3schools.com/js/js_form_validation.asp上看到javascript表单的验证,其中对象表单被“扫描”,以找到名称为“email”的输入

但我已经修改了它,从任何形式的所有字段验证为不空,无论名称或数量的字段在一个形式。我只测试了文本字段。

但是with()使事情变得更简单。代码如下:

function validate_required(field)
{
with (field)
  {
  if (value==null||value=="")
    {
    alert('All fields are mandtory');return false;
    }
  else
    {
    return true;
    }
  }
}

function validate_form(thisform)
{
with (thisform)
  {
    for(fiie in elements){
        if (validate_required(elements[fiie])==false){
            elements[fiie].focus();
            elements[fiie].style.border='1px solid red';
            return false;
        } else {elements[fiie].style.border='1px solid #7F9DB9';}
    }

  }
  return false;
}

其他回答

下面是with的一个很好的用法:根据存储在Object中的值向Object Literal添加新元素。这是我今天用的一个例子:

我有一组可能使用的瓷砖(面向顶部、底部、左侧或右侧),我想快速添加一个瓷砖列表,在游戏开始时始终放置并锁定这些瓷砖。我不想一直输入类型。tbr用于列表中的每种类型,所以我只使用with。

Tile.types = (function(t,l,b,r) {
  function j(a) { return a.join(' '); }
  // all possible types
  var types = { 
    br:  j(  [b,r]),
    lbr: j([l,b,r]),
    lb:  j([l,b]  ),  
    tbr: j([t,b,r]),
    tbl: j([t,b,l]),
    tlr: j([t,l,r]),
    tr:  j([t,r]  ),  
    tl:  j([t,l]  ),  
    locked: []
  };  
  // store starting (base/locked) tiles in types.locked
  with( types ) { locked = [ 
    br,  lbr, lbr, lb, 
    tbr, tbr, lbr, tbl,
    tbr, tlr, tbl, tbl,
    tr,  tlr, tlr, tl
  ] } 
  return types;
})("top","left","bottom","right");

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仍然是一个强大的想法,可以提高可读性。

我认为最明显的用途是作为捷径。例如,如果你初始化一个对象,你只需节省大量输入“ObjectName”。有点像lisp的“带槽”,让你可以写

(with-slots (foo bar) objectname
   "some code that accesses foo and bar"

这和写作是一样的吗

"some code that accesses (slot-value objectname 'foo) and (slot-value objectname 'bar)""

当你的语言允许“Objectname”时,这是一个更明显的快捷方式。但是还是。

只是想添加你可以得到“with()”功能与漂亮的语法和没有歧义与你自己的聪明的方法…

     //utility function
  function _with(context){
           var ctx=context;
           this.set=function(obj){
             for(x in obj){
                //should add hasOwnProperty(x) here
                ctx[x]=obj[x];
             }
       } 

       return this.set;          
 }

 //how calling it would look in code...

  _with(Hemisphere.Continent.Nation.Language.Dialect.Alphabet)({

      a:"letter a",
      b:"letter b",
      c:"letter c",
      d:"letter a",
      e:"letter b",
      f:"letter c",
     // continue through whole alphabet...

  });//look how readable I am!!!!

..或者,如果你真的想使用"with()"而不带歧义和自定义方法,可以将它包装在匿名函数中并使用.call

//imagine a deeply nested object 
//Hemisphere.Continent.Nation.Language.Dialect.Alphabet
(function(){
     with(Hemisphere.Continent.Nation.Language.Dialect.Alphabet){ 
         this.a="letter a";
         this.b="letter b";
         this.c="letter c";
         this.d="letter a";
         this.e="letter b";
         this.f="letter c";
         // continue through whole alphabet...
     }
}).call(Hemisphere.Continent.Nation.Language.Dialect.Alphabet)

然而,正如其他人所指出的,这有点毫无意义,因为你可以做……

 //imagine a deeply nested object Hemisphere.Continent.Nation.Language.Dialect.Alphabet
     var ltr=Hemisphere.Continent.Nation.Language.Dialect.Alphabet 
     ltr.a="letter a";
     ltr.b="letter b";
     ltr.c="letter c";
     ltr.d="letter a";
     ltr.e="letter b";
     ltr.f="letter c";
     // continue through whole alphabet...

有使用Delphi的经验,我会说使用with应该是最后的大小优化方法,可能由某种javascript最小化算法执行,并访问静态代码分析以验证其安全性。

随意使用with语句可能会遇到范围问题,这是一个非常痛苦的问题,我不希望任何人经历调试会话来弄清楚他…,却发现它捕获了一个对象成员或错误的局部变量,而不是您期望的全局变量或外部作用域变量。

VB的with语句更好,因为它需要点来消除范围的歧义,但Delphi的with语句是一把上膛的枪,带有一发之机,在我看来,javascript的with语句与之相似,足以保证同样的警告。