前言
Practical ES6 是 SitePoint 所出版的 the Modern JavaScript Collection 套書中的第一本。該套書共有四本:
- Practical ES6,本文所要介紹的書籍
- Modern JavaScript Tools and Skills
- JavaScript: Best Practice
- 6 JavaScript Projects
JavaScript 已經問世 20 多年了,在這段時間內,JavaScript 和網頁技術產生許多的變化。該系列書籍期望能帶來到西元 2018 年為止的最新實務。Practical ES6 注重的是 JavaScript 語法本身,至於工具鏈或其他的部分,則要參考該系列其他的書籍。
本書共 221 頁,分為 19 章,算是一本輕量級的書籍。我們接下來會逐一介紹各章節。有些讀者可能會想到有些瀏覽器並未完全實作 ES6+ 的特性,我們能把這些新的語法特性套在自己的專案上嗎?透過 Babel 我們可以把 ES6+ 程式碼轉為等效的 ES5 程式碼,故我們可以在專案中使用 ES6+ 特性。Babel 是本系列另一本書 Modern JavaScript Tools and Skill 的重點之一,故本書不重覆篇幅。
Chapter 1: New Keywords let
and const
在 ES5 以前,JavaScript 用 var
宣告變數,但 var
有一些不良的特性:
- 可視域 (scoping)
- 重覆宣告不會引發錯誤
- 無法做為實質上的常數
為了改善這些不良特性,故引入 let
和 const
。除了相容於舊瀏覽器外,應優先使用 let
和 const
。
Chapter 2: Using Map
, Set
, WeakMap
, WeakSet
在 ES5 以前,JavaScript 用物件實字 {}
做為映射 (map) 或集合 (set),但這樣做有一些顯著的缺點:
- 鍵 (key) 一定要是字串
- 無法有效地迭代
- 和內建方法 (method) 相衝突
在 ES6 後引入 Map
和 Set
兩種新的物件,用來改善物件實字的缺點。至於 WeakMap
和 WeakSet
則是在可能出現循環引用的情境中替代 Map
和 Set
的物件,用法上幾無差異。
Chapter 3: New Arrap.*
and Array.prototype.*
Methods
本章簡短地介紹 ES6 中對 Array
物件增強的特性:
Array.from()
Array.prototype.find()
Array.prototype.findIndex()
Array.prototype.keys()
Array.prototype.values()
Array.prototype.fill()
Array
本質上沒有改變,只是多些方法 (method),大略看一下即可。
Chapter 4: New String Methods - String.prototype.*
承續上一章的精神,本章簡短地介紹 ES6 中對 String
物件增強的特性:
String.prototype.startsWith()
String.prototype.endsWith()
String.prototype.includes()
String.prototype.repeat()
String.raw()
由於 String
沒有什麼大幅變動,只是新增一些方法,簡單看一下即可。
Chapter 5: New Number
Methods
承續前面章節的精神,本章簡短地介紹 ES6 中對 Number
物件增強的特性:
Number.isInteger()
Number.isNan()
Number.isFinite()
Number.isSafeInteger()
由此可知,ES6 加入一些 Number
可用的判斷方法,對撰寫程式帶來一些便利性。
Chapter 6: ES6 Arrow Functions: Fat and Concise Syntax in JavaScript
Arrow 函式 (arrow function) 是一個新的語法,主要用於撰寫函式表達式 (function expression)。例如以下函式:
$(document).ready(function () {
// Implement your code here.
});
用純 JavaScript 搭上 arrow 函式改寫如下:
document.addEventListener('DOMContentLoaded', () => {
// Implement your code here.
}, false);
Arrow 函式的用意在讓 JavaScript 的語法更簡潔,但兩者有一些些差異:
this
的作用方式相異- Arrow 函式不能做為建構子 (constructor)
- Arrow 函式不能做為生成器 (generator)
- Arrow 函式沒有 arguments 物件
由於 arrow 函式的用意是讓程式碼簡化,不是必備的功能,讀者可自行決定是否要在專案中使用這項特性。
Chpater 7: Symbols and Their Use
Symbol
是 ES6 引入的新特性,主要是做為獨一無二的 (unique) 符號,但其值不重要。如下例:
let EAST = Symbol(),
WEST = Symbol(),
NORTH = Symbol(),
SOUTH = Symbol();
在 ES5 以前,我們會直接塞入字串或其他值,但那樣做無法表達該變數獨一無二的性質,Symbol
物件的出現,就是為了解決這個議題。本章介紹數個 Symbol
的使用情境,有興趣的讀者可以讀一讀。
Chapter 8: How to Use Proxies
Proxy 是 ES6 的新特性,目的是在 JavaScript 中寫元程式 (meta-programming)。透過 proxy,程式人可以透過程式去修改物件的行為。由於元程式是相對抽象的概念,本章有一些範例,可透過範例來了解如何使用 proxy。
Proxy 包括三個要件:
- Target:Proxy 要修改的物件
- Handler:實作 proxy 的行為的物件,通常是物件實字
- Traps:在 handler 中定義的函式,用來修改 target 的行為。
以下範例摘自 MDN:
var handler = {
get: function(obj, prop) {
return prop in obj ?
obj[prop] :
37;
}
};
var p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 37
在本例中,我們修改 get
函式,當屬性不存時,回傳 37
。
當然,proxy 算是相對困難的技巧,本章提供更多的說明和範例,有興趣的讀者可以讀一讀。由於 proxy 算是進階的特性,無法用 polyfill 來補,也無法用 Babel 來轉,如果專案要支援 Internet Explorer (IE),就應該避開 proxy。
Chapter 9: Destructing Assignment
解構指派 (destructing assignment) 算是一種指派運算的語法糖,透過這項特性可以簡化程式碼。像是以下的陣列:
let [a, b, c] = [3, 4, 5];
或是以下的物件實字:
let {one: a, two: b, three: c} = {one: "eins", two: "zwei", three: "drei"};
由於指派算是一個較小的特性,本章的重點放在各種透過解構簡化程式的情境,可以讀一讀,學習這些小技巧。
Chapter 10: ES6 Generators and Iterators: a Developer's Guide
迭代器 (iterators) 和生成器 (generators) 是相當實用的特性。迭代器的使用方式如下:
for (const element of collection) {
// Do something here.
}
在 ES6 之後,我們可以不用索引來迭代容器,可以直接走訪容器。
生成器是用來產生迭代器的函式,例如下列用來生成費伯那西數的生成器:
function* getNextFib() {
let a = 0;
let b = 1;
let c;
while (true) {
yield a;
c = a + b;
a = b;
b = c;
}
}
const fib = getNextFib();
for (let i = 0; i < 10; i++) {
console.log(fib.next().value);
}
本章對迭代器和生成器有較詳細的說明,有興趣的讀者可以讀一下。
Chapter 11: Object-Oriented JavaScript: A Deep Dive into ES6 Classes
class
算是 ES6 裡主要的新增特性之一。JavaScript 的物件是以原型 (prototype) 為基礎,引入 class
並不代表物件系統有所改變,而是用更好的語法來實作物件。在 ES6 之後,就不建議用舊有的建構函式那套手法來建立物件,除非是要維護舊專案。本章介紹數個 class
相關的議題:
- 新式建構子 (constructor)
- 建立私有屬性的手法
- 靜態屬性和方法
- 繼承 (單一繼承)
- 達成多重繼承的手法
這章算是值得一讀的章節。
Chapter 12: Understand ES6 Modules
模組算是 ES6 引入的新特性,原本的 JavaScript 的模組如下:
- 網頁前端
- 網頁後端
- CommonJS
- 用 bundler 將 JavaScript 程式碼打包成單一命令稿,像是 webpack
- 網頁前後端通用
前述所提的都是在 ES6 模組出現前的一些 JavaScript 的模組機制。本章介紹如何在專案中加入模組。
雖然 ES6 模組立意良好,但模組會造成專案架構的改變,且有一定比例的瀏覽器不支援模組 (參考這裡),勢必要寫退路 (fallback)。甚至本書作者也建議在現階段的專案中,不一定要急著加入模組,等過一陣子模組更普遍再使用也不遲。
Chapter 13: An Overview of JavaScript Promises
Promises 是 ES6 裡重要的新特性,由於 JavaScript 程式以非同步模式來運行,有時會寫出複雜、難維護的回呼 (callback) 程式;透過 promises 可使得程式碼更簡潔易讀,一些常見的情境就是包裝 AJAX 程式,jQuery 新版本中也加入以 promise 為基礎的 API 呼叫,如下例:
var jqxhr = $.post( "example.php", function() {
alert( "success" );
})
.done(function() {
alert( "second success" );
})
.fail(function() {
alert( "error" );
})
.always(function() {
alert( "finished" );
});
本章中有更多 promise 的寫法,有興趣的讀者可以讀一讀。Promise 讓程式碼更易寫易讀,是值得學習的新特性。
Chapter 14: JavaScript Decorators: What They are and When to Use Them
Decorator 在 Angular 和 TypeScript 中很流行,但在 JavaScript 中這項特性還沒穩定下來 (參考這裡),故筆者目前不建議使用這樣特性。有興趣的讀者可以自行閱讀。
Chapter 15: Enhanced Object Literals
本章介紹一些在 ES6 以後對於物件實字 {}
的增強:
- 直接從變數初始化物件
- 從物件實字建立函式的語法糖
- 動態屬性 (dynamic property)
- 物件解構 (object destructing)
- Rest/spread 屬性
這章有些內容和其他章節有一些重覆,可能有些內容很難歸類所造成。
Chapter 16: Introduction to the Fetch API
Fetch API 是新的抓取數據的 API,有點像先前的 XMLHttpRequest
物件,但加入一些新的功能,像是跨網域存取 (CORS) 及 HTTP origin 標頭等。本章介紹如何以 fetch API 搭配 promise 或 async
/await
,另外介紹 fetch API 發生錯誤的處理方式。
雖然部分瀏覽器不支援 fetch API 但有 polyfill 可用,除了要支援較舊的瀏覽器外,應該可以放心使用此 API。
Chapter 17: ES6 (ES2015) and Beyond: Understand JavaScript Versioning
本章較偏歷史面及政策面,技術含金量相對低。一開始講到 JavaScript 的由來及標準化的過程,之後介紹一個語言的提案 (proposal) 制定的過程。本章的重點是看懂 JavaScript 的版本號:
(補充表格)
- N/A、ECMAScript 1、N/A
- N/A、ECMAScript 2、N/A
- N/A、ECMAScript 3、N/A
- N/A、ECMAScript 5、ES5
- ES2015、ECMAScript 2015、ES6
- ES2016、ECMAScript 2016、ES7
- ES2017、ECMAScript 2017、ES8
- ES2018、ECMAScript 2018、ES9
註:ECMAScript 4 遭廢棄而未發布。
我們在談現代 JavaScript 是指 ES6 之後所新增的語法特性;相對來說,ES5 會當成瀏覽器實作的最低版本,也是 Babel 轉換的目標版本。
Chapter 18: What's New in ES2017: Async Functions, Improved Objects, and More
本章簡短地介紹 ES2017 帶來的新特性:
async
和await
Object
的新方法 (methos),包括Object.values()
、Object.entries()
、Object.getOwnPropertyDescriptors()
等- 字串的新方法,包括
padStart()
和padEnd()
等
ES2017 最重要改變的是 async
語法,可以讓非同步程式寫起來更簡潔,其他的部分簡單看一下即可。
Chapter 19: What's New in ES2018
承續上一章,本章簡短地介紹 ES2018 的新特性:
- 非同步迭代 (asynchronous iteration)
Promise.finally()
- 用於物件解構 (object destructing) 的 rest/spread 語法
- 一些對正規表示式的小幅強化
由此可看出,ECMAScript 持續改善非同步程式的寫法。
結語
由本書的寫作方式可看出,本書比較適合已經會一些些 JavaScript 但想幫自己充電的程式人;對於程式新手或是完全不懂 JavaScript 的讀者來說,本書讀起來可能會過於吃力,而且無法理解為什麼 JavaScript 要引入這些新特性。
本書的範例是典型的西方式寫法,沒有完整的範例而是短小的程式碼片段 (code snippets)。對於有經驗的程式人來說,這樣的書很容易抓到重點,但初學者可能覺得這樣的寫作方式過於困難。除了針對完全新手的書籍外,大部分書籍都會採用這種寫作方式,要慢慢習慣。
本書承襲 SitePoint 系列書籍輕薄短小的特性,閱讀一次應該不會花太久的時間。但 JavaScript 有許多的議題,僅以 200 多頁的份量是無法完整交待的,所以 the Modern JavaScript Collection 這個系列以四本書的容量來介紹 JavaScript,讀者可視自己的需求單獨購買或成套購買。