現代的JavaScriptおれおれアドベントカレンダー2017 – 06日目

JavaScriptにおけるメソッドってのはオブジェクト(receiver)をコンテキスト this に設定した状態で実行する関数なのであって、本質的にはただの関数であったわけです。

なので、今までは普通のプロパティと同様、値の種類が関数であるプロパティとして定義してきました。

var obj = {
  foo: function() {
    // ...
  },
};

このメソッドの書き方に新しい、もっと見やすいものが追加されました。

var obj = {
  foo() {
    // ...
  },
};

とまあこういう↑書き方で書けるようになりました。

これめっちゃ見やすくないですか? まあカンマ , は残るんだけど。

特殊な関数

非同期関数やジェネレータも、接頭辞みたいにキーワードを加えつつ、同じように書くことができます。

非同期関数 async

const obj = {
  async sleep(ms) {
    return new Promise(resolve => {
      setTimeout(resolve, ms);
    });
  },

  async doLater() {
    console.log('Sleep...');
    await this.sleep(1000);
    console.log('and wake up!')
  },
}; 

obj.doLater();

別稿参照。

ジェネレータ *

const obj = {
  * sayPhrases() {
    yield 'Hello';
    yield 'World';
  },
};

for (let phrase of obj.sayPhrases()) {
  console.log(phrase);
}

別稿参照。

こっちはなんか気持ち悪い感じが……。

非同期かつジェネレータ async *

というのもアリらしい。

コンストラクタとして利用不可

メソッド定義の書式で書いた場合、コンストラクタとして利用できません。

const obj = {
  Foo() { },
};

const foo = new obj.Foo();  // Exception: TypeError: obj.Foo is not a constructor

アロー関数と同じ状態です。といってもこちらは this が固定されないですけど。

普通の関数オブジェクトをプロパティに与える場合は可能です。

const obj = {
  Foo: function() { },
};

const foo = new obj.Foo();  // OK

この場合は、一度普通の関数オブジェクト(コンストラクタとして利用可能)を作成した後に、プロパティの値として設定してる、ってな感じでしょうか。

「関数」vs「メソッド」

ちょっと細かい話。

FunctionCreate() という内部処理の仕様によると、この処理で作成できる関数は以下の三種類です。

  • Normal
  • Method
  • Arrow

Arrowは文字通りアロー関数で、Methodは今回紹介したメソッドの書き方をした場合です。それ以外がNormalになります。(このうちNormalだけがコンストラクタとして利用できます。) ですので、メソッド記法で記述したものはまさに「メソッド」になるようです。

だから何だ

そうはいってもその情報が関数オブジェクトに残るわけでもなし。実際は実行オブジェクト (receiver) の有無で分けて、同じ関数オブジェクトでも利用形態に合わせて呼ぶのが一番良いかなと思います。

functin foo() {}

// 関数
foo();

// メソッド
const obj = { method: foo };
obj.method();

ふつう、ふつう、わりと普通。

その他

receiver?

obj.method()obj のことです。

末尾カンマ

古いIEだとオブジェクトプロパティの最後の定義にカンマが付いてると文法エラーになったんですが(バージョン忘れたけどたしか6あたり)、今はもうとっくにそうはならないようになってます。

個人的にはいっそ全部に付けるようにしてます。続きに追加した際に、カンマ変更分の差分が出るのもなんか見づらいし。

参考