深入理解javascript原型和閉包(14)——從【自由變數】到【範圍鏈】,深入理解javascript
先解釋一下什麼是“自由變數”。
在A範圍中使用的變數x,卻沒有在A範圍中聲明(即在其他範圍中聲明的),對於A範圍來說,x就是一個自由變數。如
如上程式中,在調用fn()函數時,函數體中第6行。取b的值就直接可以在fn範圍中取,因為b就是在這裡定義的。而取x的值時,就需要到另一個範圍中取。到哪個範圍中取呢?
有人說過要到父範圍中取,其實有時候這種解釋會產生歧義。例如:
所以,不要在用以上說法了。相比而言,用這句話描述會更加貼切——要到建立這個函數的那個範圍中取值——是“建立”,而不是“調用”,切記切記——其實這就是所謂的“靜態範圍”。
對於本文第一段代碼,在fn函數中,取自由變數x的值時,要到哪個範圍中取?——要到建立fn函數的那個範圍中取——無論fn函數將在哪裡調用。
上面描述的只是跨一步範圍去尋找。
如果跨了一步,還沒找到呢?——接著跨!——一直跨到全域範圍為止。要是在全域範圍中都沒有找到,那就是真的沒有了。
這個一步一步“跨”的路線,我們稱之為——範圍鏈。
我們拿文字總結一下取自由變數時的這個“範圍鏈”過程:(假設a是自由量)
第一步,現在當前範圍尋找a,如果有則擷取並結束。如果沒有則繼續;
第二步,如果當前範圍是全域範圍,則證明a未定義,結束;否則繼續;
第三步,(不是全域範圍,那就是函數範圍)將建立該函數的範圍作為當前範圍;
第四步,跳轉到第一步。
以上代碼中:第13行,fn()返回的是bar函數,賦值給x。執行x(),即執行bar函數代碼。取b的值時,直接在fn範圍取出。取a的值時,試圖在fn範圍取,但是取不到,只能轉向建立fn的那個範圍中去尋找,結果找到了。
這一節看似很輕鬆的把範圍鏈引出來,並講完了。之所有輕鬆是有前幾節的基礎,否則將很難解釋。
接下來咱們開始正式說說一直期待依舊的朋友——閉包。敬請期待下一節。
---------------------------------------------------------------------------
本文已更新到《深入理解javascript原型和閉包系列》的目錄,更多內容可參見《深入理解javascript原型和閉包系列》。
另外,歡迎關注我的微博。
也歡迎關注我的其他教程——別怕,都是免費的!
《微軟petshop4.0源碼解讀視頻》《json2.js源碼解讀視頻》
--------------------------------------------------------------------------
javascript範圍鏈與原型鏈有聯絡?從原理上分析,不要說我網上找得到的
個人感覺,沒什麼聯絡。
一般來說,範圍鏈是針對變數的,js裡面大的範圍上來說,只有兩種範圍,全域範圍和函數內部範圍,如果函數1裡面又定義了函數2(一般都是匿名函數), 那麼就有了這麼一個範圍鏈全域範圍==>函數1範圍==>函數2範圍;特點是函數1裡面可以直接使用全域範圍的變數,函數2裡面可以直接使用全域範圍和函數1範圍的變數
原型鏈的話,一般是定義建構函式時用到,可以認為是針對建構函式的或者說針對建構函式對應的類的;原型鏈的頭部就是Object類/建構函式,如果有建構函式1.prototype = 建構函式2;那麼也就有這麼一個原型鏈; Object ==> 建構函式1 ==> 建構函式2,這樣的好處是建構函式2對應的類,可以擁有建構函式1 和Object中的屬性,js沒有對應繼承的關鍵字,所以用原型鏈來類比繼承的效果。
純手打,希望對你有協助
我要深入的學習javascript運行機制的東西,比如閉包,原型鏈,範圍等,有什書推薦?
上面兩個權威指南和進階程式設計都可以看。
我推薦你周愛民寫的javascript語言精髓