作用域
作用域定義了變量和函數(shù)的可訪問(wèn)范圍,決定了代碼中變量和函數(shù)的可見(jiàn)性和生命周期。在 JavaScript 中,主要有兩種類型的作用域:全局作用域與局部作用域,局部作用域又分為函數(shù)作用域和塊級(jí)作用域(ES6出現(xiàn)之后)。
1. 全局作用域
全局作用域是最外層的作用域,在全局作用域中聲明的變量和函數(shù)可以在代碼的任何地方訪問(wèn)。如整個(gè)script標(biāo)簽或者是一個(gè)單獨(dú)的js文件:
// 全局作用域
var globalVariable = 'I am a global variable';
function globalFunction() {
console.log(globalVariable); // 可以在函數(shù)內(nèi)部訪問(wèn)全局變量
}
globalFunction(); // 輸出: I am a global variable
console.log(globalVariable); // 可以在全局作用域中直接訪問(wèn)全局變量
2. 局部作用域
局部作用域又分為函數(shù)作用域和塊級(jí)作用域
2.1 函數(shù)作用域
函數(shù)作用域是指在函數(shù)內(nèi)部聲明的變量和函數(shù)只能在該函數(shù)內(nèi)部訪問(wèn),外部無(wú)法直接訪問(wèn)。
function myFunction() {
var localVariable = 'I am a local variable';
console.log(localVariable); // 可以在函數(shù)內(nèi)部訪問(wèn)局部變量
}
myFunction(); // 輸出: I am a local variable
// console.log(localVariable); // 報(bào)錯(cuò),localVariable 未定義,因?yàn)樗诤瘮?shù)外部不可訪問(wèn)
2.2 塊級(jí)作用域
ES6 引入了 let 和 const 關(guān)鍵字,它們可以創(chuàng)建塊級(jí)作用域。塊級(jí)作用域是指在 {} 內(nèi)部聲明的變量和函數(shù)只能在該塊內(nèi)部訪問(wèn)。
if (true) {
let blockVariable = 'I am a block variable';
console.log(blockVariable); // 可以在塊內(nèi)部訪問(wèn)塊級(jí)變量
}
// console.log(blockVariable); // 報(bào)錯(cuò),blockVariable 未定義,因?yàn)樗趬K外部不可訪問(wèn)
執(zhí)行效率
全局變量存放在內(nèi)存中,只有瀏覽器關(guān)閉時(shí)才會(huì)銷毀,比較占內(nèi)存資源;
而局部變量,當(dāng)程序執(zhí)行完畢后就會(huì)被銷毀,比較節(jié)約內(nèi)部資源。所以我們更喜歡使用局部變量。
作用域鏈
作用域鏈的底層是變量查找機(jī)制。
當(dāng)訪問(wèn)一個(gè)變量時(shí),JavaScript引擎會(huì)首先在當(dāng)前作用域查找該變量,如果沒(méi)有找到,就會(huì)沿著作用域鏈向上查找,直到全局作用域。如果在全局作用域中也沒(méi)有找到,通常會(huì)拋出一個(gè)引用錯(cuò)誤(ReferenceError)。
// 全局作用域
var globalVar = 'Global variable';
function outerFunction() {
var outerVar = 'Outer variable';
function innerFunction() {
var innerVar = 'Inner variable';
// 訪問(wèn) innerVar,直接在當(dāng)前作用域中找到
console.log(innerVar);
// 訪問(wèn) outerVar,當(dāng)前作用域中找不到,沿著作用域鏈向上查找,在 outerFunction 的作用域中找到
console.log(outerVar);
// 訪問(wèn) globalVar,當(dāng)前作用域和 outerFunction 的作用域中都找不到,繼續(xù)沿著作用域鏈向上查找,在全局作用域中找到
console.log(globalVar);
}
innerFunction();
}
outerFunction();
在上述示例中,innerFunction 內(nèi)部形成了一個(gè)作用域鏈,它包含了 innerFunction 的作用域、outerFunction 的作用域和全局作用域。當(dāng) innerFunction 訪問(wèn)變量時(shí),會(huì)按照作用域鏈的順序依次查找。
作用域鏈的存在使得 JavaScript 能夠?qū)崿F(xiàn)變量的嵌套訪問(wèn)和閉包等特性,同時(shí)也保證了變量的安全性和封裝性。