深入理解ES6 - var-let-const
阿新 • • 發佈:2018-05-27
sting fun ret 全局 key 聲明 mas 剛才 syn
知識點
var 聲明變量:
1、存在變量提升,實際上var無論在哪裏聲明,都會被當做當前的作用域頂部聲明變量。
2、可以重復聲明,後聲明的變量會覆蓋前聲明的變量。
let 聲明變量:
1、不存在變量提升。
2、禁止重復聲明。
3、塊級作用域,只在當前作用域塊有用。
4、臨時死區,而且不能在聲明之前訪問它。
const聲明常量:
1、const 聲明的是常量,其值一旦確定後不可以修改 2、const 聲明常量時候必須要進行賦值 3、const 不存在變量提升,一旦執行快外就會立即銷毀。 4、const 只能在當前代碼塊級有效, 5、const 不能重復聲明相同常量。 6、const聲明不允許修改綁定,但允許修改值,也就是說用const創建對象後,可以修改該對象的屬性值。
一、聲明JavaScript的變量有哪些?
每種編程語言都有變量,聲明變量的方法各不同,在JavaScript裏面,最經典的var聲明一個變量,當ECMAScript6出現後,新增了2個聲明變量的方法:let和const,那何時創建變量,用什麽聲明變量方法會更好呢?
二、先談談var聲明及變量提示(hoisting)機制
var聲明一個變量時候,只需要 var name; 或者聲明賦值var name = "Bob";
實際上var無論在哪裏聲明,都會被當做當前的作用域頂部聲明變量。
(1)什麽是變量提示機制?
// var 的變量提升機制
function getValue(condition) {
if (condition) {
var values = ‘Bob‘;
return values;
} else {
console.log(values); // 這裏訪問到values 是undefined,原因下面解釋:
return null;
}
}
// 原因解釋:為什麽上面的代碼else還能訪問values的值,雖然是undefined
// 無論變量values都會被創建,在編譯過程中,JavaScript引擎會將上面的getValue函數修改成這樣:
function getValue (condition) {
// 重點看這裏,變量values的聲明被提升到函數頂部
var values;
if (condition) {
values = ‘Bob‘;
return values;
} else {
console.log(values); // 所以這裏訪問到是聲明過的但未賦值的values,所以是undefined。
return null;
}
}
三、塊級聲明的出現
塊級聲明用於聲明在指定的塊的作用域之外無法訪問的變量
- 函數內部
- 塊級中(字符{ }之間的區域)
四、let聲明
let聲明變量和var聲明變量,但let有自己的四個特征:
- 塊級作用域,限制在當前的塊級作用域中,外面作用域無法訪問。
- 不存在變量提升。
- 臨時死區,而且不能在聲明之前訪問它。
- 禁止重復聲明相同的變量,否則報錯。
我們可以把剛才聊到的getValue函數修改一下:
// let 塊級作用域 && 不存在變量提升
function getValue(condition) {
if (condition) {
// 使用let聲明變量
let values = ‘Bob‘;
return values;
} else {
console.log(values); // 這裏報錯: ReferenceError: values is not defined..
// 原因就是用let聲明的變量,是不存在變量提升的,
// 而且values變量只能在if{ 這個作用塊裏面有效 } 外面是訪問不到的
// 同時,在外面訪問不僅會訪問不到,而且會報錯
return null;
}
}
// let 禁止重復聲明相同變量
function getValue() {
var values = "Bob";
let values = {name: ‘Bob‘};
// 使用let聲明變量禁止重復聲明已經有的變量名
// 否則報錯:SyntaxError: Identifier ‘values‘ has already been declared
}
五、const聲明
- const 聲明的是常量,其值一旦確定後不可以修改。
- const 聲明常量時候必須要進行賦值。
- const 不存在變量提升,一旦執行快外就會立即銷毀。
- const 只能在當前代碼塊級有效,
- const 不能重復聲明相同常量。
- const聲明不允許修改綁定,但允許修改值,也就是說用const創建對象後,可以修改該對象的屬性值。
function getValue() {
// 聲明一個常量
const USER_NAME = "梁鳳波";
// 禁止重復聲明相同常量,否則報錯:TypeError: Assignment to constant variable.
// const USER_NAME = "Bob";
// 記住:const聲明不允許修改綁定,但允許修改值,
// 也就是說用const創建對象後,可以修改該對象的屬性值
const STUDYENT = {
name: ‘梁鳳波‘
};
console.log(`STUDYENT.name = ${STUDYENT.name}`); // STUDYENT.name = 梁鳳波
STUDYENT.name = ‘Bob‘;
console.log(`STUDYENT.name = ${STUDYENT.name}`); // STUDYENT.name = Bob
}
拓展:循環中的塊級作用域綁定
訪問for循環後的結果
// 在for循環內用var 聲明,在外面訪問到的是for循環後的結果
for (var i = 0; i < 10; i++) {
}
console.log(`i = ${i}`); // i = 10
// 在for循環內用let 聲明,在外面 訪問不到,塊級作用域問題
for (let i = 0; i < 10; i++) {
}
console.log(`i = ${i}`); // ReferenceError: i is not defined
循環中的var聲明
// 經過for循環後,在外面訪問i,是直接訪問到了結果i = 10
let funcs = [];
for (var i = 0; i < 10; i++) {
funcs.push(function () {
console.log(i);
})
}
funcs.forEach(func => {
func() // 分別輸出10次10
});
原因:循環裏每次叠代同時共享著變量i,循環內部創建的函數全保留相同變量的引用,循環結束時候i的值變為10,所以每次調用console.log(i)時候回輸出數字10
為了解決這個問題,可以在循環中使用立即調用函數表達式(IIFE),以強制生成計數器變量的副本:
使用var達到理想狀態
// 如果要理想效果,在外面分別輸出 0 ~ 9,
// 可以使用閉包暴露出去
let funcs = [];
for (var i = 0; i < 10; i++) {
funcs.push((function (val) {
return function () {
console.log(val);
}
}(i)))
}
funcs.forEach(func => {
func()
});
循環中的let聲明
let funcs = [];
for (let i = 0; i < 10; i++) {
funcs.push(function () {
console.log(i);
})
}
funcs.forEach(func => {
func() // 分別輸出 0 ~ 9
});
let 聲明模仿上述示例IIFE所做的一切簡化循環過程,每次叠代循環都會創建一個新變量,並以之前叠代中同名變量的值將其初始化。
循環中的const聲明
let funcs = [];
let obj = {
a: true,
b: true,
c: true
}
for (const key in obj) {
funcs.push(function () {
console.log(key);
})
}
funcs.forEach(func => {
func() // 分別輸出 a, b, c Authorization
});
let和const聲明循環,const循環是不能改變key的值,const 循環應該使用for-in,for-of,其他和let示例一樣,因為每次叠代不會像var循環例子一樣修改已有的綁定,而是會創建一個新綁定。
全局塊級作用域綁定
var RegExp = "Bob";
// 即使是全局對象RegExp定義在window,也不能幸免被var聲明覆蓋
console.log(RegExp); // Bob
console.log(window.RegExp); // Bob
let RegExp = "Bob";
// 用let或const聲明不能覆蓋全局變量,而只能屏蔽它
console.log(RegExp); // Bob
console.log(window.RegExp); // undefined
console.log(window.RegExp === RegExp); // false
const ncz = ‘Hi!‘
console.log(‘ncz‘ in window); // false
最後聊一聊塊級綁定的最佳實踐
默認使用const,只在確實需求改變變量的值使用let,這樣就可以在某種程度上實現代碼的不可變,從而防止默寫錯誤產生。
深入理解ES6 - var-let-const