ES6是下一代JavaScript語言標準的統稱,每年6月發布一次修訂版,迄今為止已經發布了3個版本,分別是ES2015、ES2016、ES2017。本書根據ES2017標準,詳盡介紹了所有新增的語法,對基本概念、設計目的和用法進行了清晰的講解,給出了大量簡單易懂的示例。本書為中級難度,適合那些已經對JavaScript語言有一定了解的讀者,可以作為學習這門語言*進展的工具書,也可以作為參考手冊供大家隨時查閱新語法。第3版增加了超過30%的內容,完全覆蓋了ES2017標準,相比第2版介紹了更多的語法點,還調整了原有章節的文字表達,充實了示例,論述更準確,更易懂易學。
橫跨ES2015/2016/2017新標,搶占JavaScript制高點
由千萬級名博、布道引領無數前端入行的阮一峰執筆
來自BAT一線實踐,精彩案例透徹解讀新標|保留語法
新標首著,凝結多年研究心得,剖析ES理解應用難題
第3版前言
4年前,當我開始寫這本書的時候,ECMAScript
5.1版剛剛開始普及,最流行的框架還是jQuery。ES6看上去就像一個遙遠的藍圖,無人知道何時會實現。
僅僅4年,ES6已經經歷了ES2015、ES2016、ES2017這3個版本的迭代,各種實現的支持度已經超過90%,不僅可以實現網頁的編寫,還可以實現服務器腳本、手機App和桌面應用的編寫。程序員們完全接受了這個標準,甚至大量使用尚未標準化的新語法。JavaScript語言就像一列高鐵,以令人眩暈的速度向前沖刺。
互聯網行業的蓬勃興旺造就了ES6的成功,也使得這本教程不斷更新,越寫越厚。第2版問世18個月之后,不得不推出第3版。
第3版新增了超過30%的內容,完全覆蓋了ES2017標準(第2版只做到覆蓋 ES2015標準),并且對所有章節都進行了修訂,文字表達更準確易懂,示例更豐富。對讀者來說,這個版本更容易學習,更有參考價值。
這4年來,我對ES6的理解和所有的學習筆記,都濃縮在這本教程里面。那些我自己感到最困難的地方,書中都做出了詳細講解,給出了細致的示例,我相信這也是其他國內學習者所需要的。
這本教程當然也包含了些許局限,以及細致檢查之后仍然疏漏的各種錯誤。一旦發現,我會第一時間更正。讀者可以到官方倉庫github.com/ruanyf/es6tutorial中查看勘誤。
我在微博上曾經說過一段話,就把它放在這里作為結束吧。
我水平其實不高,只是好奇心重,從沒想到這么多人會關注。希望不要讓大家失望,未來做一塊墊腳石,為需要的朋友提供幫助,為技術的推廣和發展做出力所能及的貢獻。
阮一峰
2017年8月1日,寫于杭州
第1版前言
2012年年底,我開始動手做一個開源項目《JavaScript標準參考教程》(github.com/ruanyf/
jstutorial)。原來的設想是將自己的學習筆記整理成一本書,哪里料到,這個項目不斷膨脹,最后變成了ECMAScript 5及其外圍API的全面解讀和參考手冊,寫了一年多還沒寫完。
那個項目的最后一章就是ECMAScript 6的語法簡介。那一章也是越寫越長,最后我不得不決定,把它獨立出來,作為一個新項目,也就是您現在看到的這本書。
JavaScript已經是互聯網開發的第一大語言,而且正在變成一種全領域的語言。著名程序員Jeff Atwood甚至提出了一條Atwood定律:所有可以用JavaScript編寫的程序,最終都會出現JavaScript的版本。(Any application that can be written in JavaScript will eventually be
written in JavaScript.)
ECMAScript正是JavaScript的國際標準,這就決定了該標準的重要性。而ECMAScript 6是ECMAScript歷史上最大的一次版本升級,在語言的各個方面都有極大的變化,即使是熟練的JavaScript程序員,也需要重新學習。由于ES6的設計目標是企業級開發和大型項目,所以可以預料,除了互聯網開發者,將來還會有大量應用程序開發者(甚至操作系統開發者)成為ES6的學習者。
我寫作這本書的目標,就是想為上面這些學習者提供一本篇幅較短、簡明易懂、符合中文表達習慣的ES6教程。它由淺入深、循序漸進,既有重要概念的講解,又有API接口的羅列,便于日后當作參考手冊查閱,還提供大量示例代碼,讓讀者不僅一看就懂,還能舉一反三,直接復制用于實際項目之中。
需要聲明的是,為了突出重點,本書只涉及ES6與ES5的不同之處,不對JavaScript已有的語法進行全面講解,畢竟市面上這樣的教程已經有很多了。因此,本書不是JavaScript入門教材,不適合初學者。閱讀本書之前,需要對JavaScript的基本語法有所了解。
我本人也是一個ES6的學習者,不敢說自己有多高的水平,只是較早地接觸了這個主題,持續地讀了許多資料,追蹤標準的進展,做了詳細的筆記而已。雖然我盡了最大努力,并且原稿在GitHub上公開后已經得到了大量的勘誤,但是本書的不盡如人意之處恐怕還有不少。
歡迎大家訪問本書的項目主頁(github.com/ruanyf/es6tutorial),提出意見,提交pull request。這些都會包括在本書的下一個版本中。
阮一峰
2014年6月4日,寫于上海
阮一峰,資深JavaScript 語言專家,知名技術博客作者,專注于網站開發技術十余年。暢銷書《黑客與畫家》、《軟件隨想錄》的譯者,現就職于螞蟻金服集團。
目錄
第1章 ECMAScript 6簡介1
1.1 ECMAScript和JavaScript的關系1
1.2 ES6與ECMAScript 2015的關系1
1.3 語法提案的批準流程2
1.4 ECMAScript的歷史3
1.5 部署進度4
1.6 Babel 轉碼器4
1.6.1 配置文件.babelrc5
1.6.2 命令行轉碼babel-cli6
1.6.3 babel-node7
1.6.4 babel-register8
1.6.5 babel-core8
1.6.6 babel-polyfill9
1.6.7 瀏覽器環境10
1.6.8 在線轉換10
1.6.9 與其他工具的配合11
1.7 Traceur轉碼器11
1.7.1 直接插入網頁12
1.7.2 在線轉換13
1.7.3 命令行轉換14
1.7.4 Node環境的用法15
第2章 let和const命令17
2.1 let 命令17
2.1.1 基本用法17
2.1.2 不存在變量提升19
2.1.3 暫時性死區19
2.1.4 不允許重復聲明21
2.2 塊級作用域22
2.2.1 為什么需要塊級作用域22
2.2.2 ES6的塊級作用域23
2.2.3 塊級作用域與函數聲明24
2.2.4 do表達式27
2.3 const命令28
2.3.1 基本用法28
2.3.2 本質29
2.3.3 ES6聲明變量的6種方法30
2.4 頂層對象的屬性30
2.5 global對象31
第3章 變量的解構賦值33
3.1 數組的解構賦值33
3.1.1 基本用法33
3.1.2 默認值35
3.2 對象的解構賦值37
3.3 字符串的解構賦值41
3.4 數值和布爾值的解構賦值41
3.5 函數參數的解構賦值42
3.6 圓括號問題43
3.6.1 不能使用圓括號的情況43
3.6.2 可以使用圓括號的情況44
3.7 用途44
第4章 字符串的擴展49
4.1 字符的Unicode表示法49
4.2 codePointAt()50
4.3 String.fromCodePoint()52
4.4 字符串的遍歷器接口52
4.5 at()53
4.6 normalize()53
4.7 includes()、startsWith()、endsWith()54
4.8 repeat()55
4.9 padStart()、padEnd()56
4.10 模板字符串57
4.11 實例:模板編譯60
4.12 標簽模板62
4.13 String.raw()67
4.14 模板字符串的限制68
第5章 正則的擴展71
5.1 RegExp構造函數71
5.2 字符串的正則方法72
5.3 u修飾符72
5.4 y修飾符74
5.5 sticky屬性77
5.6 flags屬性77
5.7 s修飾符:dotAll模式78
5.8 后行斷言79
5.9 Unicode屬性類80
5.10 具名組匹配81
5.10.1 簡介81
5.10.2 解構賦值和替換82
5.10.3 引用83
第6章 數值的擴展85
6.1 二進制和八進制表示法85
6.2 Number.isFinite()、Number.isNaN()86
6.3 Number.parseInt()、Number.parseFloat()87
6.4 Number.isInteger()88
6.5 Number.EPSILON88
6.6 安全整數和Number.isSafeInteger()89
6.7 Math對象的擴展92
6.7.1 Math.trunc()92
6.7.2 Math.sign()92
6.7.3 Math.cbrt()93
6.7.4 Math.clz32()94
6.7.5 Math.imul()95
6.7.6 Math.fround()95
6.7.7 Math.hypot()96
6.7.8 對數方法96
6.7.9 雙曲函數方法98
6.8 Math.signbit()98
6.9 指數運算符99
6.10 Integer數據類型99
6.10.1 簡介99
6.10.2 運算100
第7章 函數的擴展103
7.1 函數參數的默認值103
7.1.1 基本用法103
7.1.2 與解構賦值默認值結合使用105
7.1.3 參數默認值的位置107
7.1.4 函數的length屬性108
7.1.5 作用域108
7.1.6 應用111
7.2 rest參數112
7.3 嚴格模式113
7.4 name屬性115
7.5 箭頭函數116
7.5.1 基本用法116
7.5.2 注意事項118
7.5.3 嵌套的箭頭函數121
7.6 綁定this123
7.7 尾調用優化124
7.7.1 什么是尾調用124
7.7.2 尾調用優化125
7.7.3 尾遞歸126
7.7.4 遞歸函數的改寫128
7.7.5 嚴格模式129
7.7.6 尾遞歸優化的實現129
7.8 函數參數的尾逗號132
第8章 數組的擴展133
8.1 擴展運算符133
8.1.1 含義133
8.1.2 替代數組的apply方法134
8.1.3 擴展運算符的應用136
8.2 Array.from()139
8.3 Array.of()142
8.4 數組實例的copyWithin()143
8.5 數組實例的find()和findIndex()144
8.6 數組實例的fill()145
8.7 數組實例的entries()、keys()和values()145
8.8 數組實例的includes()146
8.9 數組的空位147
第9章 對象的擴展151
9.1 屬性的簡潔表示法151
9.2 屬性名表達式154
9.3 方法的name屬性156
9.4 Object.is()157
9.5 Object.assign()158
9.5.1 基本用法158
9.5.2 注意點160
9.5.3 常見用途161
9.6 屬性的可枚舉性163
9.7 屬性的遍歷165
9.8 __proto__ 屬性、Object.setPrototypeOf()、Object.getPrototypeOf()166
9.8.1 __proto__ 屬性166
9.8.2 Object.setPrototypeOf()167
9.8.3 Object.getPrototypeOf()168
9.9 Object.keys()、Object.values()、Object.entries()169
9.9.1 Object.keys()169
9.9.2 Object.values()170
9.9.3 Object.entries171
9.10 對象的擴展運算符173
9.11 Object.getOwnPropertyDescriptors()177
9.12 Null傳導運算符181
第10章 Symbol183
10.1 概述183
10.2 作為屬性名的Symbol185
10.3 實例:消除魔術字符串188
10.4 屬性名的遍歷189
10.5 Symbol.for()、Symbol.keyFor()191
10.6 實例:模塊的Singleton模式192
10.7 內置的Symbol值194
10.7.1 Symbol.hasInstance194
10.7.2 Symbol.isConcatSpreadable195
10.7.3 Symbol.species196
10.7.4 Symbol.match197
10.7.5 Symbol.replace197
10.7.6 Symbol.search198
10.7.7 Symbol.split198
10.7.8 Symbol.iterator199
10.7.9 Symbol.toPrimitive200
10.7.10 Symbol.toStringTag201
10.7.11 Symbol.unscopables202
第11章 Set和Map數據結構205
11.1 Set205
11.1.1 基本用法205
11.1.2 Set實例的屬性和方法207
11.1.3 遍歷操作208
11.2 WeakSet212
11.2.1 含義212
11.2.2 語法212
11.3 Map214
11.3.1 含義和基本用法214
11.3.2 實例的屬性和操作方法218
11.3.3 遍歷方法220
11.3.4 與其他數據結構的互相轉換222
11.4 WeakMap225
11.4.1 含義225
11.4.2 WeakMap的語法227
11.4.3 WeakMap示例228
11.4.4 WeakMap的用途229
第12章 Proxy233
12.1 概述233
12.2 Proxy實例的方法237
12.2.1 get()237
12.2.2 set()241
12.2.3 apply()243
12.2.4 has()244
12.2.5 construct()246
12.2.6 deleteProperty()247
12.2.7 defineProperty()248
12.2.8 getOwnPropertyDescriptor()248
12.2.9 getPrototypeOf()249
12.2.10 isExtensible()249
12.2.11 ownKeys()250
12.2.12 preventExtensions()254
12.2.13 setPrototypeOf()255
12.3 Proxy.revocable()255
12.4 this問題256
12.5 實例:Web服務的客戶端258
第13章 Reflect259
13.1 概述259
13.2 靜態方法261
13.2.1 Reflect.get(target, name, receiver)262
13.2.2 Reflect.set(target, name, value, receiver)263
13.2.3 Reflect.has(obj, name)264
13.2.4 Reflect.deleteProperty(obj, name)265
13.2.5 Reflect.construct(target, args)265
13.2.6 Reflect.getPrototypeOf(obj)265
13.2.7 Reflect.setPrototypeOf(obj, newProto)266
13.2.8 Reflect.apply(func, thisArg, args)267
13.2.9 Reflect.defineProperty(target, propertyKey, attributes)267
13.2.10 Reflect.getOwnPropertyDescriptor (target, propertyKey)268
13.2.11 Reflect.isExtensible (target)268
13.2.12 Reflect.preventExtensions(target)269
13.2.13 Reflect.ownKeys (target)269
13.3 實例:使用Proxy實現觀察者模式270
第14章 Promise對象273
14.1 Promise的含義273
14.2 基本用法274
14.3 Promise.prototype.then()278
14.4 Promise.prototype.catch()279
14.5 Promise.all()285
14.6 Promise.race()287
14.7 Promise.resolve()288
14.8 Promise.reject()290
14.9 兩個有用的附加方法291
14.9.1 done()291
14.9.2 finally()292
14.10 應用292
14.10.1 加載圖片292
14.10.2 Generator函數與Promise的結合293
14.11 Promise.try()294
第15章 Iterator和for...of循環297
15.1 Iterator(遍歷器)的概念297
15.2 默認Iterator接口300
15.3 調用Iterator接口的場合305
15.4 字符串的Iterator接口307
15.5 Iterator接口與Generator函數308
15.6 遍歷器對象的return()、throw()309
15.7 for...of循環310
15.7.1 數組310
15.7.2 Set和Map結構311
15.7.3 計算生成的數據結構312
15.7.4 類似數組的對象313
15.7.5 對象314
15.7.6 與其他遍歷語法的比較315
第16章 Generator函數的語法317
16.1 簡介317
16.1.1 基本概念317
16.1.2 yield表達式319
16.1.3 與Iterator接口的關系322
16.2 next方法的參數323
16.3 for...of循環325
16.4 Generator.prototype.throw()328
16.5 Generator.prototype.return()334
16.6 yield*表達式335
16.7 作為對象屬1