ES2016以降のJavaScriptを勉強してないと理解できない記法一覧

知らない人は知らないES2016以降の記法

最近のJavaScriptはES2016以降の仕様について勉強していないと理解できない記法がいくつかある。

ES2015のletやconstやアロー関数程度であればよく見かけるので理解している人は多いが、ES2016以降のものだと認知度が極端に落ちる。

この記事では意外と知らない人が多い、ES2016以降の記法についてまとめました。

べき乗演算子 (**)

ES2016から「**」のべき乗演算子が使用可能。

「**」が使用可能になる前はMath.pow()が使用されていた。

何も知らない人だと「2 * 3」の書き間違いと勘違いされるケースもある。

// 2の3乗の場合

console.log(Math.pow(2, 3))
// => 8

console.log(2 ** 3)
// => 8

Async Function

ES2017から導入されたAsync Function。

awaitと併用して非同期処理に使用することが多い。

async function sample() {
  console.log('開始')
  await new Promise(s => setTimeout(s, 3000))
  console.log('開始から3秒経過')
}
 
sample()

ES2022からはAsync Functionで囲まなくてもawaitが実行可能になった。

console.log('開始')
await new Promise(s => setTimeout(s, 3000))
console.log('開始から3秒経過')

BigInt

数値が大きすぎて表すことができないときに表現したり操作したりするために使用します。

JavaScriptで有効な数値の最大値は9007199254740991 (2 ** 53 - 1)です。

この最大値はNumber.MAX_SAFE_INTEGERで取得することも可能です。

console.log(2 ** 53 - 1)
// 9007199254740991

console.log(Number.MAX_SAFE_INTEGER)
// 9007199254740991

Number.MAX_SAFE_INTEGERに1または2を足すとconsole.logでは9007199254740992と9007199254740993と表示されます。

しかし、JavaScriptでは9007199254740991を超えた場合、9007199254740992と9007199254740993は同じ扱いになるため、trueになってしまいます。

const x = Number.MAX_SAFE_INTEGER + 1
const y = Number.MAX_SAFE_INTEGER + 2
console.log(x === y)
// true

const a = 9007199254740992
const b = 9007199254740993
console.log(a === b)
// true

BigIntを使えば前述のように9007199254740991を超えた場合でも正しく判定できます。

使い方は数値の末尾にnを追加するかBigInt()を使用します。

※ BigInt()はNumberで渡すと精度が落ちるので文字列を使用してください。

const maxSafeInteger = 9007199254740991n
const x = maxSafeInteger + 1n
const y = maxSafeInteger + 2n
console.log(x === y)
// false

const a = 9007199254740992n
const b = 9007199254740993n
console.log(a === b)
// false

const c = BigInt('9007199254740992')
const d = BigInt('9007199254740993')
console.log(c === d)
// false

Numeric Separators

ES2021から使える数値リテラルにアンダースコア( _ )で区切り文字を入れられる。

計算などの処理が完了したあとは区切り文字は除去される。

const a = 1_000_000_000_000
const b = 200_000_000_000
console.log(a + b)
// => 1200000000000

オプショナルチェーン演算子 (?.)

nullish (null または undefined) の場合にエラーではなくundefinedを返すことができる演算子。

例えば以下のコードはtrainer.monster.nameは存在しないためエラーになる。

const trainer = {
  name: 'Satoshi',
  partner: {
    name: 'Pikachu'
  }
}
console.log(trainer.monster.name)

しかしオプショナルチェーン演算子(?.)を使用して以下のように書いた場合はエラーではなくundefinedを返すようになる。

const trainer = {
  name: 'Satoshi',
  partner: {
    name: 'Pikachu'
  }
}
console.log(trainer.monster?.name)

スプレッド構文 (オブジェクト)

スプレッド構文は配列だけに使用されるものだと勘違いされることが多いが、ES2018からはオブジェクトにも使用可能になっている。

const trainer = {
  name: 'Satoshi',
  partner: {
    name: 'Pikachu'
  }
}
const trainerItems = {
  item1: 'monster ball',
  item2: 'bicycle',
}
const trainerStatus = { ...trainer, ...trainerItems }
console.log(trainerStatus)
/*
{
  item1: "monster ball"
  item2: "bicycle"
  name: "Satoshi"
  partner: {name: 'Pikachu'}
}
*/

Null合体演算子 (??)

左辺がnullまたはundefinedの場合に右の値を返し、それ以外の場合に左の値を返す演算子。

const foo = null ?? 'default'
console.log(foo)
// 'default'

const bar = 0 ?? 'default'
console.log(bar)
// 0

「||」はfalse, 0, '', NaN, null, undefinedだと右の値を返すため、nullまたはundefinedのときのみ右の値を返したい場合はNull合体演算子を使用する。

const foo = null || 'default'
console.log(foo)
// 'default'

const bar = 0 || 'default'
console.log(bar)
// 'default'

classのフィールド宣言

従来のJavaScriptは以下のようにconstrutor()内に宣言する必要があった。

class Dog {
  constructor() {
    this.age = 5
  }
}

const dog = new Dog()
console.log(dog.age) // 5

ES2022からはconstructor()なしでも宣言可能になった。

class Dog {
  age = 5
}

const dog = new Dog()
console.log(dog.age) // 5

classのプライベートフィールド宣言

宣言の先頭に「#」を付けることでプライベートフィールド宣言になる。

class Dog {
  #age

  constructor(age) {
    this.#age = age
  }

  showAge() {
    console.log(this.#age)
  }
}

const dog = new Dog(7)
dog.showAge() // 7

// プライベートの宣言なのでdog.#ageはエラーになる
// console.log(dog.#age)

// dog.ageと同一の宣言ではないため以下はundefinedになる
// console.log(dog.age)

export * as name from "./foo.js";

ES2020からモジュールのすべての名前付きのエクスポートをインポートして任意の名前で再エクスポートできるようになった。

ES2020より前は「export * from "./foo.js"」のように書けるが、名前は指定できなかった。