1 定義:
作用域日常有很多叫法比如
- this綁定的值
- this綁定值定義的執行上下文
- 一個變量的“生命週期”、
- 變量的值解析方案或詞法綁定
作用域通俗的講就是一個變量多長時間內保持一定的值。
2 分類:
作用域從範圍上劃分可以分成全局作用域或局部作用域(常見的是函數內部,也叫函數作用域)。
作用域按照工作模式分爲詞法作用域(靜態作用域)或動態作用域。
2.1 全局作用域
1.在全局聲明的變量生命週期將跨越整個程序(盡力少些,並且不好維護)。
2.在JS中沒有用var 關鍵字聲明的變量都是全局變量,能被程序中任何函數或方法訪問。
aVariable = '我是全局變量'
function aTest() {
console.log(aVariable)
}
aTest() // 我是全局變量
就是因爲任何一段代碼可以隨便改變它們,會引起之後一些的麻煩,相當的危險。
2.2 詞法作用域
先說說詞法,詞法的中文意思是特定文本內語詞的構成和使用的法則。
在大部分編譯器也有這類似步驟,對源代碼進行字符檢查,如果是有狀態的解析過程,就會賦予單詞語義。
詞法作用域是指一個變量的可見性,及其文本表述的模擬值。(大概先記着有個印象)
上個代碼:
aVar = 'One'
function aFun() {
let aVar = 'Two'
return [1, 2, 3].map(function (item) {
var aVar = 'three'
console.log([aVar, item].join(''))
})
}
aFun() //three1 three2 three3
分析
換句話說,詞法作用域是由你寫代碼時將變量或塊作用域寫在哪裏所決定的。
2.3 動態作用域
在編程中最容易被低估或過度濫用的概念就是動態作用域。
aVariable = '我是全局變量'
function aTest() {
var aVariable = "我是TEST作用域的變量"
function childFun() {
var childVar = "我是child的變量"
console.log(aVariable, childVar)
}
childFun()
}
aTest() // 我是TEST作用域的變量 我是child的變量
但是如果在當前作用域中沒有查到值,就會向上級作用域去查,直到查到第一個值,最如果一直沒有會一層層直到查到全局作用域,這麼一個查找過程形成的鏈條就叫做作用域鏈。
aVariable = '我是全局變量'
function aTest() {
var aVariable = "我是TEST作用域的變量"
childFun()
}
function childFun() {
var childVar = "我是child的變量"
console.log(aVariable, childVar)
}
aTest() // 我是全局變量 我是child的變量
動態作用域的核心是維護一個命名綁定棧的全局映射。
缺點:任何給定的綁定的值,在確定調用其函數之前,都是不可知的
(JS中this引用是動態作用域,尤其是事件處理函數中,如果點擊按鈕得到的this沒用,會破壞程序的正常運行,是危險的)
2.4 函數作用域
在任意代碼片段外部添加包裝函數,可以將內部的變量和函數定義“隱藏”起來,外部作用域無法訪問包裝函數內部的任何內容。
function testFun(n) {
for(var i=0;i<n;i++);
console.log(i)
}
testFun(100) // 100
搜索在JS中所有在函數體內的var聲明都會隱式地移到函數的頂部,JS重新排列變量聲明的動作成爲吊裝(hoisting)
上面的代碼實際重新排列就成這樣了
function testFun(n) {
var i;
for (i = 0; i < n; i++);
console.log(i)
}
testFun(100) // 100
舉個例子:
i = 100
function testFun(n) {
console.log(i)
var i = 111;
}
testFun()
console.log(i)
原因分析:
i = 100 // 定義全局的 i
function testFun(n) {
var i; // JS吊裝排列
console.log(i) // 此時還沒有定義說undefined
i = 111; // 定義當前作用域的 i
}
testFun()
console.log(i) // 打印全局變量i
【ES6的let填坑了,會直接報錯 Uncaught ReferenceError: Cannot access 'i' before initialization(初始化之前不能訪問')】
Hositing的概念真的理解了麼,再來個測試~~~ do it~
i = 100
function testFun(n) {
console.log(i)
i = 111;
}
testFun()
console.log(i)