let命令
ES6新增了 let
命令瓶摆,用來聲明變量。它的用法類似于var
馍驯,當(dāng)然也只是類似阁危,說明它還有其他不同于var
的地方,那我們就來看下有哪些不同的地方汰瘫。
-
let
的聲明的變量只在塊級(jí)作用域內(nèi)有效
我們知道ES5只有全局作用域和函數(shù)作用域狂打,這會(huì)帶來行風(fēng)多不合理的場(chǎng)景,比如內(nèi)層變量可能會(huì)覆蓋外層變量:
var tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f(); // undefined
上面代碼的的原意是混弥,在f()
里打印外層作用域里的變量tmp
趴乡,條件語句里也是打算使用外層作用域里的變量tmp
,但是由于沒有塊級(jí)作用域蝗拿,f()
里的tmp
實(shí)際上是函數(shù)作用域內(nèi)if
代碼塊里變量提升的tmp
晾捏,所以打印的是undefined
。這時(shí)如果將var tmp = 'hello world';
里的var
換成let
就可以達(dá)到原來的目的:
從這里我們也可以看出
let
聲明與var
聲明的另一個(gè)不同之處
-
變量提升哀托?不存在的
我們知道通過var
聲明的變量惦辛,在作用域內(nèi)先于聲明語句之前對(duì)變量進(jìn)行使用而不會(huì)報(bào)錯(cuò)(值為undefined),這是因?yàn)樽兞刻嵘臋C(jī)制(JavaScript引擎在執(zhí)行一段代碼的時(shí)候仓手,會(huì)把所有變量的聲明都提升到當(dāng)前作用域的最前面胖齐。),但這種現(xiàn)象多少有些奇怪嗽冒,所以為了糾正這種現(xiàn)象let
命令改變了語法行為呀伙,它使得凡是由它聲明出來的變量必須在聲明之后才能使用,否則報(bào)錯(cuò)添坊。也就是由let
聲明的變量不會(huì)再被提升了:
-
不允許重復(fù)聲明
let不允許在相同作用域內(nèi)剿另,重復(fù)聲明同一個(gè)變量。
// 報(bào)錯(cuò)
!function () {
let a = 10;
var a = 1;
}()
// 報(bào)錯(cuò)
!function () {
let a = 10;
let a = 1;
}()
// 報(bào)錯(cuò)
!function () {
var a = 10;
let a = 1;
}()
上面三段代都會(huì)報(bào)錯(cuò)Uncaught SyntaxError: Identifier 'a' has already been declared
贬蛙,只要涉及到let
聲明某個(gè)變量摩钙,在同一作用域內(nèi)重復(fù)聲明該變量都會(huì)報(bào)錯(cuò)齐帚,不管重復(fù)的聲明是怎樣方式疏日。
-
塊級(jí)作用域里的
let
聲明會(huì)形成一段“暫時(shí)性死區(qū)”
只要塊級(jí)作用域內(nèi)存在let命令欲账,它所聲明的變量就“綁定”(binding)這個(gè)塊級(jí)區(qū)域五鲫,不再受外部的影響溺职。該塊級(jí)作用域的起始到let tmp='abc'
這條語句之間的區(qū)域就稱為“暫時(shí)性死區(qū)”,因?yàn)檫@段區(qū)域內(nèi)對(duì)只要使用tmp
變量就會(huì)報(bào)錯(cuò),即使外部作用域已經(jīng)聲明過tmp
也不例外浪耘,這就是所謂的“不受外部影響”乱灵。
有了這個(gè)暫時(shí)性死區(qū)之后意味著
typeof
不再是一個(gè)百分百安全的運(yùn)算符了,在變量的死區(qū)內(nèi)對(duì)變量進(jìn)行typeof
運(yùn)算也會(huì)報(bào)錯(cuò)七冲。
let
命令與var
命令的不同之處就是這些了:let
的聲明的變量只在塊級(jí)作用域內(nèi)有效痛倚、let
聲明的變量不會(huì)被提升、let
聲明的變量在同一作用域內(nèi)不能重復(fù)聲明澜躺、let
聲明的變量會(huì)形成一段該變量的暫時(shí)性死區(qū)蝉稳。
下面舉個(gè)相比于var
,let
更方便的例子掘鄙,我記得在《高程》上有類似下面的一個(gè)例子:
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[k](); //k為0到9, 10
造成這個(gè)結(jié)果的原因是耘戚,i
是由var
聲明的,由于i
的變量提升一級(jí)不存在塊級(jí)作用域操漠,那么i
在全局范圍都有效收津,于是每一次循環(huán)中的i
從始至終都是指向的全局的那唯一一個(gè)i
,所以循環(huán)結(jié)束后浊伙,所有的i
的值都是10撞秋,因?yàn)樗麄兌际峭粋€(gè)i
。
《高程》上給的解決方案是將上面a[i]
后面的賦值放在一個(gè)立即執(zhí)行表達(dá)式里返回出來嚣鄙,模仿出一個(gè)塊級(jí)作用域讓每次循環(huán)都新建出一個(gè)新的i
以達(dá)到每個(gè)i
是次當(dāng)次循環(huán)的索引值的結(jié)果吻贿。
那現(xiàn)在有了let
聲明,使用立即執(zhí)行表達(dá)式來模擬塊作用域這樣麻煩的方法便可由let
來代替了拗慨,所以對(duì)于上面的代碼廓八,我們只需要將var i=0
改為let i = 0
就行了,僅僅一點(diǎn)點(diǎn)改動(dòng)就完全達(dá)到我們想要目的:
使用
var i=0
和let i=0
的區(qū)別就是:前者沒有塊級(jí)作用域赵抢,所有的i
從始至終都指向同一個(gè)i
剧蹂;而后者每次循環(huán)都生成一個(gè)塊級(jí)作用域且在該作用域內(nèi)聲明一個(gè)新的i
,所以每個(gè)i
的都是不同的i
烦却,基本原理大概就如同下面這個(gè)簡單例子:好了宠叼,說完了let
該說const
了,雖然const
可以一筆帶過的其爵,但還是給它一個(gè)新的標(biāo)題吧冒冬。
const命令
上面列舉的那些,let
有的const
都有摩渺,所以這部分不用再贅述简烤。直接說與let
不同的地方
const
聲明的同時(shí)必須被初始化
喏,如果不初始化會(huì)報(bào)錯(cuò)摇幻,提醒你初始化
-
const
聲明的變量初始化后不能再被賦予其他的值
那這個(gè)值指的是什么呢横侦?看兩個(gè)例子:
嗯挥萌,這不是很正常嘛,企圖改變
const
聲明的變量的值時(shí)就報(bào)錯(cuò)
咦枉侧,不是說不能改變值么引瀑?這,不對(duì)啊榨馁。好吧憨栽,其實(shí)這不是正常的操作,下面的才是
所以這下我們應(yīng)該能猜到翼虫,
const
聲明的變量初始化后不能再被賦予其他的值里的“值”指是什么了吧屑柔?
好了,其實(shí)上面的算是ECMAScript 6 入門--阮一峰相關(guān)章節(jié)的筆記蛙讥。
總結(jié)
學(xué)習(xí)東西之后一定要輸出锯蛀,理解了多少就輸出多少,輸出的同時(shí)不僅鞏固已經(jīng)理解的次慢,還會(huì)發(fā)現(xiàn)自以為理解實(shí)際沒有理解的部分以及促使自己去理解更多沒有理解旁涤。