這個第一篇中間的內容講得大體都是對的,但是還是搞得太復雜。倒是頭尾兩句話非常具有典型意義:
引用
什麼叫閉包?我花了很長時間來弄明白這個概念,但每次以為弄明白的時候,卻又會發現其實沒搞清楚。
引用
……這究竟是為什麼,我目前還不清楚。但據說ECMA262標准給出了具體的實現方法的……我沒體力看了,交給大家吧。
暫時沒有時間詳細解說這些內容,僅把在小麥文章後面的comments記錄此處。
closure還是比較容易理解的,無非是內部函數可以訪問外部的變量。之所以能比較容易的支持closure,也在於JS是使用垃圾回收的,因此不存在函數局部變量生存期的問題——被回收的只是局部變量符號,真正所引用的對象只要還有任何一個地方引用它——無論是直接引用還是像closure那樣間接引用,都不會被回收。當然,closure的間接引用也加劇了IE中內存洩露問題,此乃題外話,不贅述。
closure(閉包)、scope chain(作用域鏈)、lexical scope(詞法作用域),三者當然不是一個概念,但是確實是有緊密聯系的。具體來說,JS語言是以scope chain的方式來實現lex scope和closure的。所以就算搞不懂scope chain,也不妨礙你使用JS。
1. scope chain是一種實現手段,具體來說,它是一種name lookup的檢索機制。
2. lexical scope是一種作用域機制,它很好理解。因為lex scope取決於源代碼,所以通常編譯器可以進行靜態分析來確定每個標識符實際的引用。實際上lexical scope因此也稱為static scope。
3. 其實JS並非完全的lexical scope。因為有with和eval這兩個特例。所以說JS是lexical scope實際上是說它的scope機制非常接近於lexical scope。
4. 因此JS引擎通常不使用靜態分析,而且只使用靜態分析是無法實現with的語義的!JS使用類似dynamic scope的技術,區別在於通常dynamic scope的bindings堆棧是全局的,而JS為每個execution context都單獨設置一個bindings堆棧,也就是所謂的scope chain。
5. 結論:可以把JS的scope看做一個用scope chain機制實現的近似lexical scope。
Updates:
關於with/eval對於lexical scope的影響,可以看這位用scheme實現JS引擎的同志的說法:
引用
...But the real subtlety comes in with the
with (dynamically add a computed object value to the runtime environment as a new environment frame) and
eval constructs...
... So outside of a
with, you get normal, efficient lexical scope; inside a
with, you get stupid, slow, dynamic scope...