摘要:這意味著引擎在源代碼中聲明它的位置計算其值之前,你無法訪問該變量。因此它們同樣會受到時間死區的影響。正確理解提升機制將有助于避免因變量提升而產生的任何未來錯誤和混亂。
開始執行腳本時,執行腳本的第一步是編譯代碼,然后再開始執行代碼,如圖
另外,在編譯優化方面來說,最開始時也并不是全部編譯好腳本,而是當函數執行時,才會先編譯,再執行腳本,如圖
編譯階段:經歷了詞法分析,語法分析生成AST,以及代碼生成。并且在此階段,它只會掃描并且抽出環境中的聲明變量,聲明函數以便準備分配內存,所有的函數聲明和變量聲明都會被添加到名為Lexical Environment的JavaScript內部數據結構內的內存中。因此,它們可以在源代碼中實際聲明之前使用。但是,Javascript只會存儲函數聲明和變量聲明在內存,并不會存儲他們的值
執行階段:給變量x賦值,首先詢問內存你這有變量x嗎,如果有,則給變量x賦值,如果沒有則創建變量x并且給它賦值。
變量提升如下圖,左邊灰色塊區域,是演示函數執行前的編譯階段,先抽出所有聲明變量和聲明函數,并進行內存分配。然后再開始執行代碼,在執行第一行代碼的時候,若是變量a存在于內存中,則直接給變量a賦值。而執行到第二行時,變量b并沒有在內存中,則會創建變量b并給它賦值。
Lexical enviroment是一種包含標識符變量映射的數據結構
LexicalEnviroment = { Identifier:, Indentifier: }
簡而言之,Lexical enviroment就是程序執行過程中變量和函數存在的地方。
let,const變量console.log(a) let a = 3;
輸出
ReferenceError: a is not defined
所以let和const變量并不會被提升嗎?
這個答案會比較復雜。所有的聲明(function, var, let, const and class)在JavaScript中都會被提升,然而var聲明被undefined值初始化,但是let和const聲明的值仍然未被初始化。
它們僅僅只在Javascript引擎運行期間它們的詞法綁定被執行在才會被初始化。這意味著引擎在源代碼中聲明它的位置計算其值之前,你無法訪問該變量。這就是我們所說的時間死區,即變量創建和初始化之間的時間,我們無法訪問該變量。
如果JavaScript引擎仍然無法在聲明它們的行中找到let或者const的值,它將為它們分配undefined值或返回錯誤值(在const的情況下會返回錯誤值)。
6a9a50532bf60f5fac6b3c.png](evernotecid://F2BCA3B5-CC5A-4EB3-BD61-DD865800F342/appyinxiangcom/10369121/ENResource/p1163)
let a; console.log(a); // outputs undefined a = 5;
在編譯階段,JavaScript引擎遇到變量a并將它存儲在lexical enviroment,但是因為它是一個let變量,所以引擎不會為它初始化任何值。所以,在編譯階段,lexical enviroment看起來像下面這樣。
// 編譯階段 lexicalEnvironment = { a:}
現在如果我們嘗試在聲明它之前訪問該變量,JavaScript引擎將會嘗試從詞法環境中拿到這個變量的值,因為這個變量未被初始化,它將拋出一個引用錯誤。
在執行期間,當引擎到達了變量聲明的行,它將試圖執行它的綁定,因為該變量沒有與之關聯的值,因此它將為其賦值為unedfined
// 執行階段 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一樣,知道執行之前,它們都會保持uninitialized。因此它們同樣會受到Temporal Deal Zone(時間死區)的影響。例如
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; } }
因此要訪問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(詞法環境)將如下所示:
lexicalEnvironment = { Person:}
當引擎執行class聲明時,它將使用值初始化類。
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; } }
所以現在我們知道在提升過程中我們的代碼并沒有被JavaScript引擎實際移動。正確理解提升機制將有助于避免因變量提升而產生的任何未來錯誤和混亂。為了避免像未定義的變量或引用錯誤一樣可能產生的副作用,請始終嘗試將變量聲明在各自作用域的頂部,并始終嘗試在聲明變量時初始化變量。
Hoisting in Modern JavaScript?—?let, const, and var
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/108879.html
摘要:以英文名詞來說明,是時間的暫時的意義,則是死區,意指電波達不到的區域。所以可以翻為時間上暫時的無法達到的區域,簡稱為時間死區或暫時死區。以聲明的變量或常量,必需是經過對聲明的賦值語句的求值后,才算初始化完成,創建時并不算初始化。 Temporal Dead Zone(TDZ)是ES6(ES2015)中對作用域新的專用語義。TDZ名詞并沒有明確地寫在ES6的標準文件中,一開始是出現在ES...
摘要:會出現這樣的情況是因為擁有暫時性死區。規定暫時性死區和語句不出現變量提升,主要是為了減少運行時錯誤,防止在變量聲明前就使用這個變量,從而導致意料之外的行為。 首先我們應該知道js引擎在讀取js代碼時會進行兩個步驟: 第一個步驟是解釋。 第二個步驟是執行。 所謂解釋就是會先通篇掃描所有的Js代碼,然后把所有聲明提升到頂端,第二步是執行,執行就是操作一類的。 我們先來看個簡單的變量提升...
摘要:請注意,就變量生命周期而言,聲明階段與變量聲明是不同的概念。提升在生命周期中無效的原因如上所述,提升是變量在作用域頂部的耦合聲明和初始化階段。然而,生命周期分離聲明和初始化階段。解耦消除了的提升期限。 為了保證的可讀性,本文采用意譯而非直譯。 提升是將變量或函數定義移動到作用域頭部的過程,通常是 var 聲明的變量和函數聲明function fun() {...}。 當 ES6 引入l...
摘要:請注意,就變量生命周期而言,聲明階段與變量聲明是不同的概念。提升在生命周期中無效的原因如上所述,提升是變量在作用域頂部的耦合聲明和初始化階段。然而,生命周期分離聲明和初始化階段。解耦消除了的提升期限。 為了保證的可讀性,本文采用意譯而非直譯。 提升是將變量或函數定義移動到作用域頭部的過程,通常是 var 聲明的變量和函數聲明function fun() {...}。 當 ES6 引入l...
摘要:中函數是一等公民,所有的函數實際上是一個對象,與其他引用類型一樣擁有著屬性和方法,也可以被外界或者自身調用,也可以像傳遞參數一樣將函數傳遞給另一個函數。中函數沒有重載的概念,當定義兩個同名函數的時候,前一個函數會被覆蓋掉,舉個栗子。 JavaScript中函數是一等公民,所有的函數實際上是一個Function對象,與其他引用類型一樣擁有著屬性和方法,也可以被外界或者自身調用,也可以像傳...
閱讀 1114·2021-11-16 11:42
閱讀 2895·2021-10-12 10:18
閱讀 2853·2021-09-24 09:48
閱讀 3457·2019-08-30 15:56
閱讀 1522·2019-08-30 14:17
閱讀 3036·2019-08-29 12:14
閱讀 901·2019-08-27 10:51
閱讀 2020·2019-08-26 13:28