Skip to content

ECMAScript 13 學習筆記

參考學習資源:阮一峰 ECMAScript 6 (ES6) 標準入門教程

類別的新特性

實體屬性的新寫法

ES2022 為類別的實體屬性,又規定了一種新寫法。實體屬性現在除了可以定義在 constructor() 方法裡面的 this上面,也可以定義在類別內部的最頂層。

js
class Person {
  state = {
    a: 1,
    b: 2,
  };

  constructor(name, age) {
    this.name = name;
    this.age = age;
    this.state = {
      a: 1,
      b: 2,
    };
  }
}
const obj = new Person('sheep', 25);

私有屬性和方法

ES2022 正式為 class 新增了私有屬性,方法是在屬性名之前使用 # 表示,這種寫法不僅可以寫私有屬性,還可以用來寫私有方法。

js
class Cache {
  static #count = 0;

  static getCount() {
    return this.#count;
  }

  #obj = {};

  get(key) {
    return this.#obj[key];
  }
  set(key, value) {
    this.#obj[key] = value;
  }
}
const cache = new Cache();
cache.set('name', 'sheep');
console.log(Cache.getCount());

上面程式碼中,#obj 就是私有屬性,只能在 class 的內部使用(this.#obj)。如果在 class 的外部使用,就會報錯。

靜態程式碼區塊

ES2022 引入了靜態區塊(static block),它允許在 class 中透過 static 關鍵字定義一系列靜態程式碼區塊,這些程式碼只會在 class 被創造的時候執行一次

一個 class 可以定義任意多個靜態區塊,這些程式碼區塊會和穿插在它們之間的靜態成員變數一起按照定義的順序在 class 初始化的時候執行一次。我們還可以使用 super 關鍵字來存取父類別的屬性。

js
class Cache {
  static obj = new Map();

  static {
    this.obj.set('name', 'sheep');
    this.obj.set('age', 18);
  }

  static {
    console.log(this.obj);
  }
}

in 運算子

使用 in 可以判斷某個物件是否擁有某個私有屬性。

js
class Cache {
  #obj = {};

  get(key) {
    return this.#obj[key];
  }
  set(key, value) {
    this.#obj[key] = value;
  }

  #privateMethod() {}

  hasObj() {
    return #obj in this;
  }
}

const store = new Cache();
console.log(store.hasObj()); // true

Top-level await

頂層 await 只能用在 ES 模組,不能用在 CommonJS 模組。這是因為 CommonJS 模組的 require() 是同步載入,如果有頂層 await,就沒辦法處理載入了。

早期的語法規定是,await 指令只能出現在 async 函式內部,否則都會報錯。而從 ES2022 開始,允許在模組的頂層獨立使用 await 指令。

js
function ajax() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('data-111');
    }, 2000);
  });
}

const data = await ajax();

export default {
  name: 'moduleA',
  data, // 它會等到 await 完成後才向外 export
};
html
<script type="module">
  console.log('start!');
  import moduleA from './moduleA.js';
  console.log(moduleA);
</script>

上面的程式碼會有一個問題,整個程式碼都會被卡住不執行,直到 moduleA 的資料被傳回來才會執行。

最好的寫法應該是搭配動態 import 來使用:

html
<script type="module">
  console.log('start!');
  const moduleA = await import('./moduleA.js');
  console.log(moduleA);
</script>

陣列的實體方法:at()

長久以來,JavaScript 不支援陣列的負索引,如果要引用陣列的最後一個成員,不能寫成 arr[-1],只能使用 arr[arr.length - 1]

為了解決這個問題,ES2022 為陣列實體增加了 at() 方法,接受一個整數作為參數,回傳對應位置的成員,並支援負索引。

js
const arr = ['A', 'B', 'C', 'D', 'E'];

console.log(arr[0]);
console.log(arr[arr.length - 1]);
console.log(arr[arr.length - 2]);

console.log(arr.at(0));
console.log(arr.at(-1));
console.log(arr.at(-2));

字串也支援 at() 方法:

js
const str = 'sheep';
console.log(str.at(0));  // s
console.log(str.at(-1)); // p
console.log(str.at(-2)); // e

正規比對的開始和結束索引

ES2022 新增了 d 修飾符,這個修飾符可以讓 exec()match()的回傳結果新增 indices 屬性,在該屬性上面可以拿到比對的開始位置和結束位置。

js
const str = '今天是2022-11-24';
const reg = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/d;

const res = reg.exec(str);
console.log(res);

findLast() & findLastIndex()

js
const arr = [11, 12, 13, 14, 15];
arr.find((value) => value % 2 === 0);          // 12
arr.findLast((value) => value % 2 === 0);      // 14
arr.findIndex((value) => value % 2 === 0);     // 1
arr.findLastIndex((value) => value % 2 === 0); // 3

Error 物件的 cause 屬性

Error 物件多了一個 cause 屬性來指明錯誤出現的原因。這個屬性可以幫助我們為錯誤新增更多的上下文訊息,從而幫助使用者們更好地定位錯誤。

js
function getData() {
  try {
    console.log('success', data);
  } catch {
    // throw new Error('傳入參數不符合規則', { cause: '錯誤具體描述' });

    // cause 屬性可以放置任意內容,不必一定是字串。
    throw new Error('傳入參數不符合規則', {
      cause: {
        err: '錯誤資訊',
      },
    });
  }
}

try {
  getData();
} catch (error) {
  console.log(error, error.cause);
}