投稿日:

JavaScript の超便利なメソッド bind で this を制御する


JavaScript の関数オブジェクトには、「bind」という便利なメソッドがあります。このメソッドは関数内で参照できる this を指定のオブジェクトに束縛できるものです。この関数を使うと、this に関連した良く有る問題をスマートに解決できます。

this にまつわるよくある問題

次の例は、実行後に「こんにちわ ぷんちゃん」とアラートするコードです。

では、3秒後に表示させてみましょう。よく次のように書きます。

これは期待通りに動作します。しかし、setTimeout に渡している無名関数は、単に Person.sayHello() をコールしているだけなので、次のようにも書けそうです。

しかし、これは期待通りには動作しません。
通常、ブラウザで実行させている時には「こんにちわ undefined」と表示されます。

これは JavaScrip における一般的な動作です。オブジェクトのメソッドはオブジェクトに束縛されているものではなく、その時々のコンテキストにおいて実行されるからです。JavaScript をある程度理解しているプログラマは、このことを良くご存知のはずです。

bind を使って this を束縛する

さて、本題です。

この this を固定してしまえるメソッド「bind」が関数オブジェクトには存在します。
例を見てみます。

今度は期待通り動作しました。

bind メソッドはこのように、関数内の this を指定のオブジェクトに束縛した新しい関数を返す機能を提供します。上の例では、bind に punchan オブジェクトを与えて、sayHello メソッド内の this が常に punchan オブジェクトとなるような新しい関数を取得し、それを setTimeout に渡すことで、期待通りの動作を実現しました。

このように、bind を使うことで、関数実行時の this を簡単に束縛できます。JavaScript でオブジェクトを利用したスクリプトを書く時にはとても便利ですね!

別のよくありそうな例

もうひとつ、良く有りそうな例を。

14行目で this を参照していますが、この時の this は Person オブジェクトでは無くて、グローバルオブジェクト(ブラウザなら通常 window オブジェクト)になります(ちなみにその this が決定されているのは、3行目の呼び出し部です)。

14 行目の this の部分で、Person オブジェクトを参照したい時に、よく次のようにするでしょう。

13 行目で期待する this の値を一旦別の変数に移して、その変数を 15 行目で参照しています。これは上手く行きます。しかし、関数オブジェクトの bind を使うと、次のようにも書けます。

15 行目で bind を使って、13〜15 行目に定義した無名関数オブジェクト内での this を指定しています。このケースではこの方がスマートですね!

読みやすさについてはケースバイケースだと思いますが、これは JavaScript でオブジェクトを扱う時の基本テクニックの一つです。このような bind の用法を知っておくことで、より読みやすいコードを書ける場面も増えると思います。

ちなみに、bind にはどんなオブジェクトでも渡すことができます。ここでは this を渡していますが、必要に応じて、様々なオブジェクトを、関数内の this として bind できるということを覚えておいてください。

bind による引数の部分適用

実は bind は this だけではなく関数の引数も束縛することが出来ます。
次の例を見てください。

4 行目の mul(2, 3) は、単純な関数呼び出しです。6とアラートされます。

7 行目で bind を利用して、引数の一つを 2 に束縛した新しい関数 mul2 を得ています。
8、9 行目の意味が分かるでしょうか? 関数 mul2 は、関数 mul の最初の引数が 2 に束縛されているものなので、常に 2 * b の演算を行ってアラートする関数になります。結果、ここではそれぞれ 2 * 4 ⇒ 8、2 * 16 ⇒ 32 というアラートが表示されます(ちなみに、前述の通り bind の第1引数には this とするオブジェクトを指定しますが、ここでは this は使っていないため null としています)。

また、11 行目からのように、引数が部分適用された関数を、更に部分適用する事もできます。

mul.bind(null, 2) で返される関数と等価なコードを書くと、次のようになります。

使いどころが難しい機能かも知れませんが、ライブラリなどの汎用性を高める為に利用することが出来そうですし、アイデア次第、使い方次第、ということになると思います。

引数の部分適用の例1

引数の部分適用の例を挙げてみます。

これは tags というコレクションオブジェクトから任意の tag を削除するコードです。tags.remove メソッドは jQuery.Deferred オブジェクトを返し、tag の削除に成功した時に done、失敗した時に fail にセットされたコールバック関数が呼ばれるというコードです。ここでコールバックでは alert を表示することしかしていません。これを bind を使って書き換えると、次のように書けます。

如何でしょうか? この例が見やすいかどかは人それぞれだと思いますが、このように使えるということを覚えていると、きっと何かの時に役立つかと思います。

もう一つ、もう少し使いどころがありそうな例を挙げてみます。

引数の部分適用の例2

次のコードは、1秒毎に3回 alert がコールされて「○秒後!」と表示します。もちろん、「1秒後!」「2秒後!」「3秒後!」となることを期待していますが、これは3回とも「4秒後!」と表示されてしまいます。クロージャ変数についてよくある問題ですね。

これは例えば次のようにして期待通りの動作をさせることが出来ます。

ただ、ちょっとややこしいですね…。

そこで、bind による引数の部分適用を利用すると、次のように書くことができます。

これはスッキリして、またしっくり来るのではないでしょうか (*’-‘*)

以上です。

ご存知の方はご存知というお話ですが、僕はつい半年位前まで知らなかったもので共有させて頂きました。

 

 

 

 

JavaScript の超便利なメソッド bind で this を制御する」への4件のフィードバック

  1. そもそもナチュラルに「束縛」っていう概念が出てくることが不親切
    さらにその概念自体の説明なく、簡単ですね!って感じの文章で書かれると
    学習付加と文体にかなりのギャップがある

  2. […] 【参考】 ・FN1303001 | CreateJSで関数にスコープを定める ー proxy()関数 | HTML5 : テクニカルノート ・FN1303002 – 関数に任意のthis参照を定める – HTML5 : テクニカルノート ・JavaScript の超便利なメソッド bind で this を制御する | Foreignkey, Inc. […]

コメントを残す