JavaScript
es6

ES6 でこのように書いている

More than 3 years have passed since last update.

最近、ES6ばっかり書いていて完全に止められない状態になってしまっているのですが、ES5で書いていたときからプログラムの書き方自体が変わってきたなと感じる部分があるので列挙してみます。

Destructuring assignments on formal argument

分割代入のシンタックス

let obj = { a: 100, b: 200, c: 300 };
let { a, b, c } = obj;

console.log(a, b, c); //-> 100, 200, 300

これをメソッドとかコールバックの仮引数で使う。

emitter.on("noteOn", ({ noteNumber, velocity }) => {
  // ここでなにか処理する
});

最初は引数の順番を気にしなくて良いとか、あとから雑な気持ちで引数を増やせて便利だなくらいに思っていたのだけど、最近はイベント発行側が受け取り側の変数名を束縛できるのでコードに一貫性を持たせられるというのが実はけっこう良いのではと思っている。

Symbol

2015/07/28 13:45 記述修正
外部からアクセスしにくい、もしくは重複しない変数を作るのに使っている。

import { EventEmitter } from "events";

export const EVENTS = typeof Symbol !== "undefined" ?
    Symbol("EVENTS") : "@mohayonao/${package-name}:EVENTS"; 

export default class SummerVacation extends EventEmitter {
  constructor() {
    super();
    this[EVENTS] = [];
  }

  pushEvent(event) {
    this[EVENTS].push(event);
  }
}

Symbolはユニークなので、こうしておくと気軽にインスタンス変数にアクセスできなくなるだけでなく、継承元が使っているインスタンス変数との重複を気にしなくて良くなる。上の例だと夏休みのイベントを管理するのに this._events を使ってしまうと EventEmitter が使っているのと被るので良くない。

export してあるのはテストで触れた方が楽なことがあるから。外部から気軽にアクセスできない方がよいけど、きちんと手順を踏めば別に触っても良いよというスタンス。

Computed Property

メソッド命名規則を無視した特殊なメソッドを作るのに使っている。例はわかりにくいけど反応したいイベントハンドラを "/" 始まりのルールで記述しておいて実行できそうならするパターン。たとえば特定の URL パターンに反応させるとかが簡単に書ける。

class Delegator {
  delegate(address, data) {
    if (address[0] === "/" && typeof this[address] === "function") {
      this[address](data);
    }
  }
}

let store1 = new class extends Delegator {
  ["/read/succeeded"](data) {}
  ["/read/failed"](data) {}
};

let store2 = new class extends Delegator {
  ["/read/failed"](data) {}
};

function doAction(stores, address, data) {
  stores.forEach((store) => {
    store.delegate(address, data);
  });
}

doAction([ store1, store2 ], "/read/failed", new TypeError());

flux アーキテクチャで実際に試してみた例
https://github.com/mohayonao/fluxx/blob/master/examples/todomvc/stores/TodoStore.js

他にはオブジェクトのプロパティを16進数で書きたいときにも便利

const MIDIMessage = {
  [0x80] : "noteOff",
  [0x90] : "noteOn",
};

Selective SuperClass

たとえば、node.js でも ブラウザでも使える MIDIKeyboard を扱うクラスというのを考えた時に一般的なクラスツリーだと以下のように考えると思う。

extends1.png

このとき NodeMIDIKeyboard と WebMIDIKeyboard は同じMIDIメッセージパーサーを参照して同じような処理を2回書く必要があるのだけど、やることが全く同じなら以下のように親クラスを選択できたほうが簡単。ハードウェアに近い部分のAPIが異なる JavaScript の問題を上手く解決できていると思う。

extends2.png

MIDIKeyboard.js
function _extends(MIDIDevice) {
  return class MIDIKeyboard extends MIDIDevice {
    // クラスの実装を書く
  };
}

export default { extends: _extends };
WebMIDIKeyboard.js
import WebMIDIDevice from "@mohayonao/midi-device/webmidi";
import MIDIKeyboard from "./MIDIKeyboard";

export default MIDIKeyboard.extends(WebMIDIDevice);
NodeMIDIKeyboard.js
import NodeMIDIDevice from "@mohayonao/midi-device";
import MIDIKeyboard from "./MIDIKeyboard";

export default MIDIKeyboard.extends(NodeMIDIDevice);

実際に試してみた例