イナヅマTVログ

[JavaScript] bind キモい!でも便利

| 0件のコメント

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

コメントを残す