成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

溫故而知新:JS 變量提升與時(shí)間死區(qū)

codecraft / 2036人閱讀

摘要:這意味著引擎在源代碼中聲明它的位置計(jì)算其值之前,你無法訪問該變量。因此它們同樣會(huì)受到時(shí)間死區(qū)的影響。正確理解提升機(jī)制將有助于避免因變量提升而產(chǎn)生的任何未來錯(cuò)誤和混亂。

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

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

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

執(zhí)行階段:給變量x賦值,首先詢問內(nèi)存你這有變量x嗎,如果有,則給變量x賦值,如果沒有則創(chuàng)建變量x并且給它賦值。

變量提升

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

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

LexicalEnviroment = {
  Identifier: ,
  Indentifier: 
}

簡(jiǎn)而言之,Lexical enviroment就是程序執(zhí)行過程中變量和函數(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值初始化,但是letconst聲明的值仍然未被初始化。

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

如果JavaScript引擎仍然無法在聲明它們的行中找到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看起來像下面這樣。

// 編譯階段
lexicalEnvironment = {
  a: 
}

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

在執(zhí)行期間,當(dāng)引擎到達(dá)了變量聲明的行,它將試圖執(zhí)行它的綁定,因?yàn)樵撟兞繘]有與之關(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

就像letconst聲明一樣,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;
  }
}

因此要訪問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í),它將使用值初始化類。

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

Hoisting in Modern JavaScript?—?let, const, and var

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/108879.html

相關(guān)文章

  • 理解ES6中的暫時(shí)死區(qū)(TDZ)

    摘要:以英文名詞來說明,是時(shí)間的暫時(shí)的意義,則是死區(qū),意指電波達(dá)不到的區(qū)域。所以可以翻為時(shí)間上暫時(shí)的無法達(dá)到的區(qū)域,簡(jiǎn)稱為時(shí)間死區(qū)或暫時(shí)死區(qū)。以聲明的變量或常量,必需是經(jīng)過對(duì)聲明的賦值語句的求值后,才算初始化完成,創(chuàng)建時(shí)并不算初始化。 Temporal Dead Zone(TDZ)是ES6(ES2015)中對(duì)作用域新的專用語義。TDZ名詞并沒有明確地寫在ES6的標(biāo)準(zhǔn)文件中,一開始是出現(xiàn)在ES...

    Mike617 評(píng)論0 收藏0
  • 深入理解let和var的區(qū)別(暫時(shí)性死區(qū))?。?!

    摘要:會(huì)出現(xiàn)這樣的情況是因?yàn)閾碛袝簳r(shí)性死區(qū)。規(guī)定暫時(shí)性死區(qū)和語句不出現(xiàn)變量提升,主要是為了減少運(yùn)行時(shí)錯(cuò)誤,防止在變量聲明前就使用這個(gè)變量,從而導(dǎo)致意料之外的行為。 首先我們應(yīng)該知道js引擎在讀取js代碼時(shí)會(huì)進(jìn)行兩個(gè)步驟: 第一個(gè)步驟是解釋。 第二個(gè)步驟是執(zhí)行。 所謂解釋就是會(huì)先通篇掃描所有的Js代碼,然后把所有聲明提升到頂端,第二步是執(zhí)行,執(zhí)行就是操作一類的。 我們先來看個(gè)簡(jiǎn)單的變量提升...

    tanglijun 評(píng)論0 收藏0
  • JS變量生命周期:為什么 let 沒有被提升

    摘要:請(qǐng)注意,就變量生命周期而言,聲明階段與變量聲明是不同的概念。提升在生命周期中無效的原因如上所述,提升是變量在作用域頂部的耦合聲明和初始化階段。然而,生命周期分離聲明和初始化階段。解耦消除了的提升期限。 為了保證的可讀性,本文采用意譯而非直譯。 提升是將變量或函數(shù)定義移動(dòng)到作用域頭部的過程,通常是 var 聲明的變量和函數(shù)聲明function fun() {...}。 當(dāng) ES6 引入l...

    hoohack 評(píng)論0 收藏0
  • JS變量生命周期:為什么 let 沒有被提升

    摘要:請(qǐng)注意,就變量生命周期而言,聲明階段與變量聲明是不同的概念。提升在生命周期中無效的原因如上所述,提升是變量在作用域頂部的耦合聲明和初始化階段。然而,生命周期分離聲明和初始化階段。解耦消除了的提升期限。 為了保證的可讀性,本文采用意譯而非直譯。 提升是將變量或函數(shù)定義移動(dòng)到作用域頭部的過程,通常是 var 聲明的變量和函數(shù)聲明function fun() {...}。 當(dāng) ES6 引入l...

    Steven 評(píng)論0 收藏0
  • JavaScript中函數(shù)紀(jì)要(一)

    摘要:中函數(shù)是一等公民,所有的函數(shù)實(shí)際上是一個(gè)對(duì)象,與其他引用類型一樣擁有著屬性和方法,也可以被外界或者自身調(diào)用,也可以像傳遞參數(shù)一樣將函數(shù)傳遞給另一個(gè)函數(shù)。中函數(shù)沒有重載的概念,當(dāng)定義兩個(gè)同名函數(shù)的時(shí)候,前一個(gè)函數(shù)會(huì)被覆蓋掉,舉個(gè)栗子。 JavaScript中函數(shù)是一等公民,所有的函數(shù)實(shí)際上是一個(gè)Function對(duì)象,與其他引用類型一樣擁有著屬性和方法,也可以被外界或者自身調(diào)用,也可以像傳...

    plus2047 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<