說明:本文參考阮一峰的ECMAScript 6 入門
1.let指令
作用:let聲明的變量隻在其所在代碼塊内有效
{
let a = 10
}
console.log(a )
代碼塊外使用會報錯: ReferenceError: a is not defined
for循環内使用let和var産生的不同效果:
下面代碼使用的是var,結果為10
var a = []
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i)
}
}
a[9]() //10
上述代碼,因為變量i是var聲明的,在全局範圍内都有效,是以全局隻有一個變量i。這就導緻for循壞結束後i的值為10,而當我們再去調用a數組裡面的函數,函數裡面i的值即為i最終值10。
下面的代碼使用的是let,聲明的變量僅在塊級作用域内有效,最後結果為9
var a = []
for (let i=0; i < 10; i++) {
a[i] = function () {
console.log(i)
}
}
a[9]()//9
上述代碼,因為變量i是let聲明的,在塊級作用域内有效,就會導緻for循環的每一輪循環都會有自己聲明的變量i,可以了解為每輪循環都是在做以下的工作,隻不過各自的i值不同
當i=0時
{
let i = 0
a[i] = function () {
console.log(i)
}
}
當i=1時
{
let i = 1
a[i] = function () {
console.log(i)
}
}
等等…
當i=9時
{
let i = 9
a[i] = function () {
console.log(i)
}
}
當調用數組裡的函數,例如
a[9]()
,因為i在自己所聲明的代碼塊内有效,而函數和其同在一個代碼塊内,自然先找到自己所在代碼塊内的i,是以
a[9]()
輸出的值為9。
let指令不存在變量提升
var指令會發生“變量提升”現象,即變量可以在聲明之前使用,值為undefined
// var 的情況
console.log(a) // 輸出undefined
var a = 10
// let 的情況
console.log(b) // 報錯ReferenceError
let b = 10
暫時性死區
隻要塊級作用域存在let聲明的變量,那麼這個變量就不再受外部影響
var temp = "abc"
if (true) {
temp = "def" //ReferenceError: Cannot access 'tmp' before initialization
let temp
}
上面代碼中,存在全局變量temp,if語句的代碼塊内也使用了let聲明的temp并且是在指派temp之後聲明的,但最終報錯是因為塊級作用域記憶體在let聲明的temp變量,使得該變量綁定在塊級作用域内,不會去尋找全局變量temp,而在let聲明之前就使用該變量就會報錯。
不允許重複聲明
let指令不允許在相同作用域内,重複聲明同一個變量,以下代碼會報錯
// 報錯
function func() {
let a = 10;
var a = 1;
}
// 報錯
function func() {
let a = 10;
let a = 1;
}
2.塊級作用域
ES5隻有全局作用域和函數作用域,沒有塊級作用域,這會導緻存在許多不合理場景。
例如記憶體變量覆寫了外層變量,for循壞的循環變量成為了全局作用域,循環結束後該循環變量依然存在不能被回收。
而ES6的let指令實際上就構成了塊級作用域。并且在ES6中規定允許在塊級作用域中聲明函數。
3.const指令
const指令用來聲明一個隻讀的常量,一旦聲明,常量的值就不能改變
const PI = 3.1415;
PI // 3.1415
PI = 3;
// TypeError: Assignment to constant variable.
上面代碼在試圖改變常量PI但報了錯
既然const聲明的變量不能進行改變,那麼就需要在聲明的時候進行初始化,不能留到以後再進行指派。
const foo;
// SyntaxError: Missing initializer in const declaration
上面代碼說明const聲明變量時要進行初始化否則會報錯
const的作用域同let一樣,隻在聲明所在的塊級作用域内有效,const聲明的變量同let一樣不能重複聲明
if (true) {
const MAX = 5;
}
MAX // Uncaught ReferenceError: MAX is not defined
//const聲明的變量同let一樣不能重複聲明
var msg= "Hello!";
let age = 19;
// 以下兩行都會報錯
const msg= "Goodbye!";
const age = 25;
const本質
const實際上是讓變量指向的記憶體位址儲存的資料不能改變,并不是變量的值不能改動。對于簡單類型(數值、字元串、布爾值)來說,值就儲存在變量指向的那個記憶體位址中,是以等同于常量。對于複雜類型(主要是對象和數組)來說,變量指向的記憶體位址儲存着指向實際資料的指針,const隻能保證這個指針是固定的,至于它指向的實際資料是否可變,則不受控制。是以在将一個對象聲明為常量值時,這個對象自身是可以改變的。
const person = {}
person.name = "王五"
person.name //王五
person = {} // TypeError: "person" is read-only
上面代碼person是一個常量對象,可以成功為其添加屬性name,但不能讓person重新指向另一個位址。
頂層對象的屬性
頂層對象,在浏覽器中是指window對象,在node中指global對象。在ES5中頂層對象的屬性與全局變量是等價的。
window.a = 1;
a // 1
a = 2;
window.a // 2
上面代碼中,頂層對象的屬性指派與全局變量的指派,是同一件事。
ES6中則規定,var指令和function指令聲明的全局變量依舊是頂層對象的屬性,而let、const、class指令聲明的全局變量不屬于頂層對象的屬性。
let a = 6
console.log(window.a) //undeined
上面代碼中,全局變量a由let指令聲明,是以它不是頂層對象的屬性,傳回undefined