JavaScript中的作用域及作用域鏈

作用域

變量作用域有兩種:全局變量和局部變量。

變量在函數(shù)外定義依疼,即為全局變量贡定,全局變量有全局作用域:網(wǎng)頁(yè)中所有腳本和函數(shù)均可使用晶伦。例如:
var arr = 'hello';
function fn() {
  console.log(arr);
}
fn(); // hello
變量在函數(shù)內(nèi)申明碟狞,變量為局部作用域,局部變量:只能在函數(shù)內(nèi)部訪問(wèn)婚陪。例如:
function fn() {
  var arr1 = 'world';
}
fn();
console.log(arr1); // arr1 is not defined

注:聲明局部變量時(shí)一定要使用var族沃,否則聲明的是全局變量。
因?yàn)榫植孔兞恐蛔饔糜诤瘮?shù)內(nèi)泌参,所以不同的函數(shù)可以使用相同名稱的變量竭业。局部變量在函數(shù)開始執(zhí)行時(shí)創(chuàng)建,函數(shù)執(zhí)行完后局部變量會(huì)自動(dòng)銷毀及舍。

在函數(shù)內(nèi)定義一個(gè)局部變量在函數(shù)體內(nèi)始終是可見的,函數(shù)在解析時(shí)會(huì)將變量聲明提前窟绷。例如:
var arr2 = 'hello';
function fn() {
  console.log(arr2);  // undefined
  var arr2 = 'world';
  console.log(arr2); // world锯玛,局部變量覆蓋了全局變量
}
fn();
var arr2 = 'hello';
function fn() {
  var arr2;  // 提前聲明了局部變量
  console.log(arr2);  // undefined
  arr2 = 'world';
  console.log(arr2); // world,局部變量覆蓋了全局變量
}
fn();

注:局部變量的優(yōu)先級(jí)要高于同名的全局變量兼蜈,也就是當(dāng)局部變量與全局變量重名時(shí)攘残,局部變量會(huì)覆蓋全局變量。


作用域鏈

執(zhí)行環(huán)境:

? ? ? ? 執(zhí)行環(huán)境是在運(yùn)行和執(zhí)行代碼的時(shí)候才存在的为狸,運(yùn)行瀏覽器的時(shí)候會(huì)創(chuàng)建全局的執(zhí)行環(huán)境歼郭,在調(diào)用函數(shù)時(shí),會(huì)創(chuàng)建函數(shù)執(zhí)行環(huán)境辐棒。所以執(zhí)行環(huán)境有全局執(zhí)行環(huán)境(全局環(huán)境)和函數(shù)執(zhí)行環(huán)境之分病曾。
? ? ? ? 全局執(zhí)行環(huán)境:是最外圍的一個(gè)執(zhí)行環(huán)境,在web瀏覽器中可以認(rèn)為是window對(duì)象漾根,因此所有的全局變量和函數(shù)都是作為window對(duì)象的屬性和方法創(chuàng)建的泰涂。代碼載入瀏覽器時(shí),全局環(huán)境被創(chuàng)建辐怕,關(guān)閉網(wǎng)頁(yè)或關(guān)閉瀏覽器時(shí)全局環(huán)境被銷毀逼蒙。
? ? ? ? 函數(shù)執(zhí)行環(huán)境:每個(gè)函數(shù)都有自己的執(zhí)行環(huán)境,當(dāng)執(zhí)行流進(jìn)入一個(gè)函數(shù)時(shí)寄疏,函數(shù)的環(huán)境就被推入一個(gè)環(huán)境棧中是牢,當(dāng)函數(shù)執(zhí)行完畢后,棧將其環(huán)境彈出陕截,把控制權(quán)返回給之前的執(zhí)行環(huán)境驳棱。
? ? ? ? 每個(gè)函數(shù)運(yùn)行時(shí)都會(huì)產(chǎn)生一個(gè)執(zhí)行環(huán)境,執(zhí)行環(huán)境定義了變量和函數(shù)有權(quán)訪問(wèn)的其他數(shù)據(jù)艘策,決定了他們各自的行為蹈胡。每個(gè)執(zhí)行環(huán)境都有與之對(duì)應(yīng)的變量對(duì)象,保存著該環(huán)境中定義的所有變量和函數(shù)。

作用域鏈:

? ? ? ? 全局作用域和局部作用域中變量的訪問(wèn)權(quán)限罚渐,其實(shí)是由作用域鏈決定的却汉。
? ? ? ? 每次進(jìn)入一個(gè)新的執(zhí)行環(huán)境,都會(huì)創(chuàng)建一個(gè)用于搜索變量和函數(shù)的作用域鏈荷并。作用域鏈?zhǔn)呛瘮?shù)被創(chuàng)建的作用域中對(duì)象的集合合砂。作用域鏈可以保證對(duì)執(zhí)行環(huán)境有權(quán)訪問(wèn)的所有變量和函數(shù)的有序訪問(wèn)。
? ? ? ? 作用域鏈的最前端始終是當(dāng)前執(zhí)行代碼所在環(huán)境的變量對(duì)象(如果該環(huán)境是函數(shù)源织,則將其活動(dòng)對(duì)象作為變量對(duì)象)翩伪,下一個(gè)變量對(duì)象來(lái)自包含環(huán)境(包含當(dāng)前運(yùn)行環(huán)境的環(huán)境),下一個(gè)變量對(duì)象來(lái)自包含環(huán)境的包含環(huán)境谈息,依次往上缘屹,直到全局執(zhí)行環(huán)境的變量對(duì)象。全局執(zhí)行環(huán)境的變量對(duì)象始終是作用域鏈中的最后一個(gè)對(duì)象侠仇。

標(biāo)識(shí)符解析是沿著作用域一級(jí)一級(jí)的向上搜索標(biāo)識(shí)符的過(guò)程轻姿。搜素過(guò)程始終是從作用域的前端逐地向后回溯,直到找到標(biāo)識(shí)符(找不到就會(huì)導(dǎo)致錯(cuò)誤發(fā)生)逻炊。
例1:
var a = 1;
function fn1() {
  function fn2() {
    console.log(a); // ③互亮、執(zhí)行fn2輸出a
  }
  function fn3() {
    var a = 4;
    fn2(); // ②、fn3執(zhí)行的結(jié)果得到fn2
  }
  var a = 2;
  return fn3; // ①余素、fn1執(zhí)行結(jié)果的得到fn3
}
var fn = fn1(); // fn1賦值fn豹休,fn1執(zhí)行結(jié)果為fn3
fn(); // 2

解析:
fn()執(zhí)行結(jié)果為fn1,fn1執(zhí)行結(jié)果為fn3桨吊,fn3執(zhí)行結(jié)果為fn2威根,fn2執(zhí)行結(jié)果是輸出a的值。
在函數(shù)fn2()執(zhí)行環(huán)境中沒(méi)有變量a屏积,解析器沿著函數(shù)fn2()的作用域鏈一級(jí)級(jí)向后回溯查找變量a医窿,在父環(huán)境即函數(shù)fn1()中找到變量a,var a = 2炊林,輸出在控制臺(tái)上姥卢。(由于局部變量的優(yōu)先級(jí)要高于同名的全局變量,所以全局var a = 1被覆蓋渣聚。)
結(jié)論:

  • 函數(shù)的局部環(huán)境可以訪問(wèn)函數(shù)作用域中的變量独榴,也可以訪問(wèn)和操作父環(huán)境(包含環(huán)境)乃至全局環(huán)境的變量;
  • 父環(huán)境只能訪問(wèn)其包換環(huán)境和自己環(huán)境中的變量和函數(shù)奕枝,不能訪問(wèn)其子環(huán)境中的變量和環(huán)境棺榔。(所以函數(shù)fn1()不能訪問(wèn)子環(huán)境fn3()中的var a = 4。)
例2:
var a = 1;
function fn1() {
  function fn3() {
    var a = 4;
    fn2();  // ②隘道、fn3執(zhí)行結(jié)果得到fn2
  }
  var a = 2;
  return fn3; // ①症歇、fn1執(zhí)行結(jié)果返回fn3
}
function fn2() {
  console.log(a); // ③郎笆、執(zhí)行fn2輸出a
}
var fn = fn1(); // fn1賦值fn,fn1執(zhí)行結(jié)果為fn3
fn(); // 1

解析:
fn()執(zhí)行結(jié)果為fn1忘晤,fn1執(zhí)行結(jié)果為fn3宛蚓,fn3執(zhí)行結(jié)果為fn2,fn2執(zhí)行結(jié)果是輸出a的值设塔。
在函數(shù)fn2()執(zhí)行環(huán)境中沒(méi)有變量a凄吏,解析器沿著函數(shù)fn2()的作用域鏈一級(jí)級(jí)向后回溯查找變量a,在父環(huán)境(包含環(huán)境)即全局環(huán)境中找到變量a闰蛔,var a = 1痕钢,輸出在控制臺(tái)上。
總結(jié):
全局環(huán)境只能訪問(wèn)全局環(huán)境中的變量和函數(shù)序六,不能直接訪問(wèn)局部環(huán)境中的任何數(shù)據(jù)任连。(所以函數(shù)fn2()在全局環(huán)境不能直接訪問(wèn)函數(shù)fn1()內(nèi)的局部環(huán)境中的var a = 4或var a = 2。)

作用域鏈參考圖:里面能訪問(wèn)外面的例诀,外面不能訪問(wèn)里面的


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末课梳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子余佃,更是在濱河造成了極大的恐慌,老刑警劉巖跨算,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件爆土,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡诸蚕,警方通過(guò)查閱死者的電腦和手機(jī)步势,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)背犯,“玉大人坏瘩,你說(shuō)我怎么就攤上這事∧海” “怎么了倔矾?”我有些...
    開封第一講書人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)柱锹。 經(jīng)常有香客問(wèn)我哪自,道長(zhǎng),這世上最難降的妖魔是什么禁熏? 我笑而不...
    開封第一講書人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任壤巷,我火速辦了婚禮,結(jié)果婚禮上瞧毙,老公的妹妹穿的比我還像新娘胧华。我一直安慰自己寄症,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開白布矩动。 她就那樣靜靜地躺著有巧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪铅忿。 梳的紋絲不亂的頭發(fā)上剪决,一...
    開封第一講書人閱讀 51,578評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音檀训,去河邊找鬼柑潦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛峻凫,可吹牛的內(nèi)容都是我干的渗鬼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼荧琼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼譬胎!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起命锄,我...
    開封第一講書人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤堰乔,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后脐恩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體镐侯,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年驶冒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了苟翻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡骗污,死狀恐怖崇猫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情需忿,我是刑警寧澤诅炉,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站屋厘,受9級(jí)特大地震影響汞扎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜擅这,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一澈魄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧仲翎,春花似錦痹扇、人聲如沸铛漓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)浓恶。三九已至,卻和暖如春结笨,著一層夾襖步出監(jiān)牢的瞬間包晰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工炕吸, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留伐憾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓赫模,卻偏偏與公主長(zhǎng)得像树肃,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瀑罗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355