前言
ES6 (ECMAScript 6.0的簡(jiǎn)稱)僵朗,于2015年6月正式發(fā)布壤蚜,正式名稱是《ECMAScript 2015標(biāo)準(zhǔn)》(簡(jiǎn)稱ES2015)转绷。所以提到ES6的地方悼瓮,泛指的就是ES2015標(biāo)準(zhǔn)。
定義
let 和 const 是ES6新增加的兩個(gè)關(guān)鍵字艰猬。
let 聲明的變量只在 let 命令所在的代碼塊內(nèi)有效横堡。
const 聲明一個(gè)只讀的常量,一旦聲明冠桃,常量的值就不能改變命贴。
注:這里提到了另一個(gè)定義 代碼塊(塊級(jí)作用域 Block Scope),這也是ES6另一個(gè)重要的知識(shí)點(diǎn)食听,隨后我會(huì)整理一下塊級(jí)作用域的相關(guān)知識(shí)點(diǎn)胸蛛,再分享出來。
let 命令
let 在代碼塊內(nèi)有效
var a = 0
let b = 1
console.log(a) //輸出 0
console.log(b) //輸出 1
看起來沒什么區(qū)別樱报,但是在代碼塊內(nèi)葬项。
{
var a = 0
let b = 1
console.log(a) // 輸出 0
console.log(b) // 輸出 1
}
console.log(a) // 輸出 0
console.log(b) // 報(bào)錯(cuò) b is not defined
let 不能重復(fù)聲明
var 可以重復(fù)聲明一個(gè)變量 后聲明的變量會(huì)覆蓋之前的變量
var a = 0
var a = 1
而let則不能在同一作用域聲明相同的變量
let a = 0
let a = 1 //報(bào)錯(cuò) Identifier 'a' has already been declared
但let可以在不同作用域聲明同名稱的變量,但值不會(huì)受到影響,而var重復(fù)聲明則會(huì)被覆蓋
var a = 0
let b = 0
{
var a = 1
let b = 2
console.log(a) //輸出1
console.log(b) //輸出2
}
console.log(a) //輸出1 此時(shí) a 已經(jīng)被塊內(nèi)var a = 1 覆蓋
console.log(b) //輸出0 塊內(nèi)的let b = 2 在代碼塊執(zhí)行結(jié)束后被銷毀 不影響最初定義的 let b = 0
let 不存在變量提升
console.log(a) //輸入undefined
var a = 1
上面的代碼相當(dāng)于
var a
console.log(a) //輸入undefined
a = 1
var 定義變量是存在變量提升的
但let則會(huì)嚴(yán)格按照代碼順序執(zhí)行
console.log(a) // 報(bào)錯(cuò) a is not defined
let a = 1
暫時(shí)性死區(qū)
這個(gè)概念跟上面的變量提升有點(diǎn)類似迹蛤,但也有些許的不同民珍,舉個(gè)例子
var a = 0
{
console.log(a) // 報(bào)錯(cuò) a is not defined
let a = 1
}
雖然定義了全局變量,但在代碼塊內(nèi)部依舊報(bào)錯(cuò)盗飒。原因就是:
ES6明確規(guī)定了代碼塊內(nèi)如果存在let或const嚷量,代碼塊會(huì)對(duì)這些命令(let 或 const)聲明的變量從塊的開始就形成一個(gè)封閉的作用域。
所以代碼塊內(nèi)逆趣,在聲明變量a 之前使用它就會(huì)報(bào)錯(cuò)
其他
在 for 循環(huán)中 let的作用域清晰蝶溶,相對(duì)var 省去了很多煩惱
for (var i = 0; i < 10; i++) {
setTimeout(function(){
console.log(i);
})
}
// 輸出十個(gè) 10
for (let j = 0; j < 10; j++) {
setTimeout(function(){
console.log(j);
})
}
// 輸出 0123456789
變量 i 是用 var 聲明的,在全局范圍內(nèi)有效宣渗,所以全局中只有一個(gè)變量 i, 每次循環(huán)時(shí)抖所,setTimeout 定時(shí)器里面的 i 指的是全局變量 i ,而循環(huán)里的十個(gè) setTimeout 是在循環(huán)結(jié)束后才執(zhí)行落包,所以此時(shí)的 i 都是 10。
變量 j 是用 let 聲明的摊唇,當(dāng)前的 i 只在本輪循環(huán)中有效咐蝇,每次循環(huán)的 j 其實(shí)都是一個(gè)新的變量,所以 setTimeout 定時(shí)器里面的 j 其實(shí)是不同的變量巷查,即最后輸出0123...有序。(若每次循環(huán)的變量 j 都是重新聲明的,如何知道前一個(gè)循環(huán)的值岛请?這是因?yàn)?JavaScript 引擎內(nèi)部會(huì)記住前一個(gè)循環(huán)的值)旭寿。
const 命令
const 聲明的是一個(gè)只讀變量或常量,聲明之后不允許改變崇败。這就表示盅称,一旦聲明必須初始化肩祥,否則會(huì)報(bào)錯(cuò)。
const a = 0 // 必須初始化
const b //未初始化報(bào)錯(cuò) Uncaught SyntaxError: Missing initializer in const declaration
對(duì)于 作用域缩膝,變量提升混狠,暫時(shí)性死區(qū),重復(fù)聲明等定義疾层,const與let是相同的
但是
對(duì)于const定義數(shù)組和對(duì)象的情況要特殊理解将饺。
這里就要理解 傳值 和 傳址 兩種賦值方式,
簡(jiǎn)單理解:
簡(jiǎn)單類型(數(shù)值number , 字符串string , 布爾類型boolean)賦值是傳值方式
復(fù)雜類型(對(duì)象object痛黎,數(shù)組array予弧,函數(shù)function)賦值是傳址方式
var a = 0
const b = a
let c = a
a = 1
console.log(b) // 輸出 0
console.log(c) // 輸出 0
上面 const b = a 的時(shí)候是將 0這個(gè)值傳給b,所以當(dāng)a變化的時(shí)候湖饱,b不發(fā)生變化掖蛤。這里加了一個(gè) c 的目的是為了證明 b 不變因?yàn)閭髦捣绞剑皇且驗(yàn)閏onst 定義的常量琉历。
繼續(xù)看
var obj = {
a: 1,
b: 2
}
const obj1 = obj //這里傳遞的是 {a:1,b:2} 的地址
obj.a = 3
obj1.b = 4
console.log(obj1) // 輸出 {a: 3, b: 4}
obj = {
c: 1,
d: 2
}
//obj1 = obj // 這里會(huì)報(bào)錯(cuò) Uncaught TypeError: Assignment to constant variable.
console.log(obj) // 輸出 {c: 1, d: 2}
console.log(obj1) // 輸出 {a: 3, b: 4}
所以const保證指針是固定的坠七,至于指針指向的數(shù)據(jù)結(jié)構(gòu)是否發(fā)生變化就無法控制了。
這部分會(huì)有點(diǎn)繞旗笔,需要花時(shí)間理解一下彪置。
總結(jié)
- let 和 const 的作用域?yàn)楫?dāng)前代碼塊
- let 和 const 不能重復(fù)聲明
- ES6 暫時(shí)性死區(qū)的概念
- const 聲明常量,且聲明時(shí)必須初始化
- const 聲明復(fù)雜類型是需要謹(jǐn)慎使用