原文連接: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