原文连接:https://www.cnblogs.com/zz334...javascript
《Javascript高级程序设计(第二版)》第66页中提到:“因为with语句的变量对象是只读的,结果url就成了函数执行环境的一部分,于是能够做为函数的值被返回。”,不知道谁看完以为一头雾水?html
第三版中75页则更是难懂:“至于with语句内部,则定义了一个url的变量,所以url就成了函数执行环境的一部分,因此能够做为函数的值被返回”java
首先来看看他举的例子:函数
function buildUrl(){ var qs="?debug=true"; with(location){ var url=href+qs; } return url; } var result=buildUrl(); alert(result);
若是你没读过着本书,而且须要学习javascript,请思考并尝试运行该例子。
最后弹出的不是undefined,而是你的静态页地址+qs的值。学习
来看一下with语句的做用:ui
通俗的说,就是引用对象,并对该对象上的属性进行操做,其做用是能够省略重复书写该对象名称,起到简化书写的做用。url
可是有几个问题须要注意:debug
一、with代码块中,javascript引擎对变量的处理方式是:先查找是否是该对象的属性,若是是,则中止。若是不是继续查找是否是局部变量。(在《Javascript高级程序设计(第二版)》中提到的观点,跟这一点刚好相反,可是实例可证实其是错误的,会在接下来介绍)设计
二、就算在with语句中使用 var 运算符从新定义变量(该变量是with引用对象的属性),若是该属性是可写属性,那么也会给对象的属性赋值。code
三、若是你想经过with语句,对引用对象添加多个属性,并为每一个属性赋值,这是不可能的!也就是说,要赋值的只能是对象已经存在而且能够写入的属性(不能是只读属性)。
再来看看开头提到的那句话
“因为with语句的变量对象是只读的,结果url就成了函数执行环境的一部分,于是能够做为函数的值被返回。”
反过来:若是with语句的变量对象是可写入的…… 刚才第3点提过,不能给对象写入原来不存在的属性,先这样理解,下面还有另外的含义。
那延长做用域链又是怎么回事?
通常的,“因为with语句块中做用域的‘变量对象’是只读的,因此在他本层定义的标识符,不能存储到本层,而是存储到它的上一层做用域”。这里又要理解有一层“只读”的含义。
在Javascript的做用域中(做用域,想一想就是函数块,每一个函数都会有个函数名,就算是匿名函数也有个空函数名),那么建立做用域的时候,本层的标识符就能够寄托在这个做用域下,而with语句块中做用域的‘变量对象’是只读的,不能存储标识符,只能存储在其上一层,这就是延长做用域链。其实,这和上面说的不能给对象添加属性有同工之处。
其实,彻底能够这样理解,在Javascript中,没有块级做用域,就是说除了函数,其余的块级代码都没有本身的做用域。
如今说一下以前提到的with代码块中变量处理方式的问题
用事实说话:
var o={href:"sssss"}; var href="1111"; function buildUrl(){ var qs="?debug=true"; with(o){ href="2222"; var url=href+qs; } return url; } var result=buildUrl(); alert(result); //2222?debug=true alert(href); //1111
很明显,with语句中并无更改变量href的值,而是更改了 o 对象的 href 属性。
就是说,with中首先查找的是相关对象的属性,若是没有,才改变变量的值。
将以上例子o对象的href属性去掉
var o={}; var href="1111"; function buildUrl(){ var qs="?debug=true"; with(o){ href="2222"; var url=href+qs; } return url; } var result=buildUrl(); alert(result); //2222?debug=true alert(href); //2222