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 命令經常會發生變數提升現象,按照一般邏輯,變數應該在宣告之後使用才對。為了糾正這個現象,ES6 規定 let 和 const 命令不發生變數提升,使用 let 和 const 命令宣告變數之前,該變數是不可用的。主要是為了減少執行時錯誤,防止變數宣告前就使用這個變數,從而導致意料之外的行為。
2、暫時性死區
概述:如果在程式碼塊中存在 let 或 const 命令,這個區塊對這些命令宣告的變數,從一開始就形成了封閉作用域。凡是在宣告之前就使用這些變數,就會報錯。
var tmp = 123;
if (true) {
tmp = 'abc';//報錯,Uncaught ReferenceError: tmp is not defined
let tmp;
}
複製程式碼
剖析暫時性死區的原理,其實let/const同樣也有提升的作用,但是和var的區別在於
- var在建立時就被初始化,並且賦值為undefined
- let/const在進入塊級作用域後,會因為提升的原因先建立,但不會被初始化,直到宣告語句執行的時候才被初始化,初始化的時候如果使用let宣告的變數沒有賦值,則會預設賦值為undefined,而const必須在初始化的時候賦值。而建立到初始化之間的程式碼片段就形成了暫時性死區
3、不允許重複宣告
let
不允許在相同作用域內,重複宣告同一個變數。
// 報錯
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中我們會遇到下面這寫情況 第一種場景,內層變數可能會覆蓋外層變數。
var tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';//沒有塊級作用域tmp變數提升到函式作用域裡導致tmp為undefined
}
}
f(); // undefined
複製程式碼
第二種場景,用來計數的迴圈變數洩露為全域性變數。
var s = 'hello';
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // 5
複製程式碼
上面程式碼中,變數i
只用來控制迴圈,但是迴圈結束後,它並沒有消失,洩露成了全域性變數。
let n = 5;
if (true) {
let n = 10;
}
console.log(n); // 5
}
複製程式碼
let實際上為 JavaScript 新增了塊級作用域。
5、const注意點
1、const宣告變數的時候必須賦值,否則會報錯,同樣使用const宣告的變數被修改了也會報錯 2、const宣告變數不能改變,如果宣告的是一個引用型別,則不能改變它的記憶體地址
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.
複製程式碼
本質:const實際上保證的,並不是變數的值不得改動,而是變數指向的那個記憶體地址所儲存的資料不得改動。對於簡單型別的資料(數值、字串、布林值),值就儲存在變數指向的那個記憶體地址,因此等同於常量。但對於複合型別的資料(主要是物件和陣列),變數指向的記憶體地址,儲存的只是一個指向實際資料的指標,const只能保證這個指標是固定的(即總是指向另一個固定的地址),至於它指向的資料結構是不是可變的,就完全不能控制了
那麼我們想得到不可修改的const要怎麼做呢?應該使用Object.freeze
方法。
const foo = Object.freeze({});
// 常規模式時,下面一行不起作用;
// 嚴格模式時,該行會報錯
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 入門