prototype.js 1.4.0を読んでみた

Hawk's Laboratory » prototype.js 1.4.0を読む:base.jsその2 で、prototype.jsを解りやすく解説してくださっていた。
その中で、Function.prototype.bind() メソッドが目に留まったので改めて自分なりに読み深めてみました(何度か挫折してます)。

Function.prototype.bind()

bindメソッドで一番引っかかるのは、Function::applyメソッドの動作がうまく理解できなかったことです。なんかイメージしづらいんですよね。このメソッドについても後で紹介したいと思います。
また自分が下の説明文を理解し、説明できるようになるのにえらい時間がかかっちゃってます^^;(ハァ

  • bindメソッド (v1.31) の説明

ある関数に対して、thisを束縛した関数を生成します。
つまり、ある関数内でthisとして使うべきオブジェクトをあらかじめ決定しておくことができます。
引数の束縛については有名なサイトがありますので、そちらを参考にしてください。


では、thisを束縛できると何が美味しいのかというと、よく紹介されている簡単な例ですがイベントに関数を定義する際のテクニックを紹介したいと思います。

[サンプル1]
var Dog = Class.create();
Dog.prototype = {
  initialize: function(name) {
    this.name = name;
  },
  bark: function() {
    alert('Bow wow wooo (my name is '+this.name+'!!)');
  }
}
var siba = new Dog('ポチ');

$('button').onclick = siba.bark.bind(siba);

どうでしょうか?idがbuttonであるタグをクリックすると「Bow wow wooo (my name is ポチ!!)」と吠えてくれます(アラートが鳴るだけですが・・)。
ではなぜ、イベントに定義する関数をsiba.barkと書いては駄目なのでしょうか?
先ほどのサンプル1のイベント定義の部分を読み解いてみます。

$('button').onclick = siba.bark

これは、

$('button').onclick = function() {
  alert('Bow wow wooo (my name is '+this.name+'!!)');
}

と、書いているのと同じことです(Dogオブジェクトのbarkメソッドの中身に置き換えているだけです)。クリックイベントが起きたときこの無名関数が呼ばれるわけですが、ちょっとまってください。this.nameって何でしょうか?
Dogオブジェクトのこと?いえいえそうではありません。thisは現在のオブジェクトを返すので、この場合は無名関数を返します。そしてnameですが、この無名関数(this)のどこを見てもnameなんてものは定義されていません。
もうわかりましたよね。thisが指し示すオブジェクトが意図しないオブジェクトを参照してしまうので、bind関数を使って、thisを束縛しているわけです。

  • 余談
$('button').onclick = siba.bark.bind(this)

と書くとどうなると思います?このコードをscriptタグの直下に記述してあれば、thisはグローバルオブジェクトを指しますので、

var name = 'Global';

グローバル変数nameを書いておけば、それが呼び出されます。

  • v1.40とv1.31でのコードの違い

僕がbindメソッドを気にとめた理由のひとつが、v1.40とv1.31でコードが多少異なるからです。

[v1.31]
Function.prototype.bind = function(object) {
  var __method = this;
  return function() {
    __method.apply(object, arguments);
  }
}

[v1.40]
Function.prototype.bind = function() {
  var __method = this, args = $A(arguments), object = args.shift();
  return function() {
    return __method.apply(object, args.concat($A(arguments)));
  }
}
どうやら、オブジェクトに渡す引数の部分のコードが書き換えられているようです。

*コードが変更されている部分を赤くしています。
  • bindメソッド (v1.40) の説明

ある関数に対して、thisを束縛した関数を生成します。このことは変わりませんが新たに、thisオブジェクトの引数も束縛することができるようになりました。


新しいbindメソッドのクールな使い方がまったく思い浮かびませんが、「アイデアを募集します」と振って終わりにしたいと思います。


Tags: ,