一個完整的JavaScript的實現由三個部分組成:
- 核心:ECMAScript
- 文檔對象模型:DOM
- 瀏覽器對象模型:BOM
ECMAScript
什麼是 ES
ECMAScript(簡稱ES)是由ECMA-262定義的。
ES 與 JS
ES可以理解爲是JavaScript的一個標準。實際上,JavaScript是ECMA-262標準的實現和擴展。
ES與Web瀏覽器
ES與瀏覽器沒有依賴關係。 Web瀏覽器只是ES實現可能的宿主環境之一,其他宿主環境包括node和Adobe flash。
ES6新增功能
ES6即ECMAScript的第6版。
let
let的特性 let-Javascript MDN
- let和const不會在全局聲明時創建window對象的屬性;而位於函數或代碼頂部的var聲明會給全局對象新增屬性
var x = 'global'
let y = 'global'
console.log(this.x) // "global"
console.log(this.y) // undefined
- let聲明的變量、語句或者表達式的作用域限制在塊級作用域中;var聲明的變量只能是全局或者整個函數塊的
var a = 1
var b = 2
if (a === 1) {
var a = 11 // the scope is global
let b = 22 // the scope is inside the if-block
console.log(a) // 11
console.log(b) // 22
}
console.log(a) // 11
console.log(b) // 2
- 初始化:let在編譯時才初始化
- 可以用來模仿私有成員,在處理構造函數時,通過let聲明而不是閉包來創建一個或多個私有成員
var Thing
{
let privateScope = new WeakMap()
let counter = 0
Thing = function () {
this.someProperty = 'foo'
privateScope.set(this, {
hidden: ++counter,
})
}
Thing.prototype.showPublic = function () {
return this.someProperty
}
Thing.prototype.showPrivate = function () {
return privateScope.get(this).hidden
}
}
console.log(typeof privateScope) // "undefined"
var thing = new Thing()
console.log(thing) // Thing {someProperty: "foo"}
thing.showPublic() // "foo"
thing.showPrivate() // 1
- 在同一個函數或塊作用域中重複聲明同一個變量會引起SyntaxError
// 在 switch 語句中只有一個塊
let x = 1
switch (x) {
case 0:
let foo
break
case 1:
let foo // SyntaxError for redeclaration.
break
}
// 解決方法:一個嵌套在 case 子句中的塊會創建一個新的塊作用域的詞法環境
let x = 1
switch (x) {
case 0: {
let foo
break
}
case 1: {
let foo
break
}
}
- 暫存死區與變量提升:let和const不存在變量提升,直到它們的定義被執行時才初始化;在變量初始化前訪問該變量會導致ReferenceError,該變量處在一個自塊頂部到初始化處理的“暫存死區”中
function do_something() {
console.log(bar) // undefined
console.log(foo) // ReferenceError
var bar = 1
let foo = 2
}
// 在同一行,這個if塊中的foo已經在詞法環境中被創建了,但是還沒有到達(或者終止)它的初始化(這是語句本身的一部分)
// 這個if塊裏的foo還依舊在暫存死區裏
function test() {
var foo = 33
{
let foo = foo + 55 // ReferenceError
}
}
test()
- 暫存死區與typeof:通過var聲明的變量有初始化值undefined,和未聲明變量的typeof都爲undefined;而let,使用typeof檢測在暫存死區中的變量, 會拋出ReferenceError異常
console.log(typeof undeclaredVariable) //打印出 undefined
console.log(typeof undeclaredVariable) //打印出 undefined
var varVariable
console.log(typeof i) //引發異常 ReferenceError: Cannot access 'i' before initialization
let i = 10
const
const聲明一個只讀的常量。一旦聲明,變量指向的那個內存地址不得改動(不是變量值不能改變),且聲明時必須立即初始化,不能留到以後賦值。const的作用域與let命令相同:只在聲明所在的塊級作用域內有效。
對於簡單類型的數據(數值、字符串、布爾值),值就保存在變量指向的那個內存地址,因此等同於常量。
但對於複合類型的數據(主要是對象和數組),變量指向的內存地址,保存的只是一個指針,const只能保證這個指針是固定的,至於它指向的數據結構是不是可變的,就完全不能控制了。因此,將一個對象聲明爲常量必須非常小心。如果真的想將對象或對象屬性凍結,應該使用Object.freeze方法。
const foo = {}; // const foo = []同理,可以正常使用push等功能
foo.prop = 123; // 爲foo添加一個屬性,可以成功
console.log(foo.prop); //123
foo = {}; // 將foo指向另一個對象,就會報錯
Class
Class ES2015
類的數據類型就是函數,類本身就指向構造函數
import
解構賦值
ES6允許按照一定模式,從數組和對象中提取值,對變量進行賦值,這被稱爲解構(Destructuring)。本質上,這種寫法屬於“模式匹配”,只要等號兩邊的模式相同,左邊的變量就會被賦予對應的值。
let a = 1;
let b = 2;
let c = 3;
// 等價於
let [a, b, c] = [1, 2, 3];
let [ , third] = ["foo", "bar", "baz"];
third // "bar"
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
let [x, y, ...z] = ['a'];
x // "a"
y // 變量解構不成功,賦值爲undefined
z // 數組解構不成功,賦值爲[]
解構賦值允許指定默認值,只有當一個數組成員嚴格等於undefined,默認值纔會生效:
let [foo = true] = []; // foo = true
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [q = 1, w = 'b'] = ['a', undefined]; // q='a', w='b'
let [e = 1] = [null]; // e = null