「JavaScript學習筆記」 JavaScript 中的變量聲明簡析

update:
2017-10-23 更新了文中一些表達以及添加了JS編譯部分的理解。
2018-06-06 這篇文章能更好的理解ES6的letconst理解ES6中的暫時死區(TDZ)


先前看到方方老師最新的文章《我用了兩個月的時間才理解 let》,以下是對該文章的學習結合自己理解總結的筆記。

由于自己對JavaScript的編譯和運行理解的不是非常深,文中對于JavaScript引擎的編譯部分的理解可能并不準確,如有問題歡迎提出!

var let function const聲明的過程

首先,需要明白,JavaScript在準備階段會由JavsScript引擎進行編譯的,編譯的過程包括進行詞法分析(詞法作用域)及代碼生成。當前面的準備完成后通常會立即執行代碼。
對于變量聲明來說,一般可以簡單的分為三個過程:

  1. create創建 (編譯)
  2. initialize初始化 (編譯)
  3. assign賦值 (執行代碼)

需要注意,初始化當中也可以進行賦值。

var

// 通過fn限定作用域
function fn(){
    console.log(x) // 結果為undefined
    var x = 1
    var y = 2
}
fn()

// 1. 找到fn作用域中所有var聲明的變量,create變量(x和y)
// 2. initialize變量x,y為undefined
// 3. 開始執行代碼 x = 1 ,將變量 x assign為 1
// 4. y = 2 將變量 y assign為 2

// 可以理解為下面的情況
var x
var y 
x = 1
y = 2

基本過程:
1.找到所有var,「創建」變量
2.「初始化」變量并賦值undefined
3.「執行代碼」,根據執行的代碼開始為變量「賦值」。
在這個過程中產生了一個像是聲明提升到作用域頂部的現象,因此會出現在var x = 1之前console.log(x)

ps:從文章中學習到,聲明提升其實并非是一個官方說法。

function

// 假設全局作用域下
fn2 ()
function fn2(){
    console.log(2)
}
// 1. 找到當前作用域中所有的function聲明的變量,為當前環境create這些變量(聲明fn2)。
// 2. 初始化這些變量(fn2)并賦值為 function(){ console.log(2) }
// 3. 執行代碼fn2()

基本過程:

  1. 會先找到所有function關鍵字的函數聲明進行「創建」
  2. 進行「初始化并賦值」的操作
  3. 「執行」代碼fn2(),因此產生了函數提升的過程
    需要注意的是,這里特指函數聲明。

let

function fn3(){
    let x = 1
    x = 2 
}
fn3()
// 1. fn3()作用域中找到所有的let聲明的變量并創建它
// 2. 開始執行代碼  (與var 不同,這里還沒初始化)
// 3. 執行x = 1 ,x 「初始化」為 1(這并不是一次賦值,如果代碼是 let x,就將 x 初始化為 undefined)
// 4. 執行 x = 2,為x進行賦值

根據這個區別,let的初始化是在執行代碼的過程中,而不是先初始化:

  1. 找到所有let「創建」變量。
  2. 開始「執行」代碼,使變量根據執行的代碼「初始化并賦值」,此時如果沒有賦值(比如:let x)則「初始化」為undefined
  3. 繼續執行代碼。

由于let的初始化和賦值操作是在代碼執行階段,所以對let聲明的變量的使用必須在聲明后,也就沒有出現聲明提升的現象。

const

function fn4(){
    const x = 1
    x = 3 // Uncaught TypeError: Assignment to constant variable.
}
fn4()
// 1. fn4的作用域中找到所有const聲明的變量,并創建它(創建x) 
// 2. 為變量初始化 (變量x 初始化為3)
// 3. 執行代碼x = 3 ,報錯

const和let 主要區別在于const聲明的變量無法賦值,同時const必須在執行初始化的時候賦值,否則會拋出錯誤Uncaught SyntaxError: Missing initializer in const declaration

letvar區別:

  1. var 的創建與初始化都提升了
  2. let 的創建提升了,但是初始化沒有提升
  3. function 的創建、初始化、賦值都被提升了

因此在let初始化之前使用其聲明的變量,就會出現變量沒有定義的錯誤:

function fn5(){
    console.log(x) // Uncaught ReferenceError: x is not defined
    let x = 1 
}
fn5()

小結

對于上面的結論,我們對JavaScript變量聲明做一些總結。

創建:在編譯階段通過詞法分析,對關鍵字(var,let,const,function)進行變量創建

表現為變量提升到作用域頂端進行創建

初始化:仍在編譯階段,不同關鍵字初始化方式不同,主要操作是為變量賦值:

var:創建后初始化為undefined
let:執行代碼階段進行初始化,如果沒有賦值則初始化為undefined
function:函數聲明表達式為var的形式提升到作用域頂端創建,并同時初始化,賦值為一個函數對象
const:創建后,執行代碼階段進行初始化,同時必須賦值

執行代碼階段

var:創建變量時已進行了第一次初始化
let:關鍵字后為第一次執行,第一次執行時才進行初始化,可以不賦值,不賦值則為初始化為undefined
function:
const:關鍵字后第一次執行代碼,必須賦值
  1. 所有變量聲明方式都會將變量提升到作用域頂端,并進行創建
  2. 初始化的表現使得變量聲明不同,產生了變量提升的現象

其他相關

參考文章和知乎上的知識,各瀏覽器在console上表現并不是一致的

image.png

比如上圖中的問題,在chrome的console中,有以下的情況:

  1. 當 let聲明變量x如果初始化失敗了,就會處于一種已創建的狀態
  2. 此時無法再次對x進行初始化,即初始化機會只有一次
  3. 此時x將處于暫時死區(temporal dead zone)
  4. 于是,此狀態下的x將是不可用的
    但是對于其他瀏覽器可能報錯信息將不一致,具體可以參照問題中賀老的回答。

參考:
https://zhuanlan.zhihu.com/p/28140450
https://www.zhihu.com/question/62966713

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,619評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,155評論 3 425
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,635評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,539評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,255評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,646評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,655評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,838評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,399評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,146評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,338評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,893評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,565評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,983評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,257評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,059評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,296評論 2 376

推薦閱讀更多精彩內容

  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,532評論 1 51
  • 基本內置類型 算術類型字符整型布爾值浮點數 空類型(void) 算術類型 帶符號類型和無符號類型int、short...
    2625K閱讀 3,249評論 0 1
  • 周未沒安排工作上的事!早上,剛結束八段錦,女兒起床主動要求去跑步。好開心!這也是她的進步!我們跑了半小時,她要學...
    真心愛禮閱讀 116評論 0 1
  • 目錄 上一章:見面一刻 文/余晃 我在老家沒什么朋友,因此不用訪友,也不走什么親戚,所以相當無聊。飯后就獨自在屋子...
    風味沙拉閱讀 248評論 0 0
  • 在一片茂密森林的邊緣,一位勤勞的農夫和他善良的妻子來到這里定居,過著平淡的生活。日出而作,日落而息。 不久,他們...
    亦橈閱讀 445評論 1 2