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

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


当前回答

只是想添加你可以得到“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...

其他回答

with语句可用于减少代码大小或用于私有类成员,例如:

// demo class framework
var Class= function(name, o) {
   var c=function(){};
   if( o.hasOwnProperty("constructor") ) {
       c= o.constructor;
   }
   delete o["constructor"];
   delete o["prototype"];
   c.prototype= {};
   for( var k in o ) c.prototype[k]= o[k];
   c.scope= Class.scope;
   c.scope.Class= c;
   c.Name= name;
   return c;
}
Class.newScope= function() {
    Class.scope= {};
    Class.scope.Scope= Class.scope;
    return Class.scope;
}

// create a new class
with( Class.newScope() ) {
   window.Foo= Class("Foo",{
      test: function() {
          alert( Class.Name );
      }
   });
}
(new Foo()).test();

如果你想要修改作用域,with语句是非常有用的,这对于拥有自己的全局作用域是必要的,可以在运行时操作。你可以在它上面放置常量或者某些常用的辅助函数,比如:“toUpper”,“toLower”或“isNumber”,“clipNumber”麻生..

关于糟糕的性能,我经常读到:作用域函数不会对性能产生任何影响,事实上,在我的FF中,有作用域的函数比无作用域的函数运行得更快:

var o={x: 5},r, fnRAW= function(a,b){ return a*b; }, fnScoped, s, e, i;
with( o ) {
    fnScoped= function(a,b){ return a*b; };
}

s= Date.now();
r= 0;
for( i=0; i < 1000000; i++ ) {
    r+= fnRAW(i,i);
}
e= Date.now();
console.log( (e-s)+"ms" );

s= Date.now();
r= 0;
for( i=0; i < 1000000; i++ ) {
    r+= fnScoped(i,i);
}
e= Date.now();
console.log( (e-s)+"ms" );

所以在上面提到的方式中使用with语句对性能没有负面影响,但它减少了代码大小,这影响了移动设备上的内存使用。

使用with还会使代码在许多实现中变慢,因为现在所有内容都被包装在一个额外的查找范围中。在JavaScript中使用with没有合理的理由。

只是想添加你可以得到“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...

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

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

我一直使用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')
    )
  )
}

对于这个用例,我没有做任何赋值,所以我没有与之相关的歧义问题。