1、Javascript只有兩種作用域:一種是全局作用域,變量在整個(gè)程序中一直存在,所有地方都可以讀取;另一種是函數(shù)作用域,變量只在函數(shù)內(nèi)部存在。
在函數(shù)外部聲明的變量就是全局變量(global variable),它可以在函數(shù)內(nèi)部讀取。
var v = 1;
function f(){
console.log(v);
}
f() // 1
上面的代碼表明,函數(shù)f內(nèi)部可以讀取全局變量v。
在函數(shù)內(nèi)部定義的變量,外部無(wú)法讀取,稱(chēng)為“局部變量”(local variable)。
function f(){
var v = 1;
}
v // ReferenceError: v is not defined
上面代碼中,變量v在函數(shù)內(nèi)部定義,所以是一個(gè)局部變量,函數(shù)之外就無(wú)法讀取。
函數(shù)內(nèi)部定義的變量,會(huì)在該作用域內(nèi)覆蓋同名全局變量。
var v = 1;
function f(){
var v = 2;
console.log(v);
}
f() // 2
v // 1
上面代碼中,變量v同時(shí)在函數(shù)的外部和內(nèi)部有定義。結(jié)果,在函數(shù)內(nèi)部定義,局部變量v覆蓋了全局變量v。
注意,對(duì)于var命令來(lái)說(shuō),局部變量只能在函數(shù)內(nèi)部聲明,在其他區(qū)塊中聲明,一律都是全局變量?!具@里的意思是說(shuō)用var 在函數(shù)內(nèi)部申明的變量在函數(shù)外面訪(fǎng)問(wèn)不到。另外塊級(jí)作用域是指的是全局變量(只要不是用function內(nèi)部定義的都算是全局變量)】
這里就是非function內(nèi)部定義的,則可以稱(chēng)之為全局變量,所以在此時(shí)則可以稱(chēng)之為js沒(méi)有塊級(jí)作用域(也就是在花括號(hào)里面的東西對(duì)外部而言是可見(jiàn)的)
if (true) {
var x = 5;
}
console.log(x); // 5,可見(jiàn),無(wú)塊級(jí)作用域
上面代碼中,變量x在條件判斷區(qū)塊之中聲明,結(jié)果就是一個(gè)全局變量,可以在區(qū)塊之外讀取。
函數(shù)內(nèi)部的變量提升
與全局作用域一樣,函數(shù)作用域內(nèi)部也會(huì)產(chǎn)生“變量提升”現(xiàn)象。var命令聲明的變量,不管在什么位置,變量聲明都會(huì)被提升到函數(shù)體的頭部。
function foo(x) {
if (x > 100) {
var tmp = x - 100;
}
}
上面的代碼等同于
function foo(x) {
var tmp;
if (x > 100) {
tmp = x - 100;
};
}
函數(shù)本身的作用域
函數(shù)本身也是一個(gè)值,也有自己的作用域。它的作用域與變量一樣,就是其聲明時(shí)所在的作用域,與其運(yùn)行時(shí)所在的作用域無(wú)關(guān)。
var a = 1;
var x = function () {
console.log(a);
};
function f() {
var a = 2;
x();
}
f() // 1
上面代碼中,函數(shù)x是在函數(shù)f的外部聲明的,所以它的作用域綁定外層,內(nèi)部變量a不會(huì)到函數(shù)f體內(nèi)取值,所以輸出1,而不是2。
總之,函數(shù)執(zhí)行時(shí)所在的作用域,是定義時(shí)的作用域,而不是調(diào)用時(shí)所在的作用域。
很容易犯錯(cuò)的一點(diǎn)是,如果函數(shù)A調(diào)用函數(shù)B,卻沒(méi)考慮到函數(shù)B不會(huì)引用函數(shù)A的內(nèi)部變量。
var x = function () {
console.log(a);
};
function y(f) {
var a = 2;
f();
}
y(x)
// ReferenceError: a is not defined
上面代碼將函數(shù)x作為參數(shù),傳入函數(shù)y。但是,函數(shù)x是在函數(shù)y體外聲明的,作用域綁定外層,因此找不到函數(shù)y的內(nèi)部變量a,導(dǎo)致報(bào)錯(cuò)。
同樣的,函數(shù)體內(nèi)部聲明的函數(shù),作用域綁定函數(shù)體內(nèi)部。
function foo() {
var x = 1;
function bar() {
console.log(x);
}
return bar;
}
var x = 2;
var f = foo();
f() // 1
上面代碼中,函數(shù)foo內(nèi)部聲明了一個(gè)函數(shù)bar,bar的作用域綁定foo。當(dāng)我們?cè)趂oo外部取出bar執(zhí)行時(shí),變量x指向的是foo內(nèi)部的x,而不是foo外部的x。正是這種機(jī)制,構(gòu)成了下文要講解的“閉包”現(xiàn)象。
js中沒(méi)有塊級(jí)作用域。塊級(jí)作用域意思就是說(shuō)相對(duì)于外面是隱身不可見(jiàn)的。就是說(shuō)在js中,我們定義的那個(gè)變量在外面還是可以訪(fǎng)問(wèn)的到的。
var a=10;if(a){var b=10;} console.log(b);//10
這里不是function定義的函數(shù),所以沒(méi)有塊級(jí)作用域所以能訪(fǎng)問(wèn)到,但是但是在function中就不能訪(fǎng)問(wèn)到了。
function f(){var m=10;} console.log(m);//Uncaught ReferenceError: m is not defined
所以js的塊級(jí)作用域是相對(duì)于非函數(shù)而言。