先解釋一下什么是“自由變量”。
在A作用域中使用的變量x,卻沒有在A作用域中聲明(即在其他作用域中聲明的),對于A作用域來說,x就是一個自由變量。如下圖
如上程序中,在調(diào)用fn()函數(shù)時,函數(shù)體中第6行。取b的值就直接可以在fn作用域中取,因為b就是在這里定義的。而取x的值時,就需要到另一個作用域中取。到哪個作用域中取呢?
有人說過要到父作用域中取,其實有時候這種解釋會產(chǎn)生歧義。例如:
所以,不要在用以上說法了。相比而言,用這句話描述會更加貼切——要到創(chuàng)建這個函數(shù)的那個作用域中取值——是“創(chuàng)建”,而不是“調(diào)用”,切記切記——其實這就是所謂的“靜態(tài)作用域”。
對于本文第一段代碼,在fn函數(shù)中,取自由變量x的值時,要到哪個作用域中???——要到創(chuàng)建fn函數(shù)的那個作用域中取——無論fn函數(shù)將在哪里調(diào)用。
上面描述的只是跨一步作用域去尋找。
如果跨了一步,還沒找到呢?——接著跨!——一直跨到全局作用域為止。要是在全局作用域中都沒有找到,那就是真的沒有了。
這個一步一步“跨”的路線,我們稱之為——作用域鏈。
我們拿文字總結(jié)一下取自由變量時的這個“作用域鏈”過程:(假設(shè)a是自由量)
第一步,現(xiàn)在當(dāng)前作用域查找a,如果有則獲取并結(jié)束。如果沒有則繼續(xù);
第二步,如果當(dāng)前作用域是全局作用域,則證明a未定義,結(jié)束;否則繼續(xù);
第三步,(不是全局作用域,那就是函數(shù)作用域)將創(chuàng)建該函數(shù)的作用域作為當(dāng)前作用域;
第四步,跳轉(zhuǎn)到第一步。
以上代碼中:第13行,fn()返回的是bar函數(shù),賦值給x。執(zhí)行x(),即執(zhí)行bar函數(shù)代碼。取b的值時,直接在fn作用域取出。取a的值時,試圖在fn作用域取,但是取不到,只能轉(zhuǎn)向創(chuàng)建fn的那個作用域中去查找,結(jié)果找到了。
這一節(jié)看似很輕松的把作用域鏈引出來,并講完了。之所有輕松是有前幾節(jié)的基礎(chǔ),否則將很難解釋。
接下來咱們開始正式說說一直期待依舊的朋友——閉包。敬請期待下一節(jié)。
---------------------------------------------------------------------------
本文已更新到《深入理解javascript原型和閉包系列》的目錄,更多內(nèi)容可參見《深入理解javascript原型和閉包系列》。
另外,歡迎關(guān)注我的微博。
也歡迎關(guān)注我的其他教程:
《用grunt搭建自動化的web前端開發(fā)環(huán)境》《從設(shè)計到模式》《json2.js源碼解讀視頻》《微軟petshop4.0源碼解讀視頻》
--------------------------------------------------------------------------
聯(lián)系客服