var let const 的比較

使用

在 es6 出現(xiàn)之前, 我們通常使用 var 來(lái)申明一個(gè)變量:
var x = 'test'
es6 中新增加了 letconst , 他們的作用和 var 相同,用于申明一個(gè)變量:
let x = 'test'
const Pi = 3.1415926

對(duì)比

約束: const 、let 、var 約束依次變得松散:

var 對(duì)比 letconst :

//正常運(yùn)行
var name = 'js'
var name = 'py'
name       // py

//錯(cuò)誤
let name = 'js'
let name = 'py'  //Uncaught SyntaxError: Identifier 'name' has already been declared

const name = 'js'
const name = 'py' //Uncaught SyntaxError: Identifier 'name' has already been declared
結(jié)論1: var 申明的變量可以用 var 進(jìn)行重新申明, 而 letconst 則不行
//可以對(duì)變量重新賦值
let name = 'js'
name = 'py'
name // py

//無(wú)法對(duì)變量重新賦值
const name = 'js'
name = 'py'   //Uncaught TypeError: Assignment to constant variable

// 必須在申明變量的時(shí)候就給定一個(gè)值
const a  //Missing initializer in const declaration
結(jié)論2: const 必須在申明的時(shí)候就給變量初始化一個(gè)值,且該變量的值不能改動(dòng)

原因:const 實(shí)際上保證的,并不是變量的值不得改動(dòng),而是變量指向的那個(gè)內(nèi)存地址不得改動(dòng)。對(duì)于簡(jiǎn)單類型的數(shù)據(jù)(數(shù)值、字符串、布爾值),值就保存在變量指向的那個(gè)內(nèi)存地址,因此等同于常量。但對(duì)于復(fù)合類型的數(shù)據(jù)(主要是對(duì)象和數(shù)組),變量指向的內(nèi)存地址,保存的只是一個(gè)指針,const只能保證這個(gè)指針是固定的,至于它指向的數(shù)據(jù)結(jié)構(gòu)是不是可變的,就完全不能控制了

變量提升:

var 命令會(huì)發(fā)生”變量提升“現(xiàn)象,var 申明變量會(huì) 其申明語(yǔ)句會(huì)自動(dòng)提升到 當(dāng)前執(zhí)行環(huán)境最前面:

console.log(x) // undefined
var x = 0
console.log(x) // 0

//上面的的語(yǔ)句相當(dāng)于下面語(yǔ)句
var x
console.log(x) // undefined
x = 0
console.log(x) // 0

//let const 不會(huì)出現(xiàn)這種情況
console.log(y) // Uncaught ReferenceError: y is not defined
let y = 0

console.log(z) // Uncaught ReferenceError: z is not defined
const z = 0
結(jié)論3:var 存在變量提升現(xiàn)象, 而 const let 不存在

塊級(jí)作用域:

在 es6之前,ES5 只有全局作用域和函數(shù)作用域,沒(méi)有塊級(jí)作用域, 而let提供了塊級(jí)作用域:

var test1 = function() {
  var x = 2
  if(1){
    var x = 3
  }
  console.log(x) 
}
test1()  //3

let test2 = function() {
  let x = 2
  if(1){
    let x = 3
  }
  console.log(x) // 2
}
test2()  //2
結(jié)論4:let 會(huì)使得代碼塊擁有自己的作用域, 其內(nèi)部的變量申明不會(huì)干擾外部

關(guān)于塊級(jí)作用域,有一個(gè)常見(jiàn)的面試題:

//(1)再循環(huán)中 延時(shí)輸出數(shù)字
for (var i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i)  //會(huì)輸出5個(gè) 5
  }, 1000)
}


// (2)如果想要輸出0, 1, 2,3, 4 可以這樣寫(xiě):
for (var i = 0; i < 5; i++) {
  (function f1(k) {
    setTimeout(function(k) {
      console.log( k)
    }, 1000)
  })(i)
}



//(3)上面的方法是借用閉包形成一個(gè)新的作用域,我們已經(jīng)知道 _let_ 可以形成塊級(jí)作用域,所以我們可以使用_let_達(dá)到同樣的目的:
for (let i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i)
  }, 1000)
}
理解:
  1. 變量 i 由 var申明, 則循環(huán)每一次都是引用的同一個(gè)i, 所以 i 會(huì)變成 5 輸出 5個(gè) 5
  1. 這里每一次 的 i 被我們傳進(jìn) 一個(gè)立即執(zhí)行函數(shù), 立即執(zhí)行函數(shù)內(nèi)部有新的作用域, 每一次的k都是新的值, 而每一次的k 存儲(chǔ)了 每一次的 i, 所以輸出 0,1,2,3,4
  1. 變量i是let聲明的,當(dāng)前的i只在本輪循環(huán)有效,所以每一次循環(huán)的i其實(shí)都是一個(gè)新的變量,其中有一點(diǎn)是, javaScript 引擎內(nèi)部會(huì)記住上一輪循環(huán)的值,初始化本輪的變量i時(shí),就在上一輪循環(huán)的基礎(chǔ)上進(jìn)行計(jì)算。

對(duì)比總結(jié)

  • var 申明的變量可以用 var 進(jìn)行重新申明, 而 letconst 則不行
  • 結(jié)論2: const 必須在申明的時(shí)候就給變量初始化一個(gè)值,且該變量的值不能改動(dòng)
  • let 存在變量提升現(xiàn)象, 而 const let 不存在
  • let 會(huì)使得代碼塊擁有自己的作用域, 其內(nèi)部的變量申明不會(huì)干擾外部

應(yīng)用場(chǎng)景:

  • let 可以代替 var 的使用, 可以避免變量的意外重命名沖突
  • const 適用于你一次定義,不希望別人再進(jìn)行改動(dòng)的場(chǎng)景,比如config里面的 常值變量、工具函數(shù) 等等
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容