let、var、const聲明的區別


前言

看了方應杭老師的一篇解釋let的文章,對JavaScript中的聲明有了深刻的理解,這里也就有了總結一下JavaScript中各種聲明之間區別的這篇文章。

JavaScript中變量聲明機制

首先,我對JavaScript中所有聲明都存在提升這個觀點是認同的!

平時大家所講的變量的聲明,在JavaScript中一般是存在創建create初始化initialize賦值assign三個過程的,其中函數聲明也是一樣有這三個過程的。在這三個過程中:

創建:即在變量所在作用於頭部拋出變量,僅僅是拋出,是不能被使用的;
初始化:在變量初始化之前變量是不能被使用的,初始化只有一次,初始化之后變量可以使用;
賦值:即覆蓋初始化的值

在let、var、const(包括函數聲明)的聲明過程中,他們的創建create初始化initialize賦值assign是有區別的。

let

let是ECMAScript2015(ES6)中新增的變量聲明方式,let語句可以聲明一個塊級作用域的變量。

在同一個函數或同一個作用域中用let重復定義一個變量將引起 TypeError

if (true) {
  let foo;
  let foo; // TypeError thrown.
}

在let語句中,創建create初始化initialize賦值assign的過程如下:

if (true) {
  let foo
  console.log(foo) //undefined
  foo = 'str'
  console.log(foo)  //"str"
}

通過上面代碼可以看出let語句是如下過程的:

第一步:在塊級作用域中,找到let語句並聲明提升,創建foo變量,但是在初始化之前使用是會報錯的(如下面代碼);
第二步:執行let foo,let語句使得foo變量被初始化,初始化的過程是可選的,可以let foo初始化foo為undefined,也可以let foo = 123初始化foo為123.初始化之后變量可以使用;
第三步:執行foo = 'str',foo變量可以被賦值語句覆蓋

if (true) {
  console.log(foo) //Uncaught ReferenceError: foo is not defined
  let foo;
}

所以說,let聲明中在初始化之前是存在“暫時性死區”的。

還有值得注意的是,初始化只能一次,如果變量初始化失敗,則會存在一個該變量既不能賦值又不能使用的BUG,如下圖:

因為let foo = foo導致初始化失敗,所以導致了foo所在作用域都是foo變量只創建而未被初始化,所以foo所在作用域都會是foo變量的“暫時性死區”

var

var聲明是函數作用域。
眾所周知,var聲明是有變量提升的,有了上文的let聲明的理解,也就對var理解起來更加輕松了。

(function() {
  console.log(f) //undefined
  var f = 'str' //
  console.log(f) //"str"
}())

var聲明的過程:

第一步:在函數作用域中,找到var語句,f變量得到聲明提升到作用域頂部,創建f變量並初始化為undefined,在賦值之前f的值就是undefined;
第二步:執行f = 'str',f變量被賦值為'str'

所以,在執行var f = 'str' 之前,打印的f的值為undefined

const

const聲明創建了一個常量
const和let比較像,也是塊級作用域,區別就是,const在定義的時候必須初始化,而且不能被賦值

如上圖,const在定義時必須初始化,否則會報錯Uncaught SyntaxError: Missing initializer in const declaration;const是常量,聲明之后不能再次賦值,否則會報錯Uncaught TypeError: Assignment to constant variable

函數聲明

函數聲明在JavaScript存在變量提升,這也被眾多開發者做開發所常用。

fn()
function fn(){
  console.log(this)
}

函數聲明的過程:

第一步:在作用域中,找到function語句,將fn函數聲明提升到作用域頂部,創建fn函數,初始化並賦值為function fn(){console.log(this)}
第二步:執行fn()

即函數聲明是在找到function語句后,作用域頂部創建、初始化和賦值一步到位的

總結

MDN關於let講解中,說let沒有聲明,也許是考慮到更容易被開發者接受和理解吧,但是我認為JavaScript中所有聲明都存在提升是正確的。

最后用一個表格總結一下let、var、const聲明的區別吧

--- let var const
變量or常量 變量 變量 常量
作用域 塊級作用域 函數作用域 塊級作用域
創建 作用域頂部創建 作用域頂部創建 作用域頂部創建
初始化 let語句 作用域頂部 const語句
賦值 可以賦值 可以賦值 報錯
重復聲明 報錯 可以重復聲明 報錯
暫時性死區 沒有

本文首發在個人博客yoowin.me,歡迎訪問。


免責聲明!

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



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