一、什么是作用域?
作用域是指變量或函數(shù)的有效范圍,我更個人的理解是把作用域看作是一套限制變量作用范圍的規(guī)則沈条,這個變量可以是基本數(shù)據(jù)類型(數(shù)值匾委、字符串拖叙、布爾類型),也可以是引用數(shù)據(jù)類型(對象赂乐、數(shù)組薯鳍、函數(shù)),作用域最根本的作用挨措,就是限制了變量的可讀取性挖滤,從而影響它的作用范圍。
1. 全局作用域
在函數(shù)外部聲明的變量浅役,可以在腳本的任意地方被使用斩松,這種變量稱之為全局變量(global variable),它的作用范圍被稱為全局作用域觉既。
var weather = 'sunny';//聲明全局變量weather
function weatheris(){
var result = 'Today\'s weather is '+weather+'.';
console.log(result);
}
weatheris();//Today's weather is sunny.
在上面的代碼中惧盹,函數(shù)weatheris里面并沒有聲明變量weather,但依然能調(diào)用weather的值,這是因為變量weather是在函數(shù)外部的全局環(huán)境下聲明瞪讼,其作用域是全局作用域钧椰,可以在該腳本所有位置所調(diào)用。
然而符欠,作為全局變量也意味著有可能在其他函數(shù)內(nèi)部不經(jīng)意地被修改嫡霞。
var weather = 'sunny';//聲明全局變量weather
function weatheris(){
weather = 'cloudy';
var result = 'Today\'s weather is '+ weather +'.';
console.log(result);
}
weatheris();//Today's weather is cloudy.
console.log(weather);//cloudy
當(dāng)函數(shù)內(nèi)部修改了此前創(chuàng)建過的全局變量的時候,不單單只是在函數(shù)內(nèi)部生效希柿,同時也對全局環(huán)境下其他引用了這個 變量的地方生效诊沪。上述例子中,在函數(shù)weatheris里面修改了全局變量weather以后狡汉,weather的值就被修改了娄徊。
2. 函數(shù)作用域
在函數(shù)內(nèi)部聲明的變量就是局部變量(local variable)闽颇。與全局變量相反盾戴,局部變量只能在聲明該變量的函數(shù)內(nèi)部所讀取,在函數(shù)外部是無法被讀取和調(diào)用的兵多。
function weatheris() {
var weather = 'sunny';
console.log(weather);
}
weatheris()//sunny
console.log(weather);//報錯:weather is not defined
我們可以看到尖啡,在函數(shù)內(nèi)部聲明的變量weather,可以被立即調(diào)用剩膘,但是脫離了函數(shù)以后衅斩,輸出weather卻顯示變量未被聲明。在這種情況下怠褐,我們一般稱變量weather為局部變量畏梆,其作用域稱為函數(shù)作用域或者局部作用域。
二、什么是作用域鏈奠涌?
當(dāng)代碼進(jìn)入一個環(huán)境中執(zhí)行的時候宪巨,會創(chuàng)建變量對象的一個作用域鏈。我個人把作用域鏈理解為一套對變量進(jìn)行訪問和查找的規(guī)則溜畅,它絕對了在當(dāng)前執(zhí)行環(huán)境下捏卓,有哪些變量是可以被訪問,如果當(dāng)前執(zhí)行環(huán)境下沒有這個變量慈格,又應(yīng)該去哪里查找怠晴。
先看一個簡單的例子:
function weatheris(){
var weather = 'sunny';
function result(){
console.log ('Today\'s weather is '+ weather);
}
result();
}//聲明函數(shù)weatheris
weatheris();//Today's weather is sunny.
如果不了解作用域鏈的同學(xué)就會產(chǎn)生疑問,為什么函數(shù)result可以調(diào)用變量weather呢浴捆?weather明明不是在result內(nèi)部聲明的呀蒜田?
這是因為,result函數(shù)是在weatheris函數(shù)的函數(shù)作用域里面选泻,換句話來說物邑,這兩個函數(shù)的作用域嵌套了,解析器無法再result函數(shù)里面找到變量weather的時候滔金,就會向上色解,來到聲明函數(shù)result的那一層作用域里面尋找,找到以后就會訪問這個變量獲取其值餐茵,放回result函數(shù)里面進(jìn)行調(diào)用科阎。而上述的一系列的過程,正是作用域鏈運(yùn)用的體現(xiàn)忿族,所以我把它理解為一套對變量進(jìn)行訪問和查找的規(guī)則锣笨。
需要注意的是,上述代碼之所以能正確被解析并執(zhí)行的一個關(guān)鍵點道批,在于兩個函數(shù)作用域的嵌套错英。作用域只能被嵌套,不能重疊隆豹。假如我們把上述的部分代碼的位置改變一下:
function weatheris(){
var weather = 'sunny';
}
function result(){
console.log ('Today\'s weather is '+ weather);
}
result();//保存weather is not defined
weatheris();//只是在weatheris函數(shù)作用域內(nèi)聲明了變量weather椭岩,賦值為‘sunny’。
上面代碼中璃赡,函數(shù)weatheris和函數(shù)result兩者的函數(shù)作用域是平行的判哥,也就是說兩者內(nèi)部的變量都無法被相互訪問,所以出現(xiàn)了報錯提示weather is not defined
碉考,也無法達(dá)到我們想要的效果塌计。