這裡主要記錄在日常中對知識的學習,通過結合筆記與自身理解的方式嘗試寫下總結
文章對細節可能不會一一介紹解釋,內容僅作參考
複製程式碼
作用域指程式原始碼中定義變數的區域,規定了如何查詢變數即確定當前執行程式碼對變數的訪問許可權
JavaScript採用的是詞法作用域,也就是函式的作用域在函式定義的時候就決定了
與詞法作用域相反的是動態作用域,也就是函式的作用域是在函式呼叫的時候才決定,這裡僅供瞭解就好
在JavaScript中主要有全域性作用域、函式作用域、塊級作用域(ES6之前沒有)三個
- 全域性作用域:顧名思義,是為最頂層最大的範圍
- 函式作用域:僅在某個函式內部有效的範圍
- 塊級作用域:僅在某個塊級程式碼內部有效的範圍
作用域是一個很抽象的概念,可以理解成一個地盤,具有
- 獨立性:作用域包裹起來讓變數不會外洩,所以在不同作用域下同名變數不會有衝突 - 隔離變數
- 分層與巢狀:作用域是有層級關係的,上下級關係的確定就看函式是在哪個作用域下定義的(在哪個作用域下定義就是哪個作用域的子作用域)
內層作用域(子作用域)可以訪問外層作用域(父作用域)的變數,反之則不行。在查詢一個變數時,如果在本作用域內無定義,那麼就會往上一層父作用域查詢,一層一層向上直到全域性作用域,這種方式就成為了作用域鏈
再強調一次:作用域是在相應程式碼定義時就被建立(例如定義函式時決定相對應的函式作用域)
舉個栗子加深一下理解:
function foo() {
var b = 2
function bar(c) {
var d = 3
console.log(a, b, c, d)
}
bar(b * 3)
}
function hkk() {
var e = 4
console.log(a, e)
}
var a = 1
複製程式碼
假設走到這段程式碼的時候,最外層作用域是全域性作用域,目前的作用域層級為
[全域性作用域]
複製程式碼
定義foo函式,會有一個foo作用域產生
[全域性作用域[foo作用域]]
複製程式碼
然後走進foo裡面,定義bar函式,會有一個bar作用域產生
[全域性作用域 [foo作用域 [ bar作用域 ] ] ]
複製程式碼
繞出來後,還定義了hkk函式,會有一個hkk作用域產生
[全域性作用域 [foo作用域 [ bar作用域 ], hkk作用域]]
複製程式碼
在接下來變數的查詢就會依賴這個作用域鏈 比如說在上面程式碼會有
- bar -> foo -> 全域性
- hkk -> 全域性
在函式執行時變數的查詢就會變成這樣:
function foo() {
var b = 2
function bar(c) {
var d = 3
console.log(a, b, c, d)
// a: 在bar這裡找不到,去foo那裡找找。foo也找不到呢,再上去全域性找找。在全域性找到了 -> 最後得出這個值要在全域性作用域下拿到
// b: 在bar這裡找不到,去foo那裡找找。在foo找到了 -> 最後得出這個值要在foo作用域下拿到
// c: 在bar這裡找到了 -> 最後得出這個值要在bar作用域下拿到
// d: 在bar這裡找到了 -> 最後得出這個值要在bar作用域下拿到
}
bar(b * 3)
}
function hkk() {
var e = 4
console.log(a, e)
// a: 在hkk這裡找不到,上去全域性找找。在全域性找到了 -> 最後得出這個值要在全域性作用域下拿到
// c: 在hkk這裡找到了 -> 最後得出這個值要在hkk作用域下拿到
}
var a = 1
複製程式碼
作用域是執行上下文知識的前置知識
可以想象成: 我要辦一座學校(全域性),會有多個年級(函式/塊級作用域),然後呢每個年級裡面又有多個班級(子函式/塊級作用域),每個班級又會有跟細的組織結構
但是呢 我這裡只是想好了怎麼安排制度(某個班級考試時,如果班級自己沒有試卷,那需要的試卷應該向對應的年級拿,年級沒有,再去找學校要),但至於執行起來後,年級有多少試卷,是否還有作業,就要看年級私底下的安排了(這個這裡先不去理解 看看就好)