JavaScriptの"仕様にまだ導入されていない新機能"紹介

# 概要

ECMAScript の仕様は TC39 という組織によって決められているが、この記事ではまだ ECMAScript の仕様に導入されていないが TC39 が proposal (提案)として認めている新機能(ESNext とも呼ばれる)をいくつか紹介する。各見出しは該当の GitHub ページにリンクされている。

今すぐこれらの機能を使いたい場合は babel の [plugin](https://babeljs.io/docs/en/plugins) を使用するのがいいだろう。また、ブラウザの中でも特に Google Chrome は新機能の実装に積極的であり、仕様に導入される前の proposal を早めに Chrome に実装することがよくある。これについて最新情報を知りたい場合は [@ChromiumDev](https://twitter.com/ChromiumDev) を見ればよいだろう。

proposal ごとに stage (「提案されただけの段階」から「仕様に導入された段階」までのどれくらいの進捗度かを表す)が割り振られているが、今後変わっていくものであるためここでは書かない。stage ごとの一覧は以下のページで見られる。

- [ECMAScript proposals](https://github.com/tc39/proposals)



# [Optional Chaining](https://github.com/tc39/proposal-optional-chaining)

ネストされたオブジェクトの深いプロパティに安全にアクセスしたいとき、一段階深く行くたびに `undefined` や `null` であるかどうかチェックする必要がある(なぜなら `undefined` や `null` のプロパティにアクセスしようとするとエラーが発生する)が、optional chaining ではその必要がなくなる。

Swift の同名の operator や C# の null-conditional operator に類似している。名前の由来はおそらくその Swift のものであり、`Optional`型の値から`Optional`型の値を得る operator であるため chain (連ねて使用すること)できるからだと思われる。

例えば `o.a.b.c` にアクセスしたいとき、以下のように、まず `o` が nullish (`undefined` か `null`)であるかチェックし、次に `o.a` が nullish であるかチェックし...と冗長なコードになってしまう。

**Note:** `x == null` は `x` が nullish のときのみ `true` になることに注意。

```js
const o_a_b_c = (o == null || o.a == null || o.a.b == null) ? undefined : o.a.b.c
```

optional chaining により次のように簡潔に書ける。

```js
const o_a_b_c = o?.a?.b?.c
```

key を expression で指定するプロパティアクセスや関数呼び出しもできる。

```js
o?.[propName]  // o == null ? undefined : o[propName]
f?.(arg)       // f == null ? undefined : f(arg)
```

# [Nullish Coalescing](https://github.com/tc39/proposal-nullish-coalescing)

何らかの値が `null` か `undefined` である場合は代わりに何か自分の指定したデフォルト値を使用したいということがある。nullish coalescing はこれを簡潔に書くためのシンタックスである。nullish coalescing と呼ばれる理由は、左に nullish な値があると右の値と融合(coalescing)させられて結果一つの値となるからである。

Before

```js
// o.a が null か undefined なら代わりに 1 を使用する
const o_a = o.a == null ? 1 : o.a
```

After

```js
const o_a = o.a ?? 1
```

先述の optional chaining と組み合わせると、JSON形式のレスポンスから何らかの値を取り出したいときに便利だろう。

```js
const posts = response?.data?.user?.[0]?.posts ?? []
```

**Note:** 同様の目的でよく使われる `||` は、左の値が [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) (Boolean に変換すると `false` になる値) であれば右の値が使われてしまうという点で `??` とは異なる。

```js
const o = {
  a: 0,
  b: false,
  c: ''
}

o.a || 10  // 10
o.b || 10  // 10
o.c || 10  // 10

o.a ?? 10  // 0
o.b ?? 10  // false
o.c ?? 10  // ''
```




# [Promise.allSettled](https://github.com/tc39/proposal-promise-allSettled) & [Promise.any](https://github.com/tc39/proposal-promise-any)

どちらも複数の promise を受け取る関数だが、`Promise.allSettled` は**すべての promise が settle (resolve または reject すること)した時点で resolve** し、`Promise.any` は**いずれかの promise が resolve した時点で resolve し、すべて reject した時点で reject する**。既存の `Promise.all` や `Promise.race` と比較すると以下のようになる。

| |`Promise.allSettled`|`Promise.any`|`Promise.all`|`Promise.race`|
| ----- | ---- | ----------- | ----------- | ----------- |
| resolve するタイミング | すべての promise が settle | いずれかの promise が resolve | すべての promise が resolve | いずれかの promise が resolve |
| resolve の値 | * | そのまま | resolve 値の配列 | そのまま |
| reject するタイミング | なし | すべての promise が reject | いずれかの promise が reject | いずれかの promise が reject |
| reject の値 | - | reject 値の配列 | そのまま | そのまま |

(settle = resolve か reject すること)


\* `Promise.allSettled` の resolve 値は、各 promise の最終的な状態(resolve/reject とその値)を表すオブジェクトの配列となる。

```js
const p1 = Promise.resolve(1)
const p2 = Promise.reject(">_<")

Promise.allSettled([p1, p2]).then(console.log)
// [
//   { status: 'fulfilled', value: 1 },
//   { status: 'rejected', reason: '>_<' }
// ]
```

# [do Expression](https://github.com/tc39/proposal-do-expressions)

`do { ... }` ブロック内で最後に実行された statement (文)の値が `do` ブロック全体の値となる。これにより、一つの値を求めるいくつかの statement を一つの expression にまとめることができ、(途中で使った)変数のスコープを狭く抑えることもできる。

Scala などでは通常のブロック `{ ... }` が同じ機能を持つ。

```js
const x = 5
const result = do {  // result === 2
  if (x > 10) {
    1
  } else if (x > 0) {
    2
  } else {
    3
  }
}

const a = do {  // a === 5
  const b = 3
  const c = 4
  const a_squared = b * b + c * c
  Math.sqrt(a_squared)
}
```

# [Pipeline Operator](https://github.com/tc39/proposal-pipeline-operator)

ある値 `x` に function `f1` を適用し、その返り値に `f2` を適用し...と繰り返したいとき、`fn(...(f2(f1(x)))...)` と書けば、function が右から左に並び、括弧も多くなるので可読性が低下する。pipeline operator `|>` により以下のように簡潔に書けるようになる。

F# や OCaml に同じ operator がすでに存在し、bash の pipe `|` も似た機能を持っている。pipeline と呼ばれるのは、function はものを入れると反対から何かが出てくるパイプのようなものとみなして、function をつなげてより大きな function、すなわちパイプラインを構成するというイメージがあるからである。

```js
const result = x |> f1 |> f2 |> f3  // result === f3(f2(f1(x)))
```

# [Partial Application](https://github.com/tc39/proposal-partial-application)

function に対して引数を渡して実行することを apply (名詞: application) というが、functional programming (関数型プログラミング)の界隈では複数の引数を取る function に対して引数を partial (部分的)に与えて新たな function を得ることを parital application という。この proposal はこの機能の JavaScript 版である。

```js
function sum(a, b, c) {
  return a + b + c
}

const sumWith3 = sum(?, 3, ?)
console.log(sumWith3(1, 2))          // 6
const sumWith3And5 = sumWith3(5, ?)
console.log(sumWith3And5(8))         // 16
```

先述の pipeline operator を使用するときに便利である。

```js
const result = x
  |> f1
  |> f2(?, 3)
  |> f3(4, ?, 5)

// f3(4, f2(f1(x), 3), 5) と等価
```

**Note:** `this` を内部で使用している function について、わざわざ `bind` する必要はない。`obj.f(?)(3)` は `obj.f(3)` と等価である。

# [Class Fields](https://github.com/tc39/proposal-class-fields)

クラスのフィールド(他のオブジェクト指向言語でいうところのインスタンス変数)を Java などと同じように `constructor` の外で宣言できるようになる。

Before

```js
class C {
  constructor() {
    this.c = 0
  }
}
```

After (**完全に等価なコードではない**)

```js
class C {
  c = 0  // class field
}
```

**Note:** 上2つのシンタックスには機能的な違いがある。実は後者は内部的には `Object.defineProperty()` によって data property[^acc] として定義される。これがどのような違いを生むかと言うと、例えば次のように accessor property[^acc] をもったクラスを継承するときに、新しいシンタックスだとそのプロパティが data property へと上書きされてしまう。

```js
class C {
  // accessor property
  get a() {
    return 10
  }
  set a(value) {
    console.log("setter called")
  }
}

// Beforeの方
class D extends C {
  constructor() {
    super()
    this.a = 1
  }
}

const d = new D() // "setter called"が出力される
d.a = 2           // ここでも出力される

// Afterの方
class E extends C {
  a = 1
}

const e = new E() // "setter called"が出力されない
e.a = 2           // ここでも出力されない
```

[^acc]: data property は`{ prop: 1 }`のようにして作られる通常のプロパティであるのに対し、accessor property とは getter と setter によって定義されたプロパティである。

# [Private Fields](https://github.com/tc39/proposal-class-fields#private-fields)

先述の class field について、`#`を先頭につけることで外からアクセスできない private な field となる。Java や C# における private instance variable に相当する。

```js
class Counter {
  #c = 0  // private field

  get count() {
    return this.#c
  }

  increment() {
    this.#c++
  }
}

const c = new Counter()
console.log(c.count)  // 0

c.increment()
console.log(c.count)  // 1

console.log(c.#c) // SyntaxError
```

子クラスから親クラスの private field にはアクセスできない。

```js
class C {
  #a = 0
}

class D extends C {
  printa() {
    console.log(this.#a)  // Syntax Error
  }
}
```

ただし、同じクラスの他のインスタンスの private field にはアクセスできる。

```js

class C {
  #a = 0

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

  printa() {
    console.log(this.#a)
  }

  add(other) {
    return new C(this.#a + other.#a)
  }
}

const c1 = new C(1)
const c2 = new C(2)
const c3 = c1.add(c2)
c3.printa()  // 3
```

# [Private Methods & Getter/Setters](https://github.com/tc39/proposal-private-methods)

先述の private field と同様に method や getter/setter にも`#`をつけることで private にできる。

```js
class C {
  get #a() {
    return 1
  }
  set #a(value) {
  }

  #method() {
  }
}
```

# [Static Fields & Methods](https://github.com/tc39/proposal-static-class-features/)

`static` をつけることで (public) field、private field、private method を static (インスタンスではなくクラスのプロパティ)にできる。Java や C# における static variable/method に相当する。public static method はすでに ECMAScript 2015 で導入されている。

```js
class A {
  static publicStaticVar = 4
  static #privateStaticVar = 4

  static #privateStaticMethod() {
    return 4
  }
}
```