国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JS變量生命周期:為什么 let 沒有被提升

hoohack / 2138人閱讀

摘要:請注意,就變量生命周期而言,聲明階段與變量聲明是不同的概念。提升在生命周期中無效的原因如上所述,提升是變量在作用域頂部的耦合聲明和初始化階段。然而,生命周期分離聲明和初始化階段。解耦消除了的提升期限。

為了保證的可讀性,本文采用意譯而非直譯。

提升是將變量或函數定義移動到作用域頭部的過程,通常是 var 聲明的變量和函數聲明function fun() {...}

當 ES6 引入let(以及與let類似聲明的constclass)聲明時,許多開發人員都使用提升定義來描述如何訪問變量。但是在對這個問題進行了更多的探討之后,令我驚訝的是提升并不是描述let變量的初始化和可用性的正確術語。

ES6 為let提供了一個不同的和改進的機制。它要求更嚴格的變量聲明,在定義之前不能使用,從而提高代碼質量。

想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你!

1. 容易出錯的 var 提升

有時候我們會在zuo內作用域內看到一個奇怪的變量var varname和函數函數function funName() {...} 聲明:

// var hoisting
num;     // => undefined
var num;
num = 10;
num;     // => 10
// function hoisting
getPi;   // => function getPi() {...}
getPi(); // => 3.14
function getPi() {
  return 3.14;
}

變量num在聲明var num之前被訪問,因此它被賦值為undefinedfucntion getPi(){…}在文件末尾定義。但是,可以在聲明getPi()之前調用該函數,因為它被提升到作用域的頂部。

事實證明,先使用然后聲明變量或函數的可能性會造成混淆。假設您滾動一個大文件,突然看到一個未聲明的變量,它到底是如何出現在這里的,以及它在哪里定義的?

當然,一個熟練的JavaScript開發人員不會這樣編寫代碼。但是在成千上萬的JavaScript中,GitHub repos是很有可能處理這樣的代碼的。

即使查看上面給出的代碼示例,也很難理解代碼中的聲明流。

當然,首先要聲明再使用。let 鼓勵咱們使用這種方法處理變量。

2. 理解背后原理:變量生命周期

當引擎處理變量時,它們的生命周期由以下階段組成:

聲明階段(Declaration phase)是在作用域中注冊一個變量。

初始化階段(Initialization phase)是分配內存并為作用域中的變量創建綁定。 在此步驟中,變量將使用undefined自動初始化。

賦值階段(Assignment phase)是為初始化的變量賦值。

變量在通過聲明階段時尚未初始化狀態,但未達到初始化狀態。

請注意,就變量生命周期而言,聲明階段與變量聲明是不同的概念。 簡而言之,JS引擎在3個階段處理變量聲明:聲明階段,初始化階段和賦值階段。

3.var 變量的生命周期

熟悉生命周期階段之后,讓我們使用它們來描述JS引擎如何處理var變量。

假設JS遇到一個函數作用域,其中包含var變量語句。變量在執行任何語句之前通過聲明階段,并立即通過作用域開始處的初始化階段(步驟1)。函數作用域中var變量語句的位置不影響聲明和初始化階段。

在聲明和初始化之后,但在賦值階段之前,變量具有undefined 的值,并且已經可以使用。

在賦值階段variable = "value" 時,變量接收它的初值(步驟2)。

嚴格意義的提升是指在函數作用域的開始處聲明并初始化一個變量。聲明階段和初始化階段之間沒有差別。

讓我們來研究一個例子。下面的代碼創建了一個包含var語句的函數作用域

function multiplyByTen(number) {
  console.log(ten); // => undefined
  var ten;
  ten = 10;
  console.log(ten); // => 10
  return number * ten;
}
multiplyByTen(4); // => 40

開始執行multipleByTen(4)并進入函數作用域時,變量ten在第一個語句之前通過聲明和初始化步驟。因此,當調用console.log(ten)時,打印undefined。語句ten = 10指定一個初值。賦值之后,console.log(ten) 將正確地打印10

4. 函數聲明生命周期

在函數聲明語句function funName() {...}的情況下,它比變量聲明生命周期更簡單。

聲明、初始化和賦值階段同時發生在封閉函數作用域的開頭(只有一步)。可以在作用域的任何位置調用funName(),而不依賴于聲明語句的位置(甚至可以在末尾調用)。

下面的代碼示例演示了函數提升:

function sumArray(array) {
  return array.reduce(sum);
  function sum(a, b) {
    return a + b;
  }
}
sumArray([5, 10, 8]); // => 23

當執行sumArray([5,10,8])時,它進入sumArray函數作用域。在這個作用域內,在任何語句執行之前,sum都會通過所有三個階段:聲明、初始化和賦值。這樣,array.reduce(sum)甚至可以在它的聲明語句sum(a, b){…}之前使用sum

5. let 變量的生命周期

let 變量的處理方式與var不同,主要區別在于聲明和初始化階段是分開的

現在來看看一個場景,當解釋器進入一個包含let變量語句的塊作用域時。變量立即通過聲明階段,在作用域中注冊其名稱(步驟1)。

然后解釋器繼續逐行解析塊語句。

如果在此階段嘗試訪問變量,JS 將拋出 ReferenceError: variable is not defined。這是因為變量狀態未初始化,變量位于暫時死區 temporal dead zone

當解釋器執行到語句let variable時,傳遞初始化階段(步驟2)。變量退出暫時死區。

接著,當賦值語句variable = "value"出現時,將傳遞賦值階段(步驟3)。

如果JS 遇到let variable = "value",那么初始化和賦值將在一條語句中發生。

讓我們看一個例子,在塊作用域中用 let 聲明變量 number

let condition = true;
if (condition) {
  // console.log(number); // => Throws ReferenceError
  let number;
  console.log(number); // => undefined
  number = 5;
  console.log(number); // => 5
}

當 JS 進入if (condition) {...} 塊作用域,number立即通過聲明階段。

由于number已經處于單一化狀態,并且處于的暫時死區,因此訪問該變量將引發ReferenceError: number is not defined。接著,語句let number進行初始化。現在可以訪問變量,但是它的值是undefined

constclass 類型與let具有相同的生命周期,只是分配只能發生一次。

5.1 提升在let生命周期中無效的原因

如上所述,提升是變量在作用域頂部的耦合聲明和初始化階段。然而,let生命周期分離聲明和初始化階段。解耦消除了let的提升期限。

這兩個階段之間的間隙產生了暫時死區,在這里變量不能被訪問。

總結

使用var聲明變量很容易出錯。在此基礎上,ES6 引入了let。它使用一種改進的算法來聲明變量,并附加了塊作用域。

由于聲明和初始化階段是解耦的,提升對于let變量(包括constclass)無效。在初始化之前,變量處于暫時死區,不能訪問。

為了保持變量聲明的流暢性,建議使用以下技巧

聲明、初始化然后使用變量,這個流程是正確的,易于遵循。

盡量隱藏變量。公開的變量越少,代碼就越模塊化。

番外 如何理解 let x = x 報錯之后,再次 let x 依然會報錯?

這個問題說明:如果 let x 的初始化過程失敗了,那么

x 變量就將永遠處于 created 狀態。

你無法再次對 x 進行初始化(初始化只有一次機會,而那次機會你失敗了)。

由于 x 無法被初始化,所以 x 永遠處在暫時死區

有人會覺得 JS 坑,怎么能出現這種情況;其實問題不大,因為此時代碼已經報錯了,后面的代碼想執行也沒機會。

參考:

我用了兩個月的時間才理解 let

交流

干貨系列文章匯總如下,覺得不錯點個Star,歡迎 加群 互相學習。

https://github.com/qq44924588...

我是小智,公眾號「大遷世界」作者,對前端技術保持學習愛好者。我會經常分享自己所學所看的干貨,在進階的路上,共勉!

關注公眾號,后臺回復福利,即可看到福利,你懂的。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105731.html

相關文章

  • JS變量生命周期:什么 let 沒有提升

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

    Steven 評論0 收藏0
  • ES6 變量作用域與提升變量生命周期詳解

    摘要:不同的是函數體并不會再被提升至函數作用域頭部,而僅會被提升到塊級作用域頭部避免全局變量在計算機編程中,全局變量指的是在所有作用域中都能訪問的變量。 ES6 變量作用域與提升:變量的生命周期詳解從屬于筆者的現代 JavaScript 開發:語法基礎與實踐技巧系列文章。本文詳細討論了 JavaScript 中作用域、執行上下文、不同作用域下變量提升與函數提升的表現、頂層對象以及如何避免創建...

    lmxdawn 評論0 收藏0
  • JavaScript 變量提升

    摘要:生命周期假設這樣一個場景當解釋器剛進入一個包含的作用域時,則在任何語句執行之前,變量就已完成了聲明階段和初始化階段,且值為。當解釋器執行完,變量就已完成了初始化階段,離開了臨時死區,并具有的值。 變量提升是一個將變量聲明或者函數聲明提升到作用域起始處的過程。在本篇博文中,我們一起深入了解這個過程的更多細節。 變量的生命周期 當引擎使用變量時,它們的生命周期包含以下階段: 聲明階段,...

    li21 評論0 收藏0
  • 譯:用let 和 const 來指導JavaScript 的變量提升

    摘要:最近在上看到一篇關于變量提升的文章,原文在此。對于剛入門的開發者時常難以理解變量方法提升的獨特行為。接下來我們要談論,,聲明,那么先了解變量提升就顯得更為重要了。在進入作用域和不能訪問的這段時間,我們稱為暫時性死區。 showImg(https://segmentfault.com/img/bV0Nsd?w=800&h=450); 最近在Medium上看到一篇關于變量提升的文章,原文在...

    sanyang 評論0 收藏0
  • 高級前端面試題大匯總(只有試題,沒有答案)

    摘要:面試題來源于網絡,看一下高級前端的面試題,可以知道自己和高級前端的差距。 面試題來源于網絡,看一下高級前端的面試題,可以知道自己和高級前端的差距。有些面試題會重復。 使用過的koa2中間件 koa-body原理 介紹自己寫過的中間件 有沒有涉及到Cluster 介紹pm2 master掛了的話pm2怎么處理 如何和MySQL進行通信 React聲明周期及自己的理解 如何...

    kviccn 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<