ES 6 系列為學(xué)習(xí)阮一峰老師 ECMAScript 6 入門(mén) 的一些筆記今妄。
W3C標(biāo)準(zhǔn)文檔地址: ECMAScript 6 Specification
學(xué)習(xí)ES 6 第一個(gè)概念一般都是 let
和 const
,兩種新的聲明變量的方式盘寡。
兩者在使用上都類(lèi)似于 var
用于聲明變量员凝。
let, const 與 var 的區(qū)別
-
塊級(jí)作用域
使用let
和const
聲明的變量摇锋,只在其聲明所在代碼塊內(nèi)有效(塊級(jí)作用域)苇侵。if(true) { // 這里聲明的 hello 函數(shù)只在 if 的塊級(jí)作用域內(nèi)有效 let hello = function() { alert('Hello'); } } // 試圖調(diào)用 if 作用域內(nèi)聲明的 hello 方法油狂,錯(cuò)誤历恐。 hello(); // ReferenceError: Can't find variable: hello
JavaScript 代碼中需要塊級(jí)作用域的幾個(gè)場(chǎng)景:
- 內(nèi)層變量可能會(huì)覆蓋外層變量導(dǎo)致一些不可預(yù)知的行為
- 計(jì)數(shù)的循環(huán)變量泄露為全局變量
塊級(jí)作用域的出現(xiàn),讓廣泛使用的 IIFE (立即執(zhí)行匿名函數(shù))不再必要专筷。
ES 6 中規(guī)定函數(shù)(通過(guò)function聲明的具有變量聲明提升的方法時(shí)可看出)本身的作用域弱贼,在其所在的塊級(jí)作用域之內(nèi)。
function f() { console.log('I am outside!'); }
(function () {
if(false) {
// 重復(fù)聲明一次函數(shù)f
// 變量聲明提升磷蛹,但是作用域依舊在 if 的塊級(jí)作用域內(nèi)
function f() { console.log('I am inside!'); }
}
// 在 IIFE 作用域內(nèi)調(diào)用 f()
f();
}());
上面代碼在ES5中運(yùn)行吮旅,會(huì)得到“I am inside!”,但是在ES6中運(yùn)行味咳,會(huì)得到“I am outside!”庇勃。
-
變量聲明提升(Hoisting) 與 暫時(shí)性死區(qū)
使用let
和const
聲明的變量都不存在 變量聲明提升,一個(gè)變量必須先聲明然后才能使用槽驶。
關(guān)于暫時(shí)性死區(qū):在聲明變量之前使用變量會(huì)錯(cuò)誤匪凉。
let temp = 'global temp'; // 全局作用域下聲明的 temp 變量
if (true) {
// if 包含的塊級(jí)作用域中的 temp 引用,由于還沒(méi)聲明所以錯(cuò)誤捺檬。
// 這里還涉及到變量綁定的問(wèn)題再层,
// 在 ES 6 中如果一個(gè)塊級(jí)作用域中有存在 let 命令,
// 它所聲明的變量就 '綁定' 在這個(gè)區(qū)域堡纬,不受外部的影響聂受。
// 這就解釋了為什么這里的 temp 沒(méi)有引用全局的 temp = 'global temp'
temp = 'abc'; // ReferenceError
// 不存在變量聲明提示,所以 temp 在該作用域類(lèi)的聲明不會(huì)像 ES 3 中一樣被放到作用域最開(kāi)始的地方聲明并賦值為 undefined
let temp;
}
// ReferenceError: Cannot access uninitialized variable.
ES 6 中規(guī)定暫時(shí)性死區(qū)和不存在變量聲明提升烤镐,主要是為了減少運(yùn)行時(shí)錯(cuò)誤蛋济,防止在變量聲明前使用這個(gè)變量,從而導(dǎo)致意料之外的行為炮叶。
暫時(shí)性死區(qū)同時(shí)意味著 typeof
不再是一個(gè)百分百安全的操作(ReferenceError
錯(cuò)誤)碗旅。
let temp = 'global temp';
if(true){
// 使用 typeof 操作符作用在 temp 上渡处,由于 if 作用域內(nèi)的 temp 變量目前處在 暫時(shí)性死區(qū)中,所以引用錯(cuò)誤
console.log(typeof temp);
// ReferenceError: Cannot access uninitialized variable.
let temp = 'temp';
}
不能重復(fù)聲明
使用let
和const
聲明的變量在同一作用域內(nèi)不能重復(fù)聲明祟辟。
使用var
聲明的變量如果變量名相同后聲明的變量將會(huì)覆蓋變量原來(lái)的值医瘫。全局變量以及全局對(duì)象屬性
ES 5 中全局對(duì)象的屬性 與 全局變量基本是等價(jià)的(也有區(qū)別,比如通過(guò) var 聲明的全局變量不能使用 delete 從 global (window/global) 上刪除旧困,在變量的訪問(wèn)上基本等價(jià))醇份。
很容易的在不知不覺(jué)中創(chuàng)建了全局變量(全局對(duì)象的屬性)
ES 6 中做了嚴(yán)格的區(qū)分,使用 var 和 function 聲明的全局變量依舊作為 全局對(duì)象的屬性吼具,使用 let
, const
命令聲明的全局變量不屬于全局對(duì)象的屬性僚纷。
let let_test = 'test';
window.let_test; // undefined
var var_test = 'test';
window.var_test; // test
const 的一些注意事項(xiàng)
使用 let
聲明變量除了以上和 var
不同的地方,其他使用和 var
基本一致拗盒,聲明的變量可以進(jìn)行修改怖竭。
而使用 const
聲明的變量是用來(lái)聲明一個(gè)常量,一旦聲明陡蝇,常量的值是不能改變的侵状。使用時(shí)需要注意以下幾點(diǎn):
一旦聲明不能修改
嚴(yán)格模式下對(duì)已經(jīng)初始化的常量賦值會(huì)報(bào)錯(cuò)。
非嚴(yán)格模式下對(duì)已經(jīng)初始化的常量賦值不報(bào)錯(cuò)但是無(wú)效毅整。避免只聲明不賦值
嚴(yán)格模式下對(duì)常量聲明的變量只聲明不賦值會(huì)報(bào)錯(cuò)趣兄。
if(true) {
'use strict';
const test;
// SyntaxError: Unexpected token ';'. const declared variable 'test' must have an initializer.
}
非嚴(yán)格模式下不會(huì)報(bào)錯(cuò),但值是undefined
且無(wú)法修改-
復(fù)合類(lèi)型
const
變量保存的是引用
復(fù)合類(lèi)型的常量不指向數(shù)據(jù)悼嫉,而是指向數(shù)據(jù)(heap)所在的地址(stack)艇潭,所以通過(guò) const 聲明的復(fù)合類(lèi)型只能保證其 地址引用不變,但不能保證其數(shù)據(jù)不變戏蔑。const arr= [1, 2]; // 修改數(shù)據(jù)而不修改引用地址蹋凝,正確執(zhí)行 arr.push(3); // [1, 2, 3] // 修改 arr 常量所保存的地址的值,報(bào)錯(cuò) arr = []; // TypeError: Attempted to assign to readonly property.
-
對(duì)象的凍結(jié)
因?yàn)?復(fù)合類(lèi)型const
是保存引用的原因所以存在 對(duì)象的凍結(jié)的問(wèn)題总棵。
簡(jiǎn)單的使用const
無(wú)法完成對(duì)象的凍結(jié)鳍寂。
可以通過(guò) Object.freeze() 方法實(shí)現(xiàn)對(duì)對(duì)象的凍結(jié)。
使用Object.freeze()
方法返回的對(duì)象將不能對(duì)其屬性進(jìn)行配置(definedProperty()
不可用)同時(shí)不能添加新的屬性和移除(remove)已有屬性情龄。In essence the object is made effectively immutable.
本質(zhì)上是產(chǎn)生一個(gè)有效的不可變對(duì)象迄汛。因此對(duì)其進(jìn)行的修改將不會(huì)生效。但同樣有
引用 和 數(shù)據(jù)
的問(wèn)題(和復(fù)合類(lèi)型 const 變量保存的是引用
一樣)骤视,所以徹底凍結(jié)對(duì)象時(shí)需要遞歸的對(duì)它的對(duì)象屬性進(jìn)行凍結(jié)鞍爱。
ES5只有兩種聲明變量的方法:var
命令和 function
命令。ES6除了添加 let
和 const
命令专酗,以及import
命令和 class
命令(后面將會(huì)學(xué)習(xí))睹逃。所以,ES6一共有6種聲明變量的方法祷肯。