前言
成都創(chuàng)新互聯(lián)公司專(zhuān)注于網(wǎng)站建設(shè),為客戶(hù)提供成都做網(wǎng)站、成都網(wǎng)站制作、網(wǎng)頁(yè)設(shè)計(jì)開(kāi)發(fā)服務(wù),多年建網(wǎng)站服務(wù)經(jīng)驗(yàn),各類(lèi)網(wǎng)站都可以開(kāi)發(fā),品牌網(wǎng)站設(shè)計(jì),公司官網(wǎng),公司展示網(wǎng)站,網(wǎng)站設(shè)計(jì),建網(wǎng)站費(fèi)用,建網(wǎng)站多少錢(qián),價(jià)格優(yōu)惠,收費(fèi)合理。
開(kāi)始執(zhí)行腳本時(shí),執(zhí)行腳本的第一步是編譯代碼,然后再開(kāi)始執(zhí)行代碼,如圖
另外,在編譯優(yōu)化方面來(lái)說(shuō),最開(kāi)始時(shí)也并不是全部編譯好腳本,而是當(dāng)函數(shù)執(zhí)行時(shí),才會(huì)先編譯,再執(zhí)行腳本,如圖
變量提升
如下圖,左邊灰色塊區(qū)域,是演示函數(shù)執(zhí)行前的編譯階段,先抽出所有聲明變量和聲明函數(shù),并進(jìn)行內(nèi)存分配。然后再開(kāi)始執(zhí)行代碼,在執(zhí)行第一行代碼的時(shí)候,若是變量a存在于內(nèi)存中,則直接給變量a賦值。而執(zhí)行到第二行時(shí),變量b并沒(méi)有在內(nèi)存中,則會(huì)創(chuàng)建變量b并給它賦值。
Lexical enviroment是一種包含標(biāo)識(shí)符變量映射的數(shù)據(jù)結(jié)構(gòu)
LexicalEnviroment = { Identifier:, Indentifier: }
簡(jiǎn)而言之,Lexical enviroment就是程序執(zhí)行過(guò)程中變量和函數(shù)存在的地方。
let,const變量
console.log(a) let a = 3;
輸出
ReferenceError: a is not defined
所以let和const變量并不會(huì)被提升嗎?
這個(gè)答案會(huì)比較復(fù)雜。所有的聲明(function, var, let, const and class)在JavaScript中都會(huì)被提升,然而var聲明被undefined值初始化,但是let和const聲明的值仍然未被初始化。
它們僅僅只在Javascript引擎運(yùn)行期間它們的詞法綁定被執(zhí)行在才會(huì)被初始化。這意味著引擎在源代碼中聲明它的位置計(jì)算其值之前,你無(wú)法訪(fǎng)問(wèn)該變量。這就是我們所說(shuō)的時(shí)間死區(qū),即變量創(chuàng)建和初始化之間的時(shí)間,我們無(wú)法訪(fǎng)問(wèn)該變量。
如果JavaScript引擎仍然無(wú)法在聲明它們的行中找到let或者const的值,它將為它們分配undefined值或返回錯(cuò)誤值(在const的情況下會(huì)返回錯(cuò)誤值)。
6a9a50532bf60f5fac6b3c.png](evernotecid://F2BCA3B5-CC5A-4EB3-BD61-DD865800F342/appyinxiangcom/10369121/ENResource/p1163)
let a; console.log(a); // outputs undefined a = 5;
在編譯階段,JavaScript引擎遇到變量a并將它存儲(chǔ)在lexical enviroment,但是因?yàn)樗且粋€(gè)let變量,所以引擎不會(huì)為它初始化任何值。所以,在編譯階段,lexical enviroment看起來(lái)像下面這樣。
// 編譯階段 lexicalEnvironment = { a:}
現(xiàn)在如果我們嘗試在聲明它之前訪(fǎng)問(wèn)該變量,JavaScript引擎將會(huì)嘗試從詞法環(huán)境中拿到這個(gè)變量的值,因?yàn)檫@個(gè)變量未被初始化,它將拋出一個(gè)引用錯(cuò)誤。
在執(zhí)行期間,當(dāng)引擎到達(dá)了變量聲明的行,它將試圖執(zhí)行它的綁定,因?yàn)樵撟兞繘](méi)有與之關(guān)聯(lián)的值,因此它將為其賦值為unedfined
// 執(zhí)行階段 lexicalEnviroment = { a: undefined }
之后,undefined將會(huì)被打印到控制臺(tái),然后將值5賦值給變量a,lexical enviroment中變量a的值也會(huì)從undefined更新為5
functionn foo() { console.log(a) } let a = 20; foo();
function foo() { console.log(a): // ReferenceError: a is not defined } foo(); let a = 20;
Class Declaration
就像let和const聲明一樣,class在JavaScript中也會(huì)被提升,并且和let,const一樣,知道執(zhí)行之前,它們都會(huì)保持uninitialized。因此它們同樣會(huì)受到Temporal Deal Zone(時(shí)間死區(qū))的影響。例如
let peter = new Person('Peter', 25); // ReferenceError: Person is not defined console.log(peter); class Person { constructor(name, age) { this.name = name; this.age = age; } }
因此要訪(fǎng)問(wèn)class,必須先聲明它
class Person { constructor(name, age) { this.name = name; this.age = age; } } let peter = new Person('Peter', 25); console.log(peter); // Person { name: 'Peter', age: 25 }
所以在編譯階段,上面代碼的lexical environment(詞法環(huán)境)將如下所示:
lexicalEnvironment = { Person:}
當(dāng)引擎執(zhí)行class聲明時(shí),它將使用值初始化類(lèi)。
lexicalEnvironment = { Person:}
提升Class Expressions
let peter = new Person('Peter', 25); console.log(peter); let Person = class { constructor(name, age) { this.name = name; this.age = age; } }
let peter = new Person('Peter', 25); console.log(peter); var Person = class { constructor(name, age) { this.name = name; this.age = age; } }
所以現(xiàn)在我們知道在提升過(guò)程中我們的代碼并沒(méi)有被JavaScript引擎實(shí)際移動(dòng)。正確理解提升機(jī)制將有助于避免因變量提升而產(chǎn)生的任何未來(lái)錯(cuò)誤和混亂。為了避免像未定義的變量或引用錯(cuò)誤一樣可能產(chǎn)生的副作用,請(qǐng)始終嘗試將變量聲明在各自作用域的頂部,并始終嘗試在聲明變量時(shí)初始化變量。
Hoisting in Modern JavaScript — let, const, and var
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)創(chuàng)新互聯(lián)的支持。