深入JavaScript with语句
栏目: JavaScript · 发布时间: 6年前
内容简介:深入JavaScript with语句
一般而言,所有写JS的人都有一个通常的概念:“不要用with语句”。这个准则毫无疑问一直是正确的,但要说为什么的话,并不是每个人可以回答的很好。是否去回答这个为什么并无多大意义,因为只须记住结果“不去用”就完全足够。然而去深入的理由还是有的,刚好最近有人这么问起我...刚好自己想总结一下...刚好这个题目作为草稿在博客后台躺了很久...但说到底,套用最新一话琦玉老师句式,“还是因为我很闲吧”...
with语句
with的初衷是为了避免冗余的对象调用:
foo.bar.baz.x = 1; foo.bar.baz.y = 2; foo.bar.baz.z = 3; with(foo.bar.baz){ x = 1; y = 2; z = 3; }
但其实用变量替换的写法也挺简单:
var p = foo.bar.baz; p.x = 1; p.y = 2; p.z = 3;
所以with似乎本来就没有存在的必要。到了如今,会去用with的人才真的是 罕见 。到了strict模式里,使用with会直接报错:
function foo(){'use strict'; with({});} // Uncaught SyntaxError: Strict mode code may not include a with statement
所以with已经被彻底抛弃,人们甚至都懒的关注理由~
书中的with语句
既然是总结,我想尽可能完整一些,所以就先从书籍开头吧。有关JavaScript的书我书柜里确实不少,比 Java 要多出60%!好吧,这是个冷笑话。回到正题,关于基础内容的JavaScript的书,我书柜里主要有4本,下面依次拿出来说说:
《JavaScript权威指南》(第五版, David Flanagan, P109):
with (Object) statement
with语句用于暂时修改作用域链...这一个语句能够有效地将Object添加到作用域链的头部,然后执行statement,再把作用域链恢复到原始状态...虽然有时使用with语句比较方便,但是人们反对使用它。使用了with语句的JavaScript代码很难优化,因此它的运行速度比不使用with语句的等价代码要慢得多。而且,在with语句中的函数定义和变量初始化可能会产生令人惊讶的、和直觉相抵触的行为(这一行为以及产生的原因非常复杂,在这里我们不做解释)
以现在的眼光看《权威指南》会感觉它说的很啰嗦,一大段内容到最后还来一句相当拗口的话(当然我能理解作为译本这无法避免),到了最后还“我们不做解释”,真是尴尬...
《JavaScript高级程序设计》(第3版, Nicholas C.Zakas, P60):
with语句的作用是将代码的作用域设置到一个特定的对象中...由于大量使用with语句会导致性能下降,同时也会给调试代码造成困难,因此在开发大型应用程序时,不建议使用with语句。
Zakas的《高级程序设计》是我JavaScript的入坑书,在with语句这个问题上也没有多深入什么,但写的还算简练,并且说法相当委婉。
《JavaScript语言精粹》(修订版, Douglas Crockford, P110),将with语句列为“糟粕”,并用例子讲述了它的不可预料性,结论上:
with语句在这个语言里存在,本身就严重影响了JavaScript处理器的速度,因为它阻断了变量名的词法作用域绑定。它的本意是好的,但如果没有它,JavaScript语言会更好一点。
老道虽也提到了速度,但更着重解释了不可预测性。
《深入理解JavaScript》(Axel Rauschmayer, P153),我手里唯一一本用了超过1页的篇幅来详细解释废弃with的原因的基础参考书。当时买这本书还是为了支持译者非常长,他曾经给我的博客Host提供过帮助,当然其实也想略微吐槽一下此书的翻译错漏:)
此书中的解释是比较全面的,所以我会以此书的解释作为基础,再加上自己的理解,总结在本文。
好了,看了那么多书,下面就进入本文的正题:
为什么不要使用with语句?
总而言之,主要是这几方面的考量:
- 性能
- 不可预测
- 优化
性能问题
with语句存在显而易见的性能问题,基本上所有的参考书都会提及这一点,但基本不会有什么例子说明。自己可以简单的做一个代码测试,使得对with语句的性能有更直观量化的了解。
var a = {a: {a: 1}}; function useWith(){ with(a.a){ for(var i = 0; i < 1000000; i++){ a = i; } } } var b = {b: {b: 1}}; function noWith(){ for(var i = 0; i < 1000000; i++){ b.b.b = i; } } var t1 = new Date().getTime(); useWith() alert(new Date().getTime() - t1); var t2 = new Date().getTime(); noWith() alert(new Date().getTime() - t2);
简单对一个对象属性赋值100万次,是否使with的结果差距还是很明显:
Chrome | Firefox | Edge | IE11 | |
---|---|---|---|---|
Use with | 603 | 1411 | 245 | 103 |
No with | 2 | 1 | 3 | 3 |
当然实际使用上极少会用到百万次循环,且损耗在可接受范围内,所以其实性能损失并不是废弃with语句的真正原因。
不可预测性
使用with语句后代码产生的不可预测性是废弃with的根本原因。with强行割裂了词法作用域,将对象临时性地插入到了作用域链中。这使得出现了难以捉摸的代码。
比如最简单的例子:
function foo(a){ with(a){ console.log(a); } } foo("sword"); // "sword" foo({}); // Object {} foo({a: "sword"}); // "sword"
在这个简单的例子里,字符串"sword"和空对象没有问题,但当传入的参数是带有同名a属性的a对象时,with强行访问了 a.a
这仅仅只是有一个参数的情况下,如果有很多个参数呢?当不知道调用传进来的参数带有何种属性时,多个参数间的各种属性的混乱指向可想而知,这就是“令人惊讶的、和直觉相抵触的行为”的本质。
另外,在with语句中声明的变量,并不属于with指定的参数对象:
var a ={}; with(a){ x = 'sword' var y = 'wang'; } console.log(a.x); // undefined console.log(a.y); // undefined console.log(window.x); // "sword" console.log(window.y); // "wang"
在with中声明的变量实际上是被添加到外层的function上的:
function foo(){ with({}) { x = 'sword'; } console.log(x) } foo(); // "sword"
这点可能也与想象中有些不同。
仅仅通过标识符及其上下文,无法确定一个with中的标识符指向什么,这是with被废弃的真正原因。它强行混乱了上下文使得程序的预测和解析变得困难,从而产生了之后要说的优化问题。
代码无法优化
由于无法进行预测,代码含义一直在发生变化,不同的调用,或者即使相同的调用也会因为运行时的变化而出现偏差,从而使得代码无法被优化。
优化指两方面,一方面解析和运行变得缓慢,指的就是之前已经谈到的性能。另一方面对于代码优化和压缩 工具 来说,无法确定是变量还是属性,就不能进行重命名(因为属性无法被重命名)。
结语
游览了几本书,讲了一堆没啥用的内容,我果然很闲...另外,上面那个冷笑话:“JavaScript比Java要多出60%!”指的是字符数量上...好吧,天热了,自己冷自己~
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- MySQL 建表语句转 PostgreSQL 建表语句全纪录
- Go语言开发-过程式编程-通信和并发语句-Select语句
- SQL语句优化之JOIN和LEFT JOIN 和 RIGHT JOIN语句的优化
- Python 条件语句
- Python 循环语句
- Python break 语句
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
计算机网络(第5版)
Andrew S. Tanenbaum、David J. Wetherall / 严伟、潘爱民 / 清华大学出版社 / 2012-3-1 / 89.50元
本书是国内外使用最广泛、最权威的计算机网络经典教材。全书按照网络协议模型自下而上(物理层、数据链路层、介质访问控制层、网络层、传输层和应用层)有系统地介绍了计算机网络的基本原理,并结合Internet给出了大量的协议实例。在讲述网络各层次内容的同时,还与时俱进地引入了最新的网络技术,包括无线网络、3G蜂窝网络、RFID与传感器网络、内容分发与P2P网络、流媒体传输与IP语音,以及延迟容忍网络等。另......一起来看看 《计算机网络(第5版)》 这本书的介绍吧!