@uents blog

Code wins arguments.

関数呼び出しとthisの制御

前回で関数と呼び出しパターンとthisの振る舞いの関係を学んだ通り、以下のようにthisがそのオブジェクトを指してほしいのにそうなってはくれないパターンがある。

var Quo = function() {
    this.status = 1;

    this.get_this = function() {
        var helper = function() {
            return this; // 関数呼び出しパターンなので、グローバルオブジェクトが返される!                                 
        };
        return helper();
    };
};

nodeで実行。

> var quo = new Quo();
> quo.get_this();

// グローバルオブジェクトが返される

不便。。。

このことはサイ本でも詳しく解説しています。

 関数がメソッドではなく関数として呼び出された場合、thisキーワードはグローバルオブジェクトを参照します。ややこしいことに、メソッドとして呼び出された関数中に入れ子にされた別の関数が関数として呼び出された場合も、グローバルオブジェクトを参照します。つまり、入れ子にしている側の関数(メソッド)では、thisキーワードはオブジェクトを参照していますが、入れ子にされた関数の本体中では、thisキーワードはグローバルオブジェクトを参照します。

というわけで、thisを思い通りに制御する方法ですが、僕の知っている範囲では2つあります。

1. thisを関数スコープ内の変数に待避する

JavaScript: The Good Partsにも載っている例。

var Quo = function() {
    this.status = 1;

    this.get_that = function() {
        var that = this; // メソッド呼び出しパターンなので、ここでのthisはそのオブジェクト                                 
        var helper = function() {
            return that; // 関数スコープにより、ここでのthatはthis(=そのオブジェクト)                                      
        };
        return helper();
    };
};

nodeで実行。

> var quo = new Quo();
> quo.get_that();
{ status: 1,
  get_that: [Function] }

2. bindでthisを束縛する

コード。

var Quo = function() {
    this.status = 1;

    this.get_bind_this = function() {
        var helper = function() {
            return this;
        }.bind(this); // 関数内のthisをここでのthis(=そのオブジェクト)にする
        return helper();
    };
};

nodeで実行。

> var quo = new Quo();
> quo.get_bind_this();
{ status: 1,
  get_bind_this: [Function] }

thisの待避の例だと変数を用意しないと行けないですが、局所的に束縛したいときはbindが便利そう。