js作用域(一):javascript作用域是什么?

js.jpg

如果我的文章對你有用屁商,請給我一個贊烟很,讓我有繼續(xù)堅持的動力/微笑。
原創(chuàng)文章蜡镶,此文章僅供學(xué)習(xí)參考使用镜撩,歡迎訪問我的個人網(wǎng)站zhengyepan
一葛作、理解作用域
js越是基礎(chǔ)的知識,越是會被人以為沒有什么大不了的讥耗,其實毒坛,js的基礎(chǔ)是很有“內(nèi)涵”的望伦,就作用域來講林说。首先需要了解幾個概念

1、引擎:從頭到尾負(fù)責(zé)JavaScript的編譯和執(zhí)行過程.

2屯伞、編譯器:負(fù)責(zé)語法分析與代碼生成腿箩。

3、作用域:負(fù)責(zé)聲明并維護由所有聲明的標(biāo)識符(變量)組成一系列查詢劣摇,并實施一套非常嚴(yán)格的規(guī)則珠移,確定當(dāng)前執(zhí)行的代碼對這些標(biāo)識符的訪問權(quán)限。

變量的賦值操作會執(zhí)行兩個階段末融,首先編譯器會在當(dāng)前作用域下聲明一個變量(如果之前沒有聲明過)钧惧,然后在運行時引擎會在作用域中查找該變量,如果能夠找到就會對它賦值勾习。

編譯器在編譯過程中的第二步生成代碼浓瞪,引擎執(zhí)行到它時,會通過查找變量a來判斷是是否被聲明過巧婶。查找的過程有作用域進行協(xié)助乾颁,但是引擎執(zhí)行怎么樣的查找會影響最終的查找結(jié)果。

引擎查找的方式有LHS和RHS艺栈∮⒘耄“L”和“R”分別代表著左側(cè)和右側(cè),具體是一個賦值操作的左側(cè)和右側(cè)眼滤。

那么引擎什么時候進行LHS或者RHS查找方式呢巴席?答案就是當(dāng)變量出現(xiàn)在賦值操作左側(cè)的時候進行LHS,當(dāng)變量出現(xiàn)在賦值操作右側(cè)的時候進行RHS。更加準(zhǔn)確的來講诅需,RHS的真正意思是“取到它的源值”漾唉,這意味著得到某某的值,其中對a 的引用是一個RHS 引用堰塌,因為這里a 并沒有賦予任何值赵刑。相應(yīng)地,需要查找并取得a 的值场刑,這樣才能將值傳遞給console.log(..)般此。相比之下,例如:a = 2;這里對a 的引用則是LHS 引用牵现,因為實際上我們并不關(guān)心當(dāng)前的值是什么铐懊,只是想要為=2 這個賦值操作找到一個目標(biāo)。

重要結(jié)論:LHS 和RHS 的含義是“賦值操作的左側(cè)或右側(cè)”并不一定意味著就是“=賦值操作符的左側(cè)或右側(cè)”瞎疼。賦值操作還有其他幾種形式科乎,因此在概念上最好將其理解為“賦值操作的目標(biāo)是誰(LHS)”以及“誰是賦值操作的源頭RHS)”。

下面的程序贼急,其中既有LHS 也有RHS 引用:

function foo(a) {
    console.log( a ); // 2
}
foo( 2 );

最后一行foo(..) 函數(shù)的調(diào)用需要對foo 進行RHS 引用茅茂,意味著“去找到foo 的值捏萍,并把它給我”。并且(..) 意味著foo 的值需要被執(zhí)行空闲,因此它最好真的是一個函數(shù)類型的值令杈!這里還有一個容易被忽略卻非常重要的細(xì)節(jié)。代碼中隱式的a=2 操作可能很容易被你忽略掉碴倾。這個操作發(fā)生在2 被當(dāng)作參數(shù)傳遞給foo(..) 函數(shù)時逗噩,2 會被分配給參數(shù)a。為了給參數(shù)a(隱式地)分配值影斑,需要進行一次LHS 查詢给赞。

這里還有對a 進行的RHS 引用, 并且將得到的值傳給了console.log(..)矫户。console.log(..) 本身也需要一個引用才能執(zhí)行片迅,因此會對console 對象進行RHS 查詢,并且檢查得到的值中是否有一個叫作log 的方法皆辽。最后柑蛇,在概念上可以理解為在LHS 和RHS 之間通過對值2 進行交互來將其傳遞進log(..)(通過變量a 的RHS 查詢)。假設(shè)在log(..) 函數(shù)的原生實現(xiàn)中它可以接受參數(shù)驱闷,在將2 賦值給其中第一個(也許叫作arg1)參數(shù)之前耻台,這個參數(shù)需要進行LHS 引用查詢。

有可能你可能會傾向于將函數(shù)聲明function foo(a) {... 概念化為普通的變量聲明和賦值空另,比如var foo盆耽、foo = function(a) {...。如果這樣理解的話扼菠,這個函數(shù)聲明將需要進行LHS 查詢摄杂。然而還有一個重要的細(xì)微差別,編譯器可以在代碼生成的同時處理聲明和值的定義循榆,比如在引擎執(zhí)行代碼時析恢,并不會有線程專門用來將一個函數(shù)值“分配給”foo。因此秧饮,將函數(shù)聲明理解成前面討論的LHS 查詢和賦值的形式并不合適映挂。

function foo(a) {
    console.log( a ); // 2
}
foo( 2 );

讓我們來模擬上面過程中引擎和作用域之前的操作:
引擎需要為foo 進行RHS 引用。于是向作用域請求foo的聲明
作用域響應(yīng):編譯器剛剛聲明了它盗尸。它是一個函數(shù)柑船,給你。
引擎:執(zhí)行foo泼各。
引擎:需要為a 進行LHS 引用椎组,向作用域請求
作用域:編譯器最近把它聲名為foo 的一個形式參數(shù)了,給你历恐。
引擎:收到a ,現(xiàn)在要把2 賦值給a寸癌。
引擎:要為console 進行RHS 引用,問作用域見過它嗎弱贼?
作用域:console 是個內(nèi)置對象蒸苇。給引擎。
引擎:這里面是不是有l(wèi)og(..)吮旅。太好了溪烤,找到了,是一個函數(shù)庇勃。
引擎:請問a 的RHS 引用嗎檬嘀?雖然我記得它,但想再確認(rèn)一次责嚷。
作用域:這個變量沒有變動過鸳兽,拿走,不謝罕拂。
引擎:真棒揍异。我來把a 的值,也就是2爆班,傳遞進log(..)衷掷。

……
為什么區(qū)分LHS 和RHS 是一件重要的事情?因為在變量還沒有聲明(在任何作用域中都無法找到該變量)的情況下柿菩,這兩種查詢的行為是不一樣的戚嗅。

舉個例子:

function foo(a) {
    console.log( a + b );
    b = a;
}
foo( 2 );

第一次對b 進行RHS 查詢時是無法找到該變量的。也就是說枢舶,這是一個“未聲明”的變量懦胞,因為在任何相關(guān)的作用域中都無法找到它。如果RHS 查詢在所有嵌套的作用域中遍尋不到所需的變量祟辟,引擎就會拋出ReferenceError異常医瘫。

值得注意的是,ReferenceError 是非常重要的異常類型旧困。相較之下醇份,當(dāng)引擎執(zhí)行LHS 查詢時,如果在頂層(全局作用域)中也無法找到目標(biāo)變量吼具,全局作用域中就會創(chuàng)建一個具有該名稱的變量僚纷,并將其返還給引擎,前提是程序運行在非“嚴(yán)格模式”下拗盒〔澜撸“不,這個變量之前并不存在陡蝇,但是我很熱心地幫你創(chuàng)建了一個痊臭。
”ES5 中引入了“嚴(yán)格模式”哮肚。同正常模式,或者說寬松/ 懶惰模式相比广匙,嚴(yán)格模式在行為上有很多不同允趟。其中一個不同的行為是嚴(yán)格模式禁止自動或隱式地創(chuàng)建全局變量。

因此鸦致,在嚴(yán)格模式中LHS 查詢失敗時潮剪,并不會創(chuàng)建并返回一個全局變量,引擎會拋出同RHS 查詢失敗時類似的ReferenceError 異常分唾。接下來抗碰,如果RHS 查詢找到了一個變量,但是你嘗試對這個變量的值進行不合理的操作绽乔,比如試圖對一個非函數(shù)類型的值進行函數(shù)調(diào)用弧蝇,或著引用null 或undefined 類型的值中的屬性,那么引擎會拋出另外一種類型的異常迄汛,叫作TypeError捍壤。

ReferenceError 同作用域判別失敗相關(guān),而TypeError 則代表作用域判別成功了鞍爱,但是對結(jié)果的操作是非法或不合理的鹃觉。

二、作用域的嵌套
作用域是根據(jù)名稱查找變量的一套規(guī)則睹逃。實際情況中盗扇,通常需要同時顧及幾個作用域。當(dāng)一個塊或函數(shù)嵌套在另一個塊或函數(shù)中時沉填,就發(fā)生了作用域的嵌套疗隶。因此,在當(dāng)前作用域中無法找到某個變量時翼闹,引擎就會在外層嵌套的作用域中繼續(xù)查找斑鼻,直到找到該變量,或抵達(dá)最外層的作用域(也就是全局作用域)為止猎荠。

例如以下代碼:

function foo(a) {
    console.log( a + b );
}
var b = 2;
foo( 2 ); // 4

對b 進行的RHS 引用無法在函數(shù)foo 內(nèi)部完成坚弱,但可以在上一級作用域(在這個例子中就是全局作用域)中完成。

遍歷嵌套作用域鏈的規(guī)則很簡單:引擎從當(dāng)前的執(zhí)行作用域開始查找變量关摇,如果找不到荒叶,就向上一級繼續(xù)查找。當(dāng)?shù)诌_(dá)最外層的全局作用域時输虱,無論找到還是沒找到些楣,查找過程都會停止。

總結(jié):

作用域是一套規(guī)則,用于確定在何處以及如何查找變量(標(biāo)識符)愁茁。如果查找的目的是對變量進行賦值蚕钦,那么就會使用LHS 查詢;如果目的是獲取變量的值埋市,就會使用RHS 查詢冠桃。

作用域是什么 賦值操作符會導(dǎo)致LHS 查詢。=操作符或調(diào)用函數(shù)時傳入?yún)?shù)的操作都會導(dǎo)致關(guān)聯(lián)作用域 的賦值操作道宅。JavaScript 引擎首先會在代碼執(zhí)行前對其進行編譯,在這個過程中胸蛛,像var a = 2 這樣的聲 明會被分解成兩個獨立的步驟:

  1. 首先污茵,var a 在其作用域中聲明新變量。這會在最開始的階段葬项,也就是代碼執(zhí)行前進行泞当。

  2. 接下來,a = 2 會查詢(LHS 查詢)變量a 并對其進行賦值民珍。 LHS 和RHS 查詢都會在當(dāng)前執(zhí)行作用域中開始襟士,如果有需要(也就是說它們沒有找到所 需的標(biāo)識符),就會向上級作用域繼續(xù)查找目標(biāo)標(biāo)識符嚷量,這樣每次上升一級作用域(一層 樓)陋桂,最后抵達(dá)全局作用域(頂層),無論找到或沒找到都將停止蝶溶。 不成功的RHS 引用會導(dǎo)致拋出ReferenceError 異常嗜历。不成功的LHS 引用會導(dǎo)致自動隱式 地創(chuàng)建一個全局變量(非嚴(yán)格模式下),該變量使用LHS 引用的目標(biāo)作為標(biāo)識符抖所,或者拋 出ReferenceError 異常(嚴(yán)格模式下)梨州。

學(xué)習(xí)筆記,互勵共勉田轧,歡迎交流討論~
推薦書籍《javaScript高級程序設(shè)計》
歡迎訪問我的個人網(wǎng)站zhengyepan

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末暴匠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子傻粘,更是在濱河造成了極大的恐慌每窖,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抹腿,死亡現(xiàn)場離奇詭異岛请,居然都是意外死亡,警方通過查閱死者的電腦和手機警绩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門崇败,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事后室∷跸ィ” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵岸霹,是天一觀的道長疾层。 經(jīng)常有香客問我,道長贡避,這世上最難降的妖魔是什么痛黎? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮刮吧,結(jié)果婚禮上湖饱,老公的妹妹穿的比我還像新娘。我一直安慰自己杀捻,他們只是感情好井厌,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著致讥,像睡著了一般仅仆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上垢袱,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天墓拜,我揣著相機與錄音,去河邊找鬼惶桐。 笑死撮弧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的姚糊。 我是一名探鬼主播贿衍,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼救恨!你這毒婦竟也來了贸辈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤肠槽,失蹤者是張志新(化名)和其女友劉穎擎淤,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秸仙,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡嘴拢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了寂纪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片席吴。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡赌结,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出孝冒,到底是詐尸還是另有隱情柬姚,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布庄涡,位于F島的核電站量承,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏穴店。R本人自食惡果不足惜撕捍,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望迹鹅。 院中可真熱鬧卦洽,春花似錦、人聲如沸斜棚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽弟蚀。三九已至,卻和暖如春酗失,著一層夾襖步出監(jiān)牢的瞬間义钉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工规肴, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留捶闸,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓拖刃,卻偏偏與公主長得像删壮,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子兑牡,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容