js經過沿着做用域鏈仍是原型鏈查找變量

 

這是一道很是典型的JS閉包問題,結果和具體的解析請看這裏html

對於其中的`函數做用域鏈的問題`博主彷佛沒有解釋清楚,有一些疑問:js中的變量究竟是沿着做用域鏈仍是原型鏈查找呢?segmentfault

首先,要分清做用域鏈與原型鏈的區別,簡單來講

做用域鏈是相對於函數的,原型鏈是相對於對象的

瀏覽器

js中訪問變量有多種方式
1. 直接經過標識符訪問
2. 經過 . 或 [] 訪問對象中的標識符閉包

猜測訪問方式不一樣,致使了查找的方式不一樣:
1. 直接經過標識符訪問,訪問的多是函數中的標識符,也多是全局對象(瀏覽器中是 window)的標識符,也就是說,可能沿着做用域鏈也可能沿着原型鏈訪問
2. 經過 . 或 [] 訪問對象中的標識符,js會沿着原型鏈查找函數

對於第二點,如下的小測試能夠證實
測試

 

① 至關於調用 window.test(),this 指向 window,訪問的是 window.a;this

② 中 this 指向 o,訪問的是 o.a;prototype

將全局的 a, 也就是 window.a 和 o.a 刪除以後,獲得的結果均是 1。htm

所以,經過 . 或 [] 訪問`對象`中的標識符,js會沿着原型鏈查找。對象

第一點,直接經過標識符訪問,也就是訪問當前執行上下文EC的做用域中的變量,這一過程稱爲標識符解析,依賴於做用域鏈。


做用域鏈Scope其實就是對執行上下文EC中的變量對象VO|AO有序訪問的鏈表

關於做用域鏈與執行上下文 EC 的關係,請看這裏

測試

 

把 this.a 改成 a,②的結果就變啦。

① 和 ② 的執行上下文EC(即 this 的指向)分別爲 window 和 o,但做用域鏈都是 test變量對象 + 全局變量對象。而test變量對象中沒有 a,全局變量對象含有 a 。這就說明,在函數中直接經過標識符變量,js會沿着做用域中查找。

有趣的是,當刪除了全局變量對象中的 a,再訪問 a,瀏覽器並無報錯,而是輸出 4;刪除 Window.prototype.a 以後,輸出的這是 1.
在 test 中添加一下代碼 :


 

由結果可知,訪問到的a 分別爲 Window.prototype 和 Object.prototype 中的變量。

爲何呢?由於在瀏覽器中,全局變量對象在瀏覽器中指向 window, window 也是對象,且位於做用域鏈的末尾;做用域鏈查找完,仍然找不到,js 就會沿着全局變量對象的原型鏈查找。

結論

1. 直接經過標識符訪問變量,首先沿着做用域鏈查找每個變量對象,直到全局變量對象(window)仍沒有,就沿着全局變量對象(window)的原型鏈查找2. 經過 . 或 [] 訪問對象中的標識符,就直接沿着原型鏈查找

相關文章
相關標籤/搜索