读书频道 > web开发 > Javascript > Effective JavaScript:编写高质量JavaScript代码的68个有效方法
第10条:避免使用with
2013-12-07 14:41:24     我来说两句 
收藏    我要投稿   
本书共分为7章,分别涵盖JavaScript的不同主题。第1章主要讲述最基本的主题,如版本、类型转换要点、运算符注意事项和分号局限等。第2章主要讲解变量作用域,介绍此方面的一些基本概念,以及一些最佳实践经验。第  立即去当当网订购

悲催的with特性。在JavaScript中可能没有比它更令人诟病的特性了。然而,with语句是罪有应得。它提供的任何“便利”,都更让其变得不可靠和低效率。

with语句的动机是可以理解的。程序经常需要对单个对象依次调用一系列方法。使用with语句可以很方便地避免对对象的重复引用:

 


 
在这两种情况下,使用with语句使得提取对象的属性,并将这些属性绑定到块的局部变量中变得非常诱人且容易。

这些例子看起来很有吸引力,但它实际没做它应该做的事。请注意这两个例子有两种不同类型的变量。一种是我们希望引用with对象的属性的变量,如setBackground、round以及sqrt。另一种是我们希望引用外部变量绑定的变量,如info、x和y。但其实在语法上并没有区分这两种类型的变量。它们都只是看起来像变量。

事实上,JavaScript对待所有的变量都是相同的。JavaScript从最内层的作用域开始向外查找变量。with语句对待一个对象犹如该对象代表一个变量作用域,因此,在with代码块的内部,变量查找从搜索给定的变量名的属性开始。如果在这个对象中没有找到该属性,则继续在外部作用域中搜索。

图2.1显示了当执行with语句的代码时,status函数的作用域在JavaScript引擎中的内部表示图。在ES5规范中这称为词法环境(在旧版本标准中称为作用域链)。该词法环境的最内层作用域由widget对象提供。接下来的作用域用来绑定该函数的局部变量info和widget。接下来一层绑定到status函数。注意在一个正常的作用域中,会有与局部作用域中的变量同样多的作用域绑定存储在与之对应的环境层级中。但是对于with作用域,绑定集合依赖于碰巧在给定时间点时的对象。

我们有多大的信心确信在提供给with的对象中可以找到哪些属性,或者找不到哪些属性?with块中的每个外部变量的引用都隐式地假设在with对象(以及它的任何原型对象)中没有同名的属性。而在程序的其他地方创建或修改with对象或其原型对象不一定会遵循这样的假设。JavaScript引擎当然不会读取局部代码来获取你使用了哪些局部变量。

变量作用域和对象命名空间之间的冲突使得with代码块异常脆弱。例如,如果上述例子的with对象获得了一个名为info的属性,status函数的行为将被立即改变。status函数将使用这个属性而不是status函数的info参数。这种情况可能发生在源代码的演化中。例如,程序员决定所有的widget对象都应该有一个info属性。更糟糕的是,有时会给Widget的原型对象在运行时加入info属性,这将导致status函数变得不可预测。


 

可能不会有人给Math添加x和y属性。但总是很难预测一个特定的对象是否已被修改,或是否可能拥有你不知道的属性。而事实证明,人力不可预测的特性对于优化编译器同样不可预测。通常情况下,JavaScript作用域可被表示为高效的内部数据结构,变量查找会非常快速。但是由于with代码块需要搜索对象的原型链来查找with代码块里的所有变量,因此,其运行速度远远低于一般的代码块。

在JavaScript中没有单个特性能作为一个更好的选择直接替代with语句。在某些情况下,最好的替代方法是简单地将对象绑定到一个简短的变量名上。

 


 

 提示

避免使用with语句。

使用简短的变量名代替重复访问的对象。

显式地绑定局部变量到对象属性上,而不要使用with语句隐式地绑定它们。

点击复制链接 与好友分享!回本站首页
分享到: 更多
您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇:第9条:始终声明局部变量
下一篇:第11条:熟练掌握闭包
相关文章
图文推荐
3.12 本章小结
3.10 添加新函数
3.9 递归
3.8 闭包
排行
热门
文章
下载
读书

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训
版权所有: 红黑联盟--致力于做最好的IT技术学习网站