1、變量提升
概述:變量可在聲明之前使用荷科。
console.log(a);//正常運行唯咬,控制臺輸出 undefined
var a = 1;
console.log(b);//報錯,Uncaught ReferenceError: b is not defined
let b = 1;
console.log(c);//報錯畏浆,Uncaught ReferenceError: c is not defined
const c = 1;
var 命令經(jīng)常會發(fā)生變量提升現(xiàn)象胆胰,按照一般邏輯,變量應該在聲明之后使用才對刻获。為了糾正這個現(xiàn)象蜀涨,ES6 規(guī)定 let 和 const 命令不發(fā)生變量提升,使用 let 和 const 命令聲明變量之前将鸵,該變量是不可用的勉盅。主要是為了減少運行時錯誤,防止變量聲明前就使用這個變量顶掉,從而導致意料之外的行為草娜。
2、暫時性死區(qū)
概述:如果在代碼塊中存在 let 或 const 命令痒筒,這個區(qū)塊對這些命令聲明的變量宰闰,從一開始就形成了封閉作用域茬贵。凡是在聲明之前就使用這些變量,就會報錯移袍。
var tmp = 123;
if (true) {
tmp = 'abc';//報錯解藻,Uncaught ReferenceError: tmp is not defined
let tmp;
}
剖析暫時性死區(qū)的原理,其實let/const同樣也有提升的作用葡盗,但是和var的區(qū)別在于
- var在創(chuàng)建時就被初始化螟左,并且賦值為undefined
- let/const在進入塊級作用域后,會因為提升的原因先創(chuàng)建觅够,但不會被初始化胶背,直到聲明語句執(zhí)行的時候才被初始化,初始化的時候如果使用let聲明的變量沒有賦值喘先,則會默認賦值為undefined钳吟,而const必須在初始化的時候賦值。而創(chuàng)建到初始化之間的代碼片段就形成了暫時性死區(qū)
3窘拯、不允許重復聲明
let
不允許在相同作用域內(nèi)红且,重復聲明同一個變量。
// 報錯
function func() {
let a = 10;
var a = 1;
}
// 報錯
function func() {
let a = 10;
let a = 1;
}
function func(arg) {
let arg;
}
func() // 報錯
function func(arg) {
{
let arg;
}
}
func() // 不報錯
4涤姊、塊級作用域
在es5中我們會遇到下面這寫情況
第一種場景暇番,內(nèi)層變量可能會覆蓋外層變量。
var tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';//沒有塊級作用域tmp變量提升到函數(shù)作用域里導致tmp為undefined
}
}
f(); // undefined
第二種場景砂轻,用來計數(shù)的循環(huán)變量泄露為全局變量奔誓。
var s = 'hello';
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // 5
上面代碼中,變量i
只用來控制循環(huán)搔涝,但是循環(huán)結束后厨喂,它并沒有消失,泄露成了全局變量庄呈。
let n = 5;
if (true) {
let n = 10;
}
console.log(n); // 5
}
let實際上為 JavaScript 新增了塊級作用域蜕煌。
5、const注意點
1诬留、const聲明變量的時候必須賦值斜纪,否則會報錯,同樣使用const聲明的變量被修改了也會報錯
2文兑、const聲明變量不能改變盒刚,如果聲明的是一個引用類型,則不能改變它的內(nèi)存地址
const c ; //Uncaught SyntaxError: Missing initializer in const declaration
const a= {a:1};
a.a=2;
a={d:2};// Uncaught TypeError: Assignment to constant variable.
本質(zhì):const實際上保證的绿贞,并不是變量的值不得改動因块,而是變量指向的那個內(nèi)存地址所保存的數(shù)據(jù)不得改動。對于簡單類型的數(shù)據(jù)(數(shù)值籍铁、字符串涡上、布爾值)趾断,值就保存在變量指向的那個內(nèi)存地址,因此等同于常量吩愧。但對于復合類型的數(shù)據(jù)(主要是對象和數(shù)組)芋酌,變量指向的內(nèi)存地址,保存的只是一個指向?qū)嶋H數(shù)據(jù)的指針雁佳,const只能保證這個指針是固定的(即總是指向另一個固定的地址)脐帝,至于它指向的數(shù)據(jù)結構是不是可變的,就完全不能控制了
那么我們想得到不可修改的const要怎么做呢甘穿?應該使用Object.freeze
方法腮恩。
const foo = Object.freeze({});
// 常規(guī)模式時,下面一行不起作用温兼;
// 嚴格模式時,該行會報錯
foo.prop = 123;
// 除了將對象本身凍結武契,對象的屬性也應該凍結募判。
var constantize = (obj) => {
Object.freeze(obj);
Object.keys(obj).forEach( (key, i) => {
if ( typeof obj[key] === 'object' ) {
constantize( obj[key] );
}
});
};
參考文章
ECMAScript 6 入門