JS變量聲明提升


首先來看一段代碼

console.log(a)
var a = 2;
輸出結果是undefined,正常來說JS如果是逐行向下執行,那么應該輸出未定義,為何此處輸出undefined呢?

原因在於JS在執行前都會進行編譯(通常就在執行前),在編譯過程中包括變量和函數在內的所有聲明都會被處理。

定義

是指在 JavaScript 代碼執行前的編譯過程中,JavaScript 引擎把變量的聲明部分和函數的聲明部分提升到代碼開頭的“行為”。變量被提升后,會給變量設置默認undefined。

那let,const是否會進行變量聲明提升呢?

首先我們要知道定義一個JS變量分為三個階段

  • 創建create
  • 初始化initialize
  • 賦值assign

下面我們分別來看看var、let、function 和 const的過程

var聲明

function fn() {
  var x = 1;
}
fn();
  • 進入 fn,為 fn 創建一個環境。
  • 找到 fn 中所有用 var 聲明的變量,在這個環境中「創建」這些變量(即 x 和 y)。
  • 將這些變量「初始化」為 undefined。
  • 開始執行代碼
  • x = 1 將 x 變量「賦值」為 1

 由以上步驟可知,var 聲明會在代碼執行之前就將創建變量,並將其初始化為 undefined。即創建和初始化會被提升

function聲明

fn();
function fn() {
  console.log(1);
}
  • 找到所有用 function 聲明的變量,在環境中「創建」這些變量。
  • 將這些變量「初始化」並「賦值」為 function(){ console.log(1) }。
  • 開始執行代碼 fn2()

由以上步驟可知,function 的「創建」「初始化」和「賦值」都被提升了

let聲明

{
  let x = 1;
  x = 2;
}
  • 找到所有用 let 聲明的變量,在環境中創建這些變量
  • 開始執行代碼(注意現在還沒有初始化)
  • 執行 x = 1,將 x 初始化為 1(這並不是一次賦值,如果代碼是 let x,就將 x 初始化為 undefined)
  • 執行 x = 2,對 x 進行賦值

由以上步驟可知,let只有創建過程會提升,初始化和賦值都不會提升,所以會形成暫時性死區,這也是為什么在定義前使用let會拋錯。

暫時性死區,就是不能在初始化之前,使用變量

const聲明

{
    console.log(x);
  const x = 1;
}
  • 找到所有用 const聲明的變量,在環境中「創建」這些變量
  • 開始執行代碼(注意現在還沒有初始化)
  • 執行x = 1, 將x初始化為1

由以上步驟可知,const的創建過程也會提升,但是與let不同之處在於const只有創建和初始化兩個過程,沒有賦值過程。若不初始化則會直接拋錯

總結

  • var 的創建初始化都被提升了。
  • function 的創建、初始化賦值都被提升了。
  • let 的創建被提升了,但是初始化和賦值沒有提升。
  • const的創建被提升但是初始化沒提升。const沒有賦值。

注意⚠️

函數優先

何為函數優先,來看一下下面的代碼👇

foo();
var foo;
function foo() {
  console.log(1)
}

實際上輸出值會是1,因為當變量聲明和函數聲明同時存在時,函數聲明優先於變量聲明,即函數聲明會覆蓋變量聲明。原因在於函數的賦值過程也會提升。那有人可能有疑問,如果將var變成let呢?結果為foo不允許被重復聲明。

變量提升的存儲位置

執行上下文中存在一個變量環境的對象(Viriable Environment),該對象中保存了變量提升的內容。而let,const則存在詞法環境中。

瀏覽器原理與實踐

https://www.jianshu.com/p/0f49c88cf169


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM