位元詩人 [書籍回顧] Practical ES6 評價

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

前言

Practical ES6 是 SitePoint 所出版的 the Modern JavaScript Collection 套書中的第一本。該套書共有四本:

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)
  • 重覆宣告不會引發錯誤
  • 無法做為實質上的常數

為了改善這些不良特性,故引入 letconst。除了相容於舊瀏覽器外,應優先使用 letconst

Chapter 2: Using Map, Set, WeakMap, WeakSet

在 ES5 以前,JavaScript 用物件實字 {} 做為映射 (map) 或集合 (set),但這樣做有一些顯著的缺點:

  • 鍵 (key) 一定要是字串
  • 無法有效地迭代
  • 和內建方法 (method) 相衝突

在 ES6 後引入 MapSet 兩種新的物件,用來改善物件實字的缺點。至於 WeakMapWeakSet 則是在可能出現循環引用的情境中替代 MapSet 的物件,用法上幾無差異。

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 帶來的新特性:

  • asyncawait
  • 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,讀者可視自己的需求單獨購買或成套購買。

關於作者

身為資訊領域碩士,位元詩人 (ByteBard) 認為開發應用程式的目的是為社會帶來價值。如果在這個過程中該軟體能成為永續經營的項目,那就是開發者和使用者雙贏的局面。

位元詩人喜歡用開源技術來解決各式各樣的問題,但必要時對專有技術也不排斥。閒暇之餘,位元詩人將所學寫成文章,放在這個網站上和大家分享。