首頁 > 軟體

深入瞭解JavaScript中let/var/function的變數提升

2022-07-25 10:01:11

前言

在我們的印象中,當提到JavaScript中的變數提升,我們想到的是“變數和函數的宣告在物理層面移動到程式碼的最前面“。當然這麼說不大準確,變數和函數宣告在程式碼裡的位置是不會變的,而是在編譯階段被放入記憶體中。

可是如果我問你:let 到底有沒有提升?如果有,var / let / function三者的變數提升一致嗎?此時你的答案是什麼?

接下來讓我們來探討這兩個問題,如有錯誤敬請指正。

1. let存在提升

對於let是否存在提升這個問題,讓我們先來看以下這段程式碼:

a = "global";
(function() {
    console.log(a); // undefined, 而不是列印出global
    var a;
}());

{
    console.log(a); // Uncaught ReferenceError: Cannot access 'a' before initialization
    let a = 1;
}

對於在函數作用域下列印出undefined,我們應該不奇怪。但引起我注意的是在塊作用域下,丟擲參照錯誤的原因是在初始化之前找不到a。那有沒有可能a建立過程被提升?而在我發現ES檔案中存在[var/let hoisting],這讓我有理由猜測let存在提升,只是由於暫時性死區的原因,我們不能在let a之前使用 a

為了證明我的猜想,我想先從let宣告的建立、初始化和賦值過程入手。

{
  let a = 0;
  a = 1;
}

上述的程式碼塊中發生的過程如下:

  • 找到所有用let宣告的變數,在環境建立變數;
  • 執行程式碼;
  • 執行a=0,將a初始化為1;
  • 執行a=1,對a進行賦值。

由該過程可知,如果我們在建立完變數後和初始化之前執行log()方法,控制檯將會報錯:

let a = 'global'
{
  console.log(a) // Uncaught ReferenceError: Cannot access 'a' before initialization
  let a = 1
}

由此一來我們就可以知道了let在建立的過程被提升,而在初始化過程沒有被提升。

2. var/function的變數提升

接下來我們來看看function/var的建立、初始化和賦值過程,由此看看能否探究出它們的差別。

2.1 var的變數提升

function foo() {
  console.log(a);  // undefined
  var a = 0;
  var b = 1;
}
foo();

當我們執行foo()時,發生以下過程(較為省略):

  • foo建立環境;
  • 找到foo中所有被var宣告的變數,在這個環境中建立變數;
  • 將變數初始化為 undefined;
  • 執行程式碼;
  • a賦值為0,b賦值為1。

由此我們可以知道var宣告在程式碼執行前建立變數並初始化,所以當我們在var a = 0之前執行log(a)方法會得到 undefined 的結果。

2.2 function的變數提升

foo('btqf');

function foo(name) {
  console.log("my name is" + name)  // my name is btqf
}

當我們執行foo函數時,發生以下過程:

  • 找到所有function宣告的變數,在環境中建立變數;
  • 將這些變數初始化並賦值;
  • 執行程式碼。

由此可見,function宣告在程式碼執行前就建立、初始化並賦值。

3. 總結

  • let 的「建立」過程被提升了,但是初始化沒有提升。
  • var 的「建立」和「初始化」都被提升了。
  • function 的「建立」「初始化」和「賦值」都被提升了。
  • 函數和變數相比,會被優先提升,即函數會被提升到更靠前的位置。

值得一提的是constlet基本類似,唯一的區別在於const只有建立和初始化,沒有賦值過程。

到此這篇關於深入瞭解JavaScript中let/var/function的變數提升的文章就介紹到這了,更多相關let/var/function變數提升內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com