深入瞭解JavaScript中let/var/function的變量提升
前言
在我們的印象中,當提到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
的「創建」「初始化」和「賦值」都被提升瞭。- 函數和變量相比,會被優先提升,即函數會被提升到更靠前的位置。
值得一提的是const
與let
基本類似,唯一的區別在於const
隻有創建和初始化,沒有賦值過程。
到此這篇關於深入瞭解JavaScript中let/var/function的變量提升的文章就介紹到這瞭,更多相關let/var/function變量提升內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- javascript的var與let,const之間的區別詳解
- 簡單談談JavaScript變量提升
- 基於JavaScript ES新特性let與const關鍵字
- js作用域及作用域鏈工作引擎
- JavaScript進階知識點作用域詳解