LoginSignup
189
244

More than 5 years have passed since last update.

ES6(ES2015)チートシート

Last updated at Posted at 2017-06-12

素のままのJavaScript(ES5)に直接触れる機会もだんだんと減ってきたので、うろ覚えだったES6の機能をまとめてみました。
なお文中のコードはBabel環境で書きながら確認したため、現行ブラウザでの直接の対応状況に関しては未調査です。

概要

ECMAScriptS6 = ES2015 = JavaScriptの新しいバージョン

  • ES5(現行のjs)の次のバージョンとして策定された
  • さらに新しいES7も作られている

現状は多くのブラウザが(部分的にしか)対応していないので、ES6で書いたコードを動かすためにはES5への変換(トランスパイル)が必要になる。
トランスパイル用のツールとしてはBabelが代表的な実装になる。

具体的な利用方法としては:

  • ES6をサポートしているブラウザを使う

    • 現状、サポートは部分的かつ挙動に差異がある
  • babelのCLIを使って直接トランスパイルする

  • webpack, browserify, sprocketsなどがバンドルを作成する過程にBabelを組み込む

  • Bebel/browser.jsを使って表示のたびにトランスパイルする(デバッグ用)

など。

導入方法は以前React-Redux環境構築の際に調査済なので、今回は省略する。
(React-Redux on Rails(w/webpack/yarn)環境を作ったメモ)

構文の追加/変更

モジュール(import/export)

CommonJSなどサードパーティレベルで実現していたファイル分割/依存関係解決の機能が標準機能となった。
あるモジュール(ファイル)からexportしたクラス・変数・定数・関数を、他のモジュールがimportするかたちで使う。

import/exportの指定方法は復数あるので詳細はMDNなどを参照のこと。

exportする例

// 変数・定数・関数を、名前を指定して直接出力する
export let someVariable = ...
export const SOME_CONST = ...
export const someFunc = () => {
  ...
}

// デフォルト(ファイル=モジュールにひとつ)として出力する
export default class SomeClass{
  ...
}
importする例

// モジュール内の全てをSomeModuleにバインドする
import * as SomeModule from 'path/to/module'

// デフォルトを名前空間SomeModuleにバインドする
import SomeModule from 'path/to/module'

// モジュールをバインドせずにロードだけする
import 'path/to/module'

// モジュール内のfooとbarだけロードする
import {foo, bar} from 'path/to/module'

変数と定数(let/const)

varの代替として、letconstを変数の宣言時に使える。

constで宣言すると定数となり、変更できない。
(Babel環境の場合はトランスパイル時に静的なエラーとなる

letの機能はvarと同じ。
constの対比として、変更できることを明示する意味合いで使う。

let foo = 'foo'
const bar = 'bar'

// OK
foo = 'hoge'

// Error
bar = 'piyo'

クラス(class/extends/super/static)

クラス定義を構文レベルでサポートする。
(シンタックスシュガーにすぎないので、内部的には従来のプロトタイプベース構造から変わっていないとのこと)

class Foo extends SomeSuperClass{

  // コンストラクタ
  constructor(bar, baz){

    // 親クラスのメソッドが呼べる
    super()

    // インスタンス変数はコンストラクタ内で定義する(これまでと同じ)
    this._bar = baz
    this._baz = baz
  }

  // インスタンスメソッド
  bar(){
    return this._bar
  }

  // クラスメソッド
  static foo(){
    return 'FOO'
  }
}

let foo = new Foo('BAR', 'BAZ')
console.error(foo.bar())
console.error(Foo.foo())

オブジェクト定義の簡略化

オブジェクト定義の構文が強化された。

let magicKey = 'foo'

let obj = {
  // プロトタイプを指定する
  __proto__: theProtoObj,

  // キー名を省略できる(foo: foo, と同義)
  foo,

  // メソッドを簡単に書ける
  someMethod(){
    // クラスと同様にsuper()を呼べる
    super()
  },

  // 動的なキーを使う(obj.foo)
  [ magicKey ]: 'magic value'
}

アロー関数(=>)

関数定義の省略記法として()=>が使える。
アロー関数中のthisは、その外側のスコープのthisに等しい(いわゆるselfを定義しなくていい)

// 基本形
let allowFunc = () => {
  // ...
}

// 外側のthisを参照できる
var someObj = {
  _someParam: '...',

  getSomeParam(){
    return () => {
      this._someParam  // ここでのthisはsomeObj
    }
  },
}

// 単行の場合は省略可能
let simpleFunc = () => otherFunc()

// 引数がひとつの場合は括弧も省略可能
let funcWithArg = arg => otherFunc(arg)

テンプレート文字列(${})

文字列中に変数を埋め込んで、その内容を展開できる。
テンプレート文字列は\`で囲む。

(ちなみにmarkdownでよく使うこの文字は、グレイヴ・アクセントというらしい)

const foo = 'foo'
const bar = 'bar'
const baz = () => {
    return 'baz'
}

// 変数を展開する
const foobar = `${foo}, ${bar}`

// 式の評価もできる
const some = `${baz()}`

2進/8進リテラル(0b/0o)

2進数、8進数をリテラルとして表現できるようになった。

let bin = 0b1001    // 2進
let oct = 0o11      // 8進
let dec = 9         // 10進
let hex = 0x09      // 16進

デフォルト / 可変長引数(=/...)

引数にデフォルト値を設定できるようになった。
また可変長にも対応した。

// デフォルトをとる
function add(x, y=0){
  return x + y
}
add(3)
add(4, 5)


// 可変長引数をとる
function sum(...args){
  return args.reduce(function(count, val){
    return count + val
  }, 0)
}
sum(1, 2, 3)

コレクションの繰り返し(for-of)

繰り返しの制御構文としてfor-of文が追加された。

既存のfor-in との違いは、オブジェクト以外のコレクション(Array, Map, Set, Iterator, String)にも対応していること。
また後述のイテレータを回すこともできる。

// 配列を回す(for-in): for-inなので"インデックス"が"文字列"で返る('0', '1', '2')
for(let n in [10, 20, 30])
  console.log(n)

// 配列を回す(for-of): 整数型の値10, 20, 30が返る
for(let n of [10, 20, 30])
  console.log(n)

// 文字列も回せる
for(let n of 'abc')
  console.log(n)

分割代入

英語ではDestructuring(非構造化)とのこと。

配列やオブジェクトの内容を、復数の変数に(分割して)代入する。

// 配列を分割する
const [foo, bar] = ['foo', 'bar']
console.log(foo)
console.log(bar)

// オブジェクトを分割する(大文字がオブジェクトのキー、小文字が代入される変数)
const {FOO: hoge, BAR: piyo} = {'FOO' : 'foo', 'BAR' : 'bar' }
console.log(hoge)
console.log(piyo)

配列展開

...で配列を展開し、引数や配列の初期化処理内で利用できる。

let list = [3, 4, 5]

// 展開して結合する
list = [1, 2, ...list, 6, 7]
console.log(list)


// 展開して可変長引数に渡す
print(...list)

function print(...args){
    console.log(args)
}

型とオブジェクトの追加/変更

基本型の継承(Array, Date, Element)

ES5では継承できなかった(推奨されていなかった) Array, Date, Elementが継承可能になった。

class CustomArray extends Array{
  // ...
}

シンボル型(Symbol)

シンボルは、文字列に似た一意なオブジェクト。

  • プリミティブ型である
  • それ自身とのみ等価(==)、等値(===)となる
let secretKey = Symbol('foo')
let anotherKey = Symbol('foo')

// 同じ文字列で初期化しても、シンボルは別オブジェクトとして認識される
console.log(secretKey == anotherKey)    // false
console.log(secretKey === anotherKey)   // false

// 文字と比較しても同様
console.log(secretKey == 'foo')         // false
console.log(secretKey === 'foo')        // false

// 自身とだけ合致する
console.log(secretKey == secretKey)     // true
console.log(secretKey === secretKey)    // true

rubyの:symbolのようなリテラル表記は特にない様子だった。

コレクション型(Map/Set/WeakMap/WeakSet)

  • Set = 重複のない配列

  • Map = "連想配列"に近いもの

    • 既存のObject({ })より格納の自由度が高い
    • かつ、操作用のメソッドが色々ある
  • WeakSet / WeakMap = 弱参照のSet/Map

    • 参照(オブジェクト)のみ保持できる
    • 格納しても、オブジェクトを保持しない(弱参照) = GCされうる
Set
let set = new Set()
set.add('foo')
set.add('foo')              // 値の重複はエラーとはならないが、数にはカウントされない
set.add('bar').add('bar')   // メソッドチェーンできる

console.log(set.size)       // 2
console.log(set.has('foo')) // true
Map
let map = new Map()

let strKey = 'key'
let listKey = [0, 1, 2]

map.set(strKey, 'string value')
map.set(listKey, 'list value')  // 配列オブジェクトをキーにすることができる

console.log(map.get(strKey))    // 'string value'
console.log(map.get(listKey))   // 'list value'

プロミスパターン(Promise)

Promiseパターン実装のためのオブジェクト。
非同期処理を先に実行し、その後からでも結果のコールバックが設定できる。
なのでこれを使うと、

  • 処理の順序とコードの記述順序が同じになる
  • 非同期処理が連続する場合に、コード上の深いネストを避けられる
const promise = new Promise((resolve, reject) => {
  // ...何か非同期的な処理を行う

  // 成功したら呼ぶ
  resolve()
  // 失敗したら呼ぶ
  reject()
})


promise.then(() => {
  console.log('success');
})

promise.catch(err => {
  console.error('failed: ' + err)
})

プロキシパターン(Proxy)

Proxyパターン実装のためのオブジェクト。
もとのオブジェクトをラップしてふるまいを追加/変更する。

// Proxyにつつまれるオブジェクト
var data = {};

// Proxyの処理内容
var handler = {
  get: function(obj, name){

    // ...

    return obj[name]
  },

  set: function(obj, name, value){

    // ...

    obj[name] = value
    return true
  },
};

// Proxyオブジェクトを作って操作
var proxy = new Proxy(data, handler)
proxy.foo = 'FOO'
proxy.bar = 'BAR'
console.log(proxy.foo)
console.log(proxy.bar)

ハンドルできるイベントはget, set, construct, deletePropertyなど色々。

イテレータ(Symbol.iterator)

任意のオブジェクトのSymbol.iteratorプロパティにイテレータを定義することで、for-ofによってループを回すことができる。

let list = {}

// イテレータを定義する
list[Symbol.iterator] = function(){
  let i = 0
  let iter = {
    next: () => {
      return { done: false, value: i++}
    }
  }

  return iter
}

// forで取得する
let iter = list[Symbol.iterator]()
for(let i=0; i < 10; i++){
    let result = iter.next()
    if(result.done) break
    console.log(result.value)
}

// for-ofで取得
for(let n of list){
  if(n >= 10) break
  console.log(n)
}

ジェネレータ

function*でPython方式のジェネレータを定義できる。

なおBabelでジェネレータ構文を使う場合はbabel-polyfillパッケージが必要だった。

require('babel-polyfill')

let list = {}

// ジェネレータを定義する
const gen = function*(){
  for(let i=0;;)
    yield i++
}

// for-ofで生成する
for(let n of gen()){
  if(n >= 10) break
  console.log(n)
}

参考

189
244
1

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
189
244