JavaScriptの新しい構文まとめ

## 概要

JavaScript には年々新しいシンタックスが追加されている。それらを活用すればコードが簡潔になる、読みやすくなる、バグを回避できるなどのメリットがある。IE などのブラウザでは使用できないこともあるが、babel などの transpiler や polyfill を使用することで解決できる(そもそも「モダン」でないブラウザは使用されるべきではないが)。以下に最近の JavaScript (正確には ECMAScript)のバージョンで追加されたシンタックスを紹介する。それ以外の method (`Object.entries()`など) などについてはここでは紹介しない。

## ECMAScript 2015 (ES6)

ECMASCript 2015 では非常に多くのシンタックスが追加され、それらをフルに使いこなせばそれ以前のコードと見比べると別言語にすら見えると感じる。const と let によりバグの少ないコードが書きやすくなり、arrow function は functional programming をしやすくし、class の導入は Java などのオブジェクト指向言語に慣れている人たちに喜ばれるものと思われる。また、object や array の作成、分解がしやすくなるよう様々な構文が追加された。

### const & let

`const`や`let`で変数を宣言できるようになった。`var`とは異なり`const`や`let`で宣言された変数は block scope[^1] である。`const`で宣言された変数は再代入ができず、`let`は再代入ができる。

最近では、基本的に`const`を使って変数を宣言し、再代入をする必要があるときのみ`let`を使い、`var`は使わないというスタイルが推奨されることが多い[^style]。

[^1]: block scope とは、ブロック(`for`文、`while`文、`if`文、`function () { ... }`、`{ ... }`など)の中で宣言されたとき、その中でしか使えない(正確にはその変数名を参照できない)という性質である。逆に`var`で宣言された変数は function scope であり、それが宣言された function 内でどこでも参照できる。
[^style]: 例えば[Google](https://google.github.io/styleguide/jsguide.html)、[Airbnb](https://github.com/airbnb/javascript)の style guide でそう指定されている。

```js
// 再宣言
var a = 3
var a = 4 // エラーにならない

let b = 3
let b = 4 // Uncaught SyntaxError

const c = 3
const c = 4 // Uncaught SyntaxError

// スコープ
if (true) {
  var a = 3
}
console.log(a) // 3

if (true) {
  let b = 3
}
console.log(b) // Uncaught ReferenceError

// 再代入
var a = 3
a = 3

let b = 3
b = 3

const c = 3
c = 3 // Uncaught TypeError
```

### Arrow Function

function expression (`function () {}`) をより短い形で書ける。しかし機能的な違いもあり、function expression 内の`this`の値は呼び出され方によって変わるのに対し、arrow function 内の`this`は外の`this`と常に同じとなる。この性質は、例えばオブジェクト A のメソッドの中で作った function 内から A を参照したい時に便利である。ちなみに arrow という名前は`=>`が文字通り arrow(矢印)に見えるからである。他言語ではラムダ式とも呼ばれる。

Before

```js
const f = function(x) {
  return x * 2
}
```

After

```js
const f = x => {
  return x * 2
}
// return文だけの場合 {} と return を省略できる
const f = x => x * 2
```

### Template Literal

クオート(`"`や`'`)ではなくバックティック(`` ` ``)で囲むことにより、string の literal に直接変数や式の値を埋め込んだり、複数行の文字列を作ることができる。複数行に渡る場合は、インデントも文字列に含まれることに気をつける必要がある。

```js
const x = 3
const equation = `2x = ${x * 2}` // "2x = 6"

const program = `function () {
  return 3
}` // "function () {\n  return 3\n}"
```

### for ... of

Array などの iterable[^4]な object について、それに含まれる値を一つづつ処理できる。

[^4]: iterable とは、直感的には「値を一つづつ取り出せる」ような object であり、Array がその代表例である。形式的な定義は`[Symbol.Iterator]`プロパティを持っているオブジェクトである。詳しくは[MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterable_protocol)を参照されたい。

```js
let sum = 0
for (const x of [33, 67]) {
  sum += x
}
console.log(sum) // 100
```

### Default Prameters

function の parameter(引数)のデフォルトの値を指定できる。該当の引数が指定されないとき、あるいは`undefined`が指定されたとき、デフォルト値が代わりに使用される。

Before

```js
function double(x) {
  if (x === undefined) {
    x = 0
  }

  return x * 2
}
```

After

```js
function double(x = 0) {
  return x * 2
}
```

### Rest Parameters

function の引数で、「残り(rest)すべて」を配列として受け取ることができる。他言語でいう可変長引数のシンタックスに似ている(JS の function はいつでも任意個の引数を受け取れるという点で特殊ではあるが)。

```js
function f(a, b, ...rest) {
  console.log(rest)
}

f(1, 2, 3, 4, 5) // [3, 4, 5]
```

### Destructuring

Array の要素を取り出して変数に取り出す時に短く書ける。"structure" は組み立てる、構造を作るという意味で、意味を逆にする接頭辞 "de-" がつくことにより、構造をもつものをバラバラに分解する、という意味になる。

Before

```js
const arr = [10, 20, 30, 40]
const first = arr[0]
const second = arr[1]
const rest = arr.slice(2)
```

After

```js
const arr = [10, 20, 30, 40]
const [first, second, ...rest] = arr
```

### Property Definition / プロパティ定義

オブジェクトの property の literal でキーと、値として指定された変数名が一致するとき短く書ける。

After

```js
const a = 1
const b = 2
const o = {
  a: a,
  b: b,
}
```

After

```js
const a = 1
const b = 2
const o = {
  a,
  b,
}
```

### Spread Syntax

rest parameters は受け取る側で複数のものをまとめるものであるのに対し、spread(広げる、ばら撒く) syntax は渡す側で array などの iterable[^4]をバラバラにするものである。

```js
function middle(x, y, z) {
  return y
}
const arr = [2, 3]
console.log(middle(1, ...arr)) // 2

const arr2 = [1, ...arr] // [1, 2, 3]
```

object の literal では iterable ではなく object を spread することができる(ECMAScript 2018 で追加)。

```js
const o1 = { a: 1, b: 2 }
const o2 = { c: 3, d: 4 }
const o3 = {
  ...o1,
  ...o2,
  e: 5,
}
console.log(o3) // { a: 1, b: 2, c: 3, d: 4, e: 5 }
```

### Method Definition / メソッド定義

オブジェクトの property として function expression を書くときに短く書ける。

Before

```js
{
  bla: function (x) {
    // ...
  }
}
```

After

```js
{
  bla(x) {
    // ...
  }
}
```

### Computed property name / 動的なプロパティ名

オブジェクトの literal にて key に expression を指定できる。

Before

```js
const key = 'foo'
const o = {}
o[key] = 1
```

After

<pre>
const key = 'foo'
const o = {
  &#91;key&#93;: 1,
}
</pre>

### Class / クラス

オブジェクト指向言語でお馴染みのクラスを使用できるようになった。しかし内部的には以前からある prototype が用いられていることに注意する必要がある。クラスについては説明すべき機能や性質が多すぎるため、ここでは割愛する。

```js
class Vector2D {
  // コンストラクタ
  constructor(x, y) {
    this.x = x
    this.y = y
  }

  // 長さを返すメソッド
  magnitude() {
    const { x, y } = this
    return Math.sqrt(x ** 2 + y ** 2)
  }
}

const vec = new Vector2D(3, 4)
console.log(vec.magnitude()) // 5
```

### Generator Function

iterable を生成する function を簡単に作るためのシンタックスである。リクエストされるたびに一つづつ値を返すため、うまく使えばメモリ効率のよいプログラムとなる。通常の function expression あるいは function declaration に「`*`」をつけることで、その中で`yield`を使用できるようになり、`yield`したものがアウトプットされる。

```js
// python の range と同等
function* range(end) {
  for (let i = 0; i < end; i++) {
    yield i
  }
}

for (const x of range(5)) {
  console.log(x)
}
// 0
// 1
// 2
// 3
// 4
```

## ECMAScript 2017 (ES8)

ECMAScript 2017 で追加された主なシンタックスは async/await のみである。

### async/await

`Promise`ベースの非同期処理を、あたかも同期処理であるかのように書くことができ、これにより非同期処理が非常に書きやすくなる。`async`をつけた function 内では`await`が使えるようになり、`await`の右においた`Promise`が resolve するまで待つ[^5]ようになる。`Promise`が`reject`した場合はエラーが発生し`try-catch`でキャッチすることができる。

[^5]: 待つといっても`while(true){}`のようにそこで JavaScript の処理が止まるわけではなく、他にやることがあれば実行される。実は`await x`と書くことは、`Promise`に対して`.then()`でコールバックを設定することと本質的に同じである。

```js
async function fetchPosts() {
  const posts = await fetch('/posts').then(res => res.json())
  return posts
}

async function logPosts() {
  const posts = await fetchPosts()
  console.log(posts)
}
```

## ECMAScript 2018

### Rest/Spread Properties

ECMAScript 2016 では Array の Spread Syntax や Rest Syntax が追加されたが、これは Object の property についての同様のシンタックスである。

Before

```js
const person = {
  age: 10,
  name: 'John',
  job: 'programmer',
  weight: '60kg',
}
const age = person.age
const name = person.name
const rest = {
  job: person.job,
  weight: person.weight,
}
```

After

```js
const person = {
  age: 10,
  name: 'John',
  job: 'programmer',
  weight: '60kg',
}
const { age, name, ...rest } = person
```


これらは function expression や arrow function の parameter でも使える。

```js
const extractName = ({ name }) => name
console.log(extractName({ name: 'John' })) // John
```

### Async Generator Function & for await ... of

for ... of は iterable の要素を一つづつ処理するものだが、for await ... of は async iterable の要素を処理する。`await`と同様に async function 内でのみ使用できる。直感的には async iterable とは、iterable とは異なり「非同期に」要素を一つづつ取り出せるものである。フォーマルに言うと`Symbol.asyncIterator`プロパティをもつオブジェクトである。

async iterable を手軽に作るシンタックスとして async generator function がある。簡単に言えば generator function の非同期バージョンであり、リクエストされるたびに yield のところまで実行される。

両者は stream (非同期に任意回数、値を発するデータ構造; 対して`Promise`は 1 回のみ) の処理に便利である。詳しくは以下のページを参照されたい。

- [Asynchronous Iterators for JavaScript](https://github.com/tc39/proposal-async-iteration)

```js
// time ミリ秒待つ Promise
function sleep(time) {
  return new Promise(resolve => {
    setTimeout(() => resolve(), time)
  })
}

// 間隔 interval で 0 から end まで出力する
async function* rangeInterval(end, interval) {
  for (let i = 0; i < end; i++) {
    await sleep(interval)
    yield i
  }
}

!(async () => {
  for await (const x of rangeInterval(5, 1000)) {
    console.log(x)
  }
})()
// 1秒間隔で以下が出力される
// 0
// 1
// 2
// 3
// 4
```