0 Comments

避免使用with

发布于:2012-12-03  |   作者:广州网站建设  |   已聚集:人围观

       with语句的语法如下:


  1. with ( Expression )  
  2.     Statement 

      with会把由Expression计算出来的对象添加到当前执行上下文的作用域链的前面,然后使用这个扩大的作用域链来执行语句Statement,最后恢复作用域链。不管其中的语句是否正常退出,作用域链都会被恢复。

      由于with会把额外的对象添加到作用域链的前面,因此使用with可能会影响性能,并造成难以发现的错误。由于额外的对象在作用域链的前面,当执行到with语句,需要对标识符求值时,会先沿着该对象的prototype链查找。如果找不到,才会依次查找作用域链中原来的对象。因此,如果在with语句中频繁引用不在额外对象的 prototype 链中的变量,查找的速度会比不使用with 慢,例如:


  1. function A() {  
  2.     this.a = "A";  
  3. }  
  4. function B() {  
  5.     this.b = "B";  
  6. }  
  7. B.prototype = new A();  
  8. function C() {  
  9.     this.c = "C";  
  10. }  
  11. C.prototype = new B();  
  12. (function() {  
  13.     var myVar = "Hello World";  
  14.     alert(typeof a);    // "undefined"  
  15.     var a = 1;  
  16.     var obj = new C();  
  17.     with(obj) {  
  18.         alert(typeof a);    //"string"  
  19.         alert(myVar);   //查找速度比较慢  
  20.     }  
  21.     alert(typeof a);    // "number"  
  22. })(); 

         在上面代码中,先通过prototype方式实现了继承。在with语句中,执行alert(typeof a)时需要查找变量a,由于obj在作用域链的前面,而obj中也存在名为a的属性,因此obj中的a被找到。执行alert(myVar)需要查找变量myVal,而obj中不存在名为myVal的属性,会继续查找作用域链中后面的对象,因此使用with比不使用with的速度慢。需要注意的是,最后一条语句alert(typeof a)不在with中,因此查找到的a是之前声明的 number型的变量。

          使用with语句可以快捷地访问对象的属性,然而,得到的结果有时可能是不可预料的,所以应该避免使用它。例如:


  1. with (obj) {  
  2.     a = b;  

 

       上面代码与下面的代码完成的是同样的事情。

  1. if (obj.a === undefined) {  
  2.     a = obj.b === undefined ? b : obj.b;  
  3. } else {  
  4.     objobj.a = obj.b === undefined ? b : obj.b;  

 

      因此,前面代码等价以下语句中的任何一条。

  1. a = b;  
  2. a = obj.b;  
  3. obj.a = b;  
  4. objobj.a = obj.b; 

    直接阅读代码不可能辨别出会得到这些语句中的哪一条。a和b可能随着程序运行到下一步时发生变化,甚至可能在程序运行过程中就发生变化了。如果不能通过阅读程序来了解它将会做什么,就无法确信它是否会正确地执行我们要求的事情。

    with语句在JavaScript语言中存在,本身就严重影响了JavaScript处理器的速度,因为它阻止了变量名的词法作用域绑定。它的本意是好的,但如果没有它,JavaScript语言可能会更好。

标签:
飞机