[[Scopes]]是函式的內部屬性,是無法訪問的,但是我們可以通過Chrome的開發者工具看到它的樣子。
可以清楚的看到它是一個
- 我們現在宣告個函式
foo
- 需要檢視
foo
的原型物件才能看到[[scopes]]
屬性,因為foo.prototype.constructor
和foo
指向同一個函式,所以點開constructor
選項。- 現在我們終於看到了
[[Scopes]]
屬性。
陣列
,只有一個元素Global
也就是全域性物件,經過我目測這個Global
應該和window
物件是同一個物件。
// 定義一個全域性的變數
var a = 'global property'
function foo () {
console.log(a)
}
foo() // 此時會輸出global property
複製程式碼
如上程式碼所示,此時我們再看foo
的[[Scopes]]
屬性
Global
物件裡增加了一個a
屬性,這和window
物件表現一致。事實上在函式foo
裡面執行console.log(a)
的時候,變數a
就是從這個Global
物件內讀取的。
function outer () {
var a = 'property of outer scope'
return function inner () {
console.log(a)
}
}
var inner = outer()
inner() // 如大家所料,會輸出property of outer scope
複製程式碼
此時我們再看一下inner
的[[Scopes]]
屬性
[[Scopes]]
陣列的前面新新增了一個叫Closure
的物件,從字面上看這不就是閉包
的意思嗎,我們展開看一下
果然有我們閉包
裡的屬性a
,其實inner
函式裡的console.log(a)
中的a
就是從設個Closure
物件裡面讀取的。我們再來看一個例子
function outer () {
var a = 1
function inner () {
var b = 2
return function innermost () {
console.log(a, b)
}
}
return inner()
}
var innermost = outer()
innermost() // 此時輸出的值是1 2
複製程式碼
看一下innermost
的[[Scopes]]
屬性,如下圖
Scopes
陣列的開頭又增加了一個閉包,是按照從內到外的順序排列的,讓我們點開看一下
果然,這裡的兩個閉包
物件分別包含了innermost
需要訪問的所有變數。這就是作用域鏈的概念,當一個函式被呼叫的時候,函式內部訪問的物件會先從函式自己的作用域內部進行查詢,如果沒找到對應的變數,就會從[[Scopes]]
陣列的第一項閉包
物件進行查詢,如果還沒找到就繼續到下一個閉包
物件查詢,以此類推。