ECMAScript 5で追加された bind
がキモいけど便利だって話。
JavaScript のイベントハンドラのthis参照は despatchEvent 発行元になってしまい何かと不便を被るのですが、bind を使えば参照をイベントハンドラ側にすることが可能です。
(function ( window ){ "use strict"; var document = window.document; var OnetimeClick = ( function (){ function OnetimeClick ( id ) { this._count = 0; this._element = document.getElementById( id ); this._boundClick = this.onClick.bind( this ); this._element.addEventListener( "click", this._boundClick, false ); } var p = OnetimeClick.prototype; p.onClick =function ( event ){ this._element.removeEventListener( "click", this._boundClick ); event.preventDefault(); event.stopPropagation(); console.log( "click", this._count++ ); }; return OnetimeClick; }()); var test = new OnetimeClick( "example" ); }( window )); |
テストコードは実用性はありませんが、bind を使い addEventListener, removeEventListener を行い this 参照がイベントハンドラ側になっていることが確認できます。
下位互換
bind が実装されていない残念なブラウザのために MDN で下位互換対策コードが公開されています。
MDN: Function.prototype.bind
if (!Function.prototype.bind) { Function.prototype.bind = function (oThis) { if (typeof this !== "function") { // closest thing possible to the ECMAScript 5 internal IsCallable function throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function () {}, fBound = function () { return fToBind.apply( this instanceof fNOP && oThis ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments)) ); }; fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; }; } |
bind を残念なブラウザでも使えるように実装している Underscore.js のようなライブラリもあります。
bind
update 2013-06-17
タイポ修正
_bouncClick -> _boundClick