作用域
作用域即代碼片段的有效范圍,這里的代碼片段可以是一個(gè)函數(shù)、一個(gè)變量等。
在 JavaScript 中,通常被拿來討論的是 全局作用域
和 函數(shù)作用域
。
1. 全局作用域
在全局環(huán)境下定義的變量、函數(shù),都屬于全局作用域的范圍,也就是這些變量、函數(shù)在任何地方都能被訪問。
var number = 1;
var fn = function() {
console.log('我是一個(gè)全局下的函數(shù)');
console.log('訪問全局下的 number: ', number);
};
fn();
全局的作用域很好理解,即全局下的變量、函數(shù)在任何地方都能被訪問到。
在 ES6 的模塊化規(guī)范中,一個(gè)模塊就是一個(gè) js 文件,所以如果在 ES6 的模塊的最頂層聲明變量和函數(shù),是不屬于全局的。
2. 函數(shù)作用域
函數(shù)擁有自己的作用域,也就是說函數(shù)內(nèi)聲明的變量和函數(shù),只在函數(shù)內(nèi)有效。
var fn = function() {
var innerFn = function() {
console.log('我是函數(shù)內(nèi)的函數(shù)');
};
var str = '我是函數(shù)內(nèi)的變量';
innerFn();
console.log(str);
};
fn();
console.log(str); // 輸出:ReferenceError: str is not defined
函數(shù)內(nèi)的變量 str
在函數(shù)外部無法訪問到,因?yàn)槠渌诘淖饔糜蚴呛瘮?shù) fn
的作用域,所以只在 fn
函數(shù)內(nèi)能被訪問。
3. eval 的作用域
eval 根據(jù)調(diào)用的方式,其作用域也會(huì)發(fā)生變化。
如果直接調(diào)用 eval
則其作用域就是當(dāng)前上下文中的作用域。如果間接性質(zhì)的調(diào)用,比如通過一個(gè) eval
的引用來調(diào)用,那作用域就是全局的。
var storeEval = eval;
(function() {
storeEval('var number1 = 1;');
eval('var number2 = 2');
console.log('自執(zhí)行匿名函數(shù)內(nèi)輸出:', number2);
})();
console.log(number1); // 輸出:1
console.log(number2); // 輸出:ReferenceError: number2 is not defined
本身 eval 用到的情況就少,所以這種情況下做個(gè)了解即可。
4. 作用域鏈
理解了作用域,作用域鏈就很好理解了。
通常情況下,內(nèi)層作用域擁有訪問上層作用域的能力,而外層無法訪問到內(nèi)層的作用域。
var number = 1;
var fn = function() {
console.log(number);
var str = '字符串';
};
fn();
console.log(str); // 輸出:ReferenceError: str is not defined
由此可見作用域從內(nèi)往外的。
var number1 = 1;
var fn1 = function() {
var number2 = 2;
var fn2 = function() {
var number3 = 3;
var fn3 = function() {
console.log('fn3 內(nèi)的輸出:');
console.log(number1);
console.log(number2);
console.log(number3);
}
fn3();
};
fn2();
}
fn1();
例子中的 fn3
就具有訪問 fn2作用域
、fn1作用域
、全局作用域
的能力。
這樣從內(nèi)往外就形成了一條作用域鏈。
5. 利用函數(shù)作用域進(jìn)行封裝
函數(shù)作用域最常用的場(chǎng)景之一就是隔離作用域。
因?yàn)楹瘮?shù)有自己的作用域,所以很多庫、框架在實(shí)現(xiàn)的時(shí)候都會(huì)把內(nèi)容寫在一個(gè)函數(shù)中。
(function() {
var config = {};
var fn = function() {
// ...
};
window.$ = fn;
window.jQuery = fn;
})();
這樣就不會(huì)污染到全局,只對(duì)外暴露想要暴露的部分。
6. 小結(jié)
有關(guān)作用域有更深入的內(nèi)容,本篇探討的是最容易理解的部分。
理解作用域可以更好的組織代碼結(jié)構(gòu),減少各個(gè)上下文的污染。
在 ES6 中引入了塊及作用域的概念,這是在之前都沒有的,可以查閱 ES6 中對(duì)應(yīng)的內(nèi)容進(jìn)行了解。