関数呼び出しとthis

JavaScript: The Good Parts」を読んでいる。関数の呼び出しパターンには、メソッド呼び出し、関数呼び出し、コンストラクタ呼び出し、apply呼び出しの4パターンがあり、thisがどのように扱われるかが違う。

メソッド呼び出し

thisには呼び出しオブジェクトが格納される

person = {
    name: 'kotaro',
    sex_type: 'M',
    greet: function () { alert('My name is ' + this.name+ '.') ;}
};
person.greet();

関数呼び出し

thisにはグローバルオブジェクト(window)が格納される。

greet = function() {
    if (this === window) { 
        alert('My name is Kotaro');
    }
};
greet();

実はgreet関数はwindowオブジェクトのpropertyなので、メソッド呼び出しと考えれば筋は通る。

コンストラクタ呼び出し

new演算子付きでfunctionを呼び出すと、空のオブジェクトが生成されてthisにセットされる。

Person = function() {
    alert(typeof(this)); // object
    for (var prop in this) {
        alert(prop); // 何もない
    }
    this.name = 'kotaro';
    // newのコンテキストでは暗黙的にthisがreturnされる
    // return this;
    
};
alert(new Person().name);

newを使うとクラスベースのオブジェクト指向言語っぽいので、よくないよねーというのが「JavaScript: The Good Parts」に書かれている主張と解釈してる。個人的にはnewありでもなしでもどちらでも動くように書いておくのがベストプラクティスじゃないかなと思う。

apply呼び出し

これを使うとthisにセットされる値を自由に変えることができるよ、というもの。前述のPersonでやってみる。

var personA = {name:'A', age:20};
Person.apply(personA, null);
alert(personA.name); // kotaro

ちなみにapplyはFunction関数のprototypeに定義されているメソッド。

if (Function.prototype.apply) {
    alert(Function.prototype.apply);
}

まとめ

  • JavaScriptはプロトタイプベースのオブジェクト指向言語で、関数もオブジェクトであることを徹底して理解すべし
  • 関数の呼び出し方には関数呼び出し、メソッド呼び出し、コンストラクタ呼び出し、apply呼び出しがあり、thisの扱われかたが違ってくる
  • new演算子は空オブジェクトをつくって、return this;する