首页 » 编写高质量代码:改善JavaScript程序的188个建议 » 编写高质量代码:改善JavaScript程序的188个建议全文在线阅读

《编写高质量代码:改善JavaScript程序的188个建议》建议12:避免使用with

关灯直达底部

with语句的语法如下:


with(Expression)

Statement


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

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


function A{

this.a="A";

}

function B{

this.b="B";

}

B.prototype=new A;

function C{

this.c="C";

}

C.prototype=new B;

(function{

var myVar="Hello World";

alert(typeof a);//"undefined"

var a=1;

var obj=new C;

with(obj){

alert(typeof a);//"string"

alert(myVar);//查找速度比较慢

}

alert(typeof a);//"number"

});


在上面代码中,先通过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语句可以快捷地访问对象的属性,然而,得到的结果有时可能是不可预料的,所以应该避免使用它。例如:


with(obj){

a=b;

}


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


if(obj.a===undefined){

a=obj.b===undefined?b:obj.b;

}else{

obj.a=obj.b===undefined?b:obj.b;

}


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


a=b;

a=obj.b;

obj.a=b;

obj.a=obj.b;


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

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