LoginSignup
7
7

More than 3 years have passed since last update.

JavaScriptの新しい構文まとめ

Last updated at Posted at 2019-06-24

概要

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

constletで変数を宣言できるようになった。varとは異なりconstletで宣言された変数は block scope1 である。constで宣言された変数は再代入ができず、letは再代入ができる。

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

// 再宣言
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

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

After

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

Template Literal

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

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

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

for ... of

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

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

Default Prameters

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

Before

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

  return x * 2
}

After

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

Rest Parameters

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

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

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

Destructuring

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

Before

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

After

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

Property Definition / プロパティ定義

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

After

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

After

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

Spread Syntax

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

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 で追加)。

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

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

After

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

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

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

Before

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

After


const key = 'foo'
const o = {
  [key]: 1,
}

Class / クラス

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

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したものがアウトプットされる。

// 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 するまで待つ4ようになる。Promiserejectした場合はエラーが発生しtry-catchでキャッチすることができる。

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

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

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

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

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 回のみ) の処理に便利である。詳しくは以下のページを参照されたい。

// 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

  1. block scope とは、ブロック(for文、while文、if文、function () { ... }{ ... }など)の中で宣言されたとき、その中でしか使えない(正確にはその変数名を参照できない)という性質である。逆にvarで宣言された変数は function scope であり、それが宣言された function 内でどこでも参照できる。 

  2. 例えばGoogleAirbnbの style guide でそう指定されている。 

  3. iterable とは、直感的には「値を一つづつ取り出せる」ような object であり、Array がその代表例である。形式的な定義は[Symbol.Iterator]プロパティを持っているオブジェクトである。詳しくはMDNを参照されたい。 

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

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7