JavaScript 的作用域一直是前端開發(fā)和前端面試中難以理解的知識點,一不留神就入坑了,小編寫這篇文章,就是來填坑的,好了,直接開始。
1. JavaScript 無塊級作用域
什么是塊級作用域?其實就是占地盤,畫個圈圈說這塊地盤是我的,只有我能在這個區(qū)域里作,例如,這個 “{ }” 大括號。
那無塊級作用域又是什么意思呢?就是即便你畫了個圈,但憑啥你說這是你地盤就是你地盤,我在圈外面就想插一腳玩玩。
例子1:
JavaScript 無塊級作用域
function Fun() {
if(true) {
var name = 'yes';
}
console.log(name);
};
Fun();
// yes
這里 if(true) 后面的 {...} 是一個塊級作用域,根據(jù)輸出結(jié)果,可以知道 console.log(name) 是可以訪問 var name = 'yes' 的,等同于別人在你家門外就能拿你家里的東西。
不過在 ES6 中,引入了 let 關(guān)鍵字,用于指定變量屬于塊級作用域。也就是說JavaScript 也有塊級作用域了。
例子2:
JavaScript 有塊級作用域
function Fun() {
if(true) {
let name = 'yes';
}
console.log(name);
};
Fun();
// undefined
引用 let 替換 var 后,生成了塊級作用域,console.log(name) 訪問不到大括號里面的內(nèi)容了。
2. JavaScript 函數(shù)作用域
JavaScript 中每個函數(shù)作為一個作用域,外部是無法訪問作用域內(nèi)部的變量的。
例子3:
function Fun() {
var x = 1;
var y = 2;
console.log(x);
}
Fun();
console.log(y);
// 1 ReferenceError: y is not defined......
“函數(shù)作用域”還是比較厲害的,自己家的東西管的很嚴格,別人看都不讓看。
3. JavaScript 作用域鏈
JavaScript中的每個函數(shù)作為一個作用域,如果出現(xiàn)函數(shù)之間互相嵌套,就會出現(xiàn)作用域鏈。
例子4:
x = 1;
function Fun() {
var x = 2;
function main() {
var x = 3;
console.log(x);
}
main();
}
Fun();
// 3
兩個函數(shù)互相嵌套,形成三個作用域組成的作用域鏈(不要忘記全局作用域),這種情況下,尋找變量就要按照順序。
執(zhí)行console.log(x)時,按照作用域有內(nèi)而外的優(yōu)先級尋找,很明顯,應該先在
function main() {
var x = 3;
console.log(x);
}
找到了 var x = 3,最后結(jié)果就是3。修改例子3,如下:
x = 1;
function Fun() {
var x = 2;
function main() {
console.log(x);
}
main();
}
Fun();
// 2
依次類推,如果最后找不到則報錯。
這里,順便講一下JavaScript 變量提升。
4. JavaScript 變量提升
有時候也稱之為聲明提前,變量聲明提升等等,其實都是一個意思。
什么是變量提升,即變量可以在聲明之前使用,說的簡單點,就是聲明的這個變量它比較喜歡往前湊熱鬧。
JavaScript 中不創(chuàng)建變量,直接使用,結(jié)果是報錯的
console.log(x);
// ReferenceError: x is not defined...
創(chuàng)建變量但是不賦值,結(jié)果是 undefined
var x;
console.log(x);
// undefined
創(chuàng)建變量并賦值,結(jié)果輸出正常
var x = 3;
console.log(x);
// 3
注意:這里 var x = 3 在實際執(zhí)行過程中是這樣的,明白這點很重要。
var x;
x = 3;
我們看下面這個例子
例子5:
function Fun() {
console.log(x);
var x = '5';
}
Fun();
// undefined
為什么輸出的是 undefined,而不是直接報錯或者輸出“5”呢?請看原因:這個時候,變量提升和剛才的“明白這點很重要”該出馬了。在 JavaScript 被執(zhí)行之前,有一個“預編譯”的過程,這期間代碼變成這樣了
function Fun() {
var x; // 看到了沒,我跑前面來了哦
console.log(x);
x = '5'; // 賦值語句位置不變,聲明語句提前
}
Fun();
喜歡的童鞋,可以關(guān)注一下我('?' )?