ES6+ 新語法整理#

ES6(ES2015)是 2015 年發布的 JavaScript 重大更新,引入了 let/const、箭頭函式、classPromise、模組等現代語法,奠定了今日 JavaScript 開發的基礎。 本章整理 ES6 到 ES2022 的常用特性,其中許多語法在前幾章已介紹,這裡做系統性的回顧與補充。


常用 ES6+ 特性速查#

特性版本說明
let / constES6區塊作用域變數
箭頭函式ES6簡潔函式語法
樣板字串ES6字串插值
解構賦值ES6解構陣列/物件
展開運算子ES6... 展開/其餘
classES6類別語法
PromiseES6非同步處理
async/awaitES2017更簡潔的非同步
Object.entriesES2017物件遍歷
??ES2020Nullish Coalescing
?.ES2020Optional Chaining
# 私有欄位ES2022類別私有屬性
Array.at()ES2022負數索引
structuredCloneES2022深拷貝

let 與 const(區塊作用域)#

1
2
3
4
5
6
7
// var 的問題:函式作用域,且有提升
for (var i = 0; i < 3; i++) {}
console.log(i); // 3(var 會洩漏到外面)

// let:區塊作用域
for (let j = 0; j < 3; j++) {}
console.log(j); // ReferenceError(不洩漏)

樣板字串(Template Literals)#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
const name = "世界";
console.log(`你好,${name}!`); // 你好,世界!

// 多行字串
const html = `
  <ul>
    <li>項目一</li>
    <li>項目二</li>
  </ul>
`;

// 標籤樣板(Tagged Templates)
function highlight(strings, ...values) {
    return strings.map((str, i) =>
        str + (values[i] ? `<mark>${values[i]}</mark>` : "")
    ).join("");
}
const result = highlight`搜尋 ${"關鍵字"} 的結果`;

解構賦值(Destructuring)#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 陣列解構
const [a, b, ...rest] = [1, 2, 3, 4, 5];
console.log(a, b, rest); // 1 2 [3, 4, 5]

// 交換變數
let x = 1, y = 2;
[x, y] = [y, x];
console.log(x, y); // 2 1

// 物件解構 + 重新命名 + 預設值
const { name: n = "匿名", age: a = 0 } = { name: "Alice" };
console.log(n, a); // Alice 0

// 函式參數解構
const greet = ({ name, greeting = "你好" }) => `${greeting}${name}!`;
console.log(greet({ name: "Bob" })); // 你好,Bob!

展開與其餘(Spread / Rest)#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 展開陣列
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]

// 複製陣列(淺拷貝)
const copy = [...arr1];

// 展開物件
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }

// 其餘參數
function sum(first, ...others) {
    return others.reduce((acc, n) => acc + n, first);
}
console.log(sum(1, 2, 3, 4)); // 10

箭頭函式(Arrow Function)#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// 等同 function(x) { return x * 2; }
const double = x => x * 2;

// 多個參數
const add = (a, b) => a + b;

// 回傳物件(需加括號)
const toObj = n => ({ value: n });

// 搭配陣列方法
const nums = [1, 2, 3, 4, 5];
const evens = nums.filter(n => n % 2 === 0).map(n => n * 10);
// [20, 40]

類別(Class)#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Animal {
    #name; // 私有屬性(ES2022)

    constructor(name, sound) {
        this.#name = name;
        this.sound = sound;
    }

    speak() {
        return `${this.#name} 說:${this.sound}`;
    }

    get name() { return this.#name; }

    static create(name, sound) {
        return new Animal(name, sound);
    }
}

// 繼承
class Dog extends Animal {
    constructor(name) {
        super(name, "汪汪");
        this.tricks = [];
    }

    learn(trick) {
        this.tricks.push(trick);
    }

    speak() {
        return super.speak() + "!";
    }
}

const dog = new Dog("小黑");
dog.learn("握手");
console.log(dog.speak()); // 小黑 說:汪汪!

模組(Modules)#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// math.js — 具名匯出
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export default function multiply(a, b) { return a * b; } // 預設匯出

// app.js — 匯入
import multiply, { PI, add } from "./math.js";
import * as math from "./math.js"; // 全部匯入

console.log(PI);          // 3.14159
console.log(add(1, 2));   // 3
console.log(multiply(3, 4)); // 12
console.log(math.PI);    // 3.14159

Symbol#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 每個 Symbol 都是唯一的
const id1 = Symbol("id");
const id2 = Symbol("id");
console.log(id1 === id2); // false

// 常用於物件的唯一 key
const user = {
    name: "Alice",
    [Symbol("id")]: 12345
};

Proxy 與 Reflect#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
const handler = {
    get(target, key) {
        console.log(`讀取 ${key}`);
        return key in target ? target[key] : "預設值";
    },
    set(target, key, value) {
        if (typeof value !== "string") throw new TypeError("只接受字串");
        target[key] = value;
        return true;
    }
};

const obj = new Proxy({}, handler);
obj.name = "Alice";    // 設定
console.log(obj.name); // 讀取 name → Alice
console.log(obj.age);  // 讀取 age → 預設值

Reference#