摘要:但是碰到聲明提升,這種想法就會(huì)被打破。聲明一個(gè)函數(shù)進(jìn)行相應(yīng)的操作,會(huì)得到函數(shù)聲明提升的結(jié)果。由此可以發(fā)現(xiàn)變量和函數(shù)的聲明都會(huì)被提升在其他代碼的前面執(zhí)行。一個(gè)普通塊內(nèi)部的函數(shù)聲明通常會(huì)被提升到所在的作用域的頂部。的創(chuàng)建初始化和賦值均會(huì)被提升。
Javascript聲明提升
在分析聲明提升之前,我認(rèn)為有必要知道的兩點(diǎn):
一、引擎查詢變量的兩種方式引擎查詢變量的方式可以分為L(zhǎng)HS和RHS兩種方式,通過(guò)“L”和“R”是可以大致了解意思,分別是賦值操作的左側(cè)和右側(cè)。 (不能光是理解為“=”的左右側(cè)可不行,因?yàn)橘x值操作的形式有多種。)
簡(jiǎn)單說(shuō)下我對(duì)這兩種查詢方式的理解:
LHS:賦值操作的目標(biāo)是誰(shuí)。 (查詢變量)
RHS:誰(shuí)是賦值操作的源頭。 (查詢變量的值)
這樣說(shuō)可能有些難以理解,舉個(gè)栗子:
function foo(a){ //這里存在一個(gè)隱式變量分配,LHS查詢變量a,并賦值2. //隱式a = 2; //左邊LHS查詢變量b,查詢作用域中是否存在b這個(gè)變量。 //右邊RHS查詢變量a的值,將a賦值給b。 var b = a; //返回a,b是RHS查詢變量a的值和變量b的值并使用。 return a + b; } //左邊LHS查詢變量c,查詢作用域中是否存在c這個(gè)變量。 //右邊RHS引用函數(shù)foo,將2作為參數(shù)傳進(jìn)去。 var c = foo(2);二、異常
關(guān)于異常要強(qiáng)調(diào)一點(diǎn),必須在嚴(yán)格模式下。因?yàn)樵诜菄?yán)格模式下,LHS查詢?nèi)羰窃谧铐攲拥娜肿饔糜蛏险也坏讲樵兊淖兞?,則會(huì)創(chuàng)建一個(gè)該名稱變量返還給引擎。
ReferenceError:同作用域判別失敗相關(guān)。(比如:作用域中遍尋不到所需的變量)
TypeError:作用域判別成功了,但是對(duì)結(jié)果的操作是非法或不合理的。(比如:試圖對(duì)一個(gè)非函數(shù)類型的值進(jìn)行函數(shù)調(diào)用,或者引用null或undefined類型的值中的屬性)
舉個(gè)栗子:
"strict" function foo() { console.log(a) //undefined console.log(b) //ReferenceError } var a = 2;聲明提升 一、初步了解
編寫javascript代碼時(shí),很多時(shí)候都會(huì)覺得代碼會(huì)自上而下的執(zhí)行。但是碰到聲明提升,這種想法就會(huì)被打破。
舉個(gè)栗子:
a = 2; var a; console.log(a); 運(yùn)行結(jié)果為: 2
如果按照常理的自上而下執(zhí)行,那么a執(zhí)行的預(yù)期結(jié)果應(yīng)當(dāng)是undefined,然而為什么會(huì)是2?
這就是聲明提升的結(jié)果。
當(dāng)初步了解聲明提升的時(shí)候,碰上下面的代碼:
console.log(a); var a = 2; 運(yùn)行結(jié)果為:undefined
初步了解聲明提升之后,會(huì)自然而然的認(rèn)為,聲明就會(huì)被提升,然而聲明的時(shí)候賦值,卻得不到變量的值。
其實(shí),上面代碼的運(yùn)行步驟可以分解為:
var a; //聲明提升 console.log(a); //打印a的值 a = 2; //對(duì)a進(jìn)行賦值
原來(lái),聲明提升就是字面上的聲明提升,其余的操作(如:賦值和其他邏輯)都還在原地踏步。
聲明一個(gè)函數(shù)進(jìn)行相應(yīng)的操作,會(huì)得到函數(shù)聲明提升的結(jié)果。由此可以發(fā)現(xiàn):變量和函數(shù)的聲明都會(huì)被提升在其他代碼的前面執(zhí)行。
三、逐步了解通過(guò)幾次試驗(yàn)可以逐步了解到,其實(shí)聲明提升就是:變量和函數(shù)的聲明會(huì)被提升在其他代碼(當(dāng)前作用域)的前面執(zhí)行。
走到這里,有人就會(huì)想到,要是函數(shù)表達(dá)式,也會(huì)進(jìn)行提升嗎?
答案是:不會(huì)。而且,即使是具名函數(shù)表達(dá)式,在名稱標(biāo)識(shí)符賦值之前也是不能使用的。
舉個(gè)栗子:
foo(); //TypeError bar(); //ReferenceError var foo = function bar(){};
代碼分解為:
var foo; //變量聲明提升 foo(); //foo對(duì)undefined值進(jìn)行函數(shù)調(diào)用導(dǎo)致非法操作,故TypeError bar(); //bar函數(shù)并沒有聲明,故ReferenceError foo = function bar(){}; //對(duì)foo進(jìn)行賦值
所以:函數(shù)表達(dá)式在名稱標(biāo)識(shí)符賦值之前是不能使用的。
注意:1、每個(gè)作用域都會(huì)進(jìn)行提升操作。(所以函數(shù)內(nèi)部形成的作用域也會(huì)有提升操作,提升 操作僅限當(dāng)前的函數(shù)內(nèi)部作用域)
2、在函數(shù)和變量提升時(shí),函數(shù)優(yōu)先提升。
3、一個(gè)普通塊內(nèi)部的函數(shù)聲明通常會(huì)被提升到所在的作用域的頂部。
在閱讀《你不知道的javascript》時(shí),學(xué)習(xí)let的過(guò)程中,會(huì)發(fā)現(xiàn)有說(shuō)明提到:使用let進(jìn)行的聲明不會(huì)在作用域中進(jìn)行提升。聲明的代碼在被運(yùn)行之前是,聲明并不存在。
舉個(gè)栗子:
console.log(a); let a = 2; 運(yùn)行結(jié)果是:ReferenceError: Cannot access "a" before initialization. //初始化前無(wú)法訪問"a"
然后回到之前我運(yùn)行的代碼,將let換為var,返回的結(jié)果是undefined。
二者結(jié)合,再加上閱讀我用了兩個(gè)月的時(shí)間才理解let這篇文章,發(fā)現(xiàn)對(duì)let是否提升有了一個(gè)更新的認(rèn)識(shí)。
作者把js變量分成三部分操作:創(chuàng)建(create)、初始化(initialize)和賦值(assign)。
上面的操作之所以會(huì)有不同的響應(yīng)并不是說(shuō)let沒有創(chuàng)建,而是有一個(gè)初始化的過(guò)程并沒有執(zhí)行。而在初始化之前使用變量,就會(huì)形成一個(gè)暫時(shí)性死區(qū)。
經(jīng)過(guò)var和let和function的測(cè)試可以總結(jié)到:
var的創(chuàng)建和初始化被提升,賦值不會(huì)被提升。
let的創(chuàng)建被提升,初始化和賦值不會(huì)被提升。
function的創(chuàng)建、初始化和賦值均會(huì)被提升。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/102824.html
摘要:代碼在執(zhí)行時(shí)并不完全是由上到下一行一行執(zhí)行的,由此產(chǎn)生了一個(gè)提升的問題。第二個(gè)賦值聲明會(huì)被留在原地等待執(zhí)行階段??梢缘弥瘮?shù)聲明提升的優(yōu)先權(quán)大于普通變量聲明。 JavaScript代碼在執(zhí)行時(shí)并不完全是由上到下一行一行執(zhí)行的,由此產(chǎn)生了一個(gè)提升的問題。 什么是提升 可以簡(jiǎn)單理解為:聲明(變量和函數(shù))都會(huì)被移動(dòng)到各自作用域的最頂端,這個(gè)過(guò)程被稱為提升。 具體例子看提升 下面兩個(gè)例子a會(huì)l...
摘要:輸出的結(jié)果為輸出的結(jié)果為提升后輸出的結(jié)果為重新定義了變量輸出的結(jié)果為如果定義了相同的函數(shù)變量聲明,后定義的聲明會(huì)覆蓋掉先前的聲明,看如下代碼輸出練習(xí)的值是多少的值是多少第二題的解析請(qǐng)看這里參考資料文章文章中文版鏈接文章推薦文章變量提升 JavaScript 變量聲明提升 原文鏈接 一個(gè)小例子 先來(lái)看個(gè)例子: console.log(a); // undefined var a =...
摘要:有意思的是,這意味著變量在聲明之前甚至已經(jīng)可用。的這個(gè)特性被非正式地稱為聲明提前,即函數(shù)里聲明的所有變量但不涉及賦值都被提前至函數(shù)體的頂部。但實(shí)際上會(huì)將其看成兩個(gè)聲明和。第二個(gè)賦值聲明會(huì)被留在原地等待執(zhí)行階段。 簡(jiǎn)介 JavaScript的函數(shù)作用域是指在函數(shù)內(nèi)聲明的所有變量在函數(shù)體內(nèi)始終是可見的。有意思的是,這意味著變量在聲明之前甚至已經(jīng)可用。JavaScript的這個(gè)特性被非正式地...
摘要:函數(shù)和變量相比,會(huì)被優(yōu)先提升。這意味著函數(shù)會(huì)被提升到更靠前的位置。僅提升聲明,而不提升初始化。 JavaScript 函數(shù)高級(jí)——執(zhí)行上下文與執(zhí)行上下文棧(圖解+典型實(shí)例分析) 變量提升與函數(shù)提升 變量聲明提升 通過(guò) var 定義(聲明)的變量,在定義語(yǔ)句之前就可以訪問到 值:undefined /* 面試題 : 輸出 undefined */ var a = 3 ...
摘要:變量提升需要注意兩點(diǎn)提升的部分只是變量聲明,賦值語(yǔ)句和可執(zhí)行的代碼邏輯還保持在原地不動(dòng)提升只是將變量聲明提升到變量所在的變量范圍的頂端,并不是提升到全局范圍,說(shuō)明如下會(huì)輸出變量提升之后的效果函數(shù)聲明會(huì)提升,但是函數(shù)表達(dá)式就不了。 問題 有些朋友可能會(huì)覺得javascript的代碼是從上到下,一行一行的解釋執(zhí)行的。如果按照這樣的思路,在有些情況下閱讀代碼會(huì)得到錯(cuò)誤的結(jié)果,考慮以下代碼: ...
閱讀 528·2023-04-25 23:00
閱讀 3537·2021-11-22 13:54
閱讀 1961·2021-10-27 14:14
閱讀 1530·2019-08-30 13:59
閱讀 3566·2019-08-23 16:15
閱讀 2018·2019-08-23 16:06
閱讀 3388·2019-08-23 15:26
閱讀 1313·2019-08-23 13:48