国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

JS溫故而知新之變量提升和時間死區(qū)

2019-11-19 12:13:30
字體:
供稿:網(wǎng)友

前言

開始執(zhí)行腳本時,執(zhí)行腳本的第一步是編譯代碼,然后再開始執(zhí)行代碼,如圖

另外,在編譯優(yōu)化方面來說,最開始時也并不是全部編譯好腳本,而是當(dāng)函數(shù)執(zhí)行時,才會先編譯,再執(zhí)行腳本,如圖

  • 編譯階段:經(jīng)歷了詞法分析,語法分析生成AST,以及代碼生成。并且在此階段,它只會掃描并且抽出環(huán)境中的聲明變量,聲明函數(shù)以便準(zhǔn)備分配內(nèi)存,所有的函數(shù)聲明和變量聲明都會被添加到名為Lexical Environment的JavaScript內(nèi)部數(shù)據(jù)結(jié)構(gòu)內(nèi)的內(nèi)存中。因此,它們可以在源代碼中實際聲明之前使用。但是,Javascript只會存儲函數(shù)聲明和變量聲明在內(nèi)存,并不會存儲他們的值
  • 執(zhí)行階段:給變量x賦值,首先詢問內(nèi)存你這有變量x嗎,如果有,則給變量x賦值,如果沒有則創(chuàng)建變量x并且給它賦值。

變量提升

如下圖,左邊灰色塊區(qū)域,是演示函數(shù)執(zhí)行前的編譯階段,先抽出所有聲明變量和聲明函數(shù),并進行內(nèi)存分配。然后再開始執(zhí)行代碼,在執(zhí)行第一行代碼的時候,若是變量a存在于內(nèi)存中,則直接給變量a賦值。而執(zhí)行到第二行時,變量b并沒有在內(nèi)存中,則會創(chuàng)建變量b并給它賦值。

Lexical enviroment是一種包含標(biāo)識符變量映射的數(shù)據(jù)結(jié)構(gòu)

LexicalEnviroment = { Identifier: <value>, Indentifier: <function object>}

簡而言之,Lexical enviroment就是程序執(zhí)行過程中變量和函數(shù)存在的地方。

let,const變量

console.log(a)let a = 3;

輸出

ReferenceError: a is not defined

所以let和const變量并不會被提升嗎?

這個答案會比較復(fù)雜。所有的聲明(function, var, let, const and class)在JavaScript中都會被提升,然而var聲明被undefined值初始化,但是let和const聲明的值仍然未被初始化。

它們僅僅只在Javascript引擎運行期間它們的詞法綁定被執(zhí)行在才會被初始化。這意味著引擎在源代碼中聲明它的位置計算其值之前,你無法訪問該變量。這就是我們所說的時間死區(qū),即變量創(chuàng)建和初始化之間的時間,我們無法訪問該變量。

如果JavaScript引擎仍然無法在聲明它們的行中找到let或者const的值,它將為它們分配undefined值或返回錯誤值(在const的情況下會返回錯誤值)。

6a9a50532bf60f5fac6b3c.png](evernotecid://F2BCA3B5-CC5A-4EB3-BD61-DD865800F342/appyinxiangcom/10369121/ENResource/p1163)

let a;console.log(a); // outputs undefineda = 5;

在編譯階段,JavaScript引擎遇到變量a并將它存儲在lexical enviroment,但是因為它是一個let變量,所以引擎不會為它初始化任何值。所以,在編譯階段,lexical enviroment看起來像下面這樣。

// 編譯階段lexicalEnvironment = { a: <uninitialized>}

現(xiàn)在如果我們嘗試在聲明它之前訪問該變量,JavaScript引擎將會嘗試從詞法環(huán)境中拿到這個變量的值,因為這個變量未被初始化,它將拋出一個引用錯誤。

在執(zhí)行期間,當(dāng)引擎到達了變量聲明的行,它將試圖執(zhí)行它的綁定,因為該變量沒有與之關(guān)聯(lián)的值,因此它將為其賦值為unedfined

// 執(zhí)行階段lexicalEnviroment = { a: undefined}

之后,undefined將會被打印到控制臺,然后將值5賦值給變量a,lexical enviroment中變量a的值也會從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中也會被提升,并且和let,const一樣,知道執(zhí)行之前,它們都會保持uninitialized。因此它們同樣會受到Temporal Deal Zone(時間死區(qū))的影響。例如

let peter = new Person('Peter', 25); // ReferenceError: Person is not definedconsole.log(peter);class Person { constructor(name, age) { this.name = name; this.age = age; }}

因此要訪問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: <uninitialized>}

當(dāng)引擎執(zhí)行class聲明時,它將使用值初始化類。

lexicalEnvironment = { Person: <Person object>}

提升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)在我們知道在提升過程中我們的代碼并沒有被JavaScript引擎實際移動。正確理解提升機制將有助于避免因變量提升而產(chǎn)生的任何未來錯誤和混亂。為了避免像未定義的變量或引用錯誤一樣可能產(chǎn)生的副作用,請始終嘗試將變量聲明在各自作用域的頂部,并始終嘗試在聲明變量時初始化變量。

Hoisting in Modern JavaScript ― let, const, and var

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對武林網(wǎng)的支持。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 独山县| 贵南县| 师宗县| 井冈山市| 尖扎县| 哈尔滨市| 黄浦区| 思茅市| 漠河县| 时尚| 河曲县| 柳林县| 巩留县| 万州区| 增城市| 邳州市| 白沙| 万宁市| 屏东县| 淮阳县| 阳城县| 北海市| 宁强县| 东乌珠穆沁旗| 开江县| 金昌市| 桐柏县| 连城县| 罗山县| 江源县| 榆社县| 富源县| 蛟河市| 宣汉县| 申扎县| 阿荣旗| 宁海县| 拜泉县| 铁岭市| 中西区| 合山市|