3

私は現在、ページ URL のハッシュ変更に基づいてアプリケーション ルーティングを制御する、作業中のゲームのクラスを作成しています。

私の問題は、メイン ルーティング関数を hashchange イベントにアタッチした後、「this」のコンテキストが「window」に変わることです。

これまでのコードは次のとおりです。

Game.Router = function() {

return {

    init: function() {

        window.addEventListener('hashchange', this.route, false);

    },

    route: function(e) {

        e.preventDefault();
        var routingLocation = e.newURL.substr(e.newURL.indexOf('#!/') + 3, e.newURL.length);

        switch(routingLocation) {
            case "new":
                this.toggleView('Game');
                break;
            case "instructions":
                this.toggleView('Instructions');
                break;
            case "scores":
                this.toggleView('Scores');
                break;
            case "about":
                this.toggleView('About');
                break;
        }

    },

    toggleView: function(viewID) {

        var els = document.querySelectorAll('section');
        for(var i=0, l=els.length; i<l; i++) {
            if(els[i].id == viewID) {
                els[i].className = 'currentGameSection';
            } else {
                els[i].className = '';
            }
        }

    }

}

}();

route 関数の switch 文で this.toggleView を呼び出してみると、「this」が Game.Router から window に変わっていることがわかりました。this.toggleView を Game.Router.toggleView に置き換えることで問題を解決できますが、これは理想的ではありません。

イベントリスナーを追加した後に「this」コンテキストが変更される理由を誰かが理解するのを手伝ってくれませんか?

4

3 に答える 3

4

を使用しているので、オブジェクトにメソッドをaddEventListener追加しhandleEvent、ハンドラーの代わりにオブジェクトを渡します。

Game.Router = function() {

    return {
          // vv--- add this
        handleEvent: function(e) {
            if (e.type === "hashchange")
                return this.route();
        },

        init: function() {
                             // pass the object---vv
            window.addEventListener('hashchange', this, false);
        },

        route: function(e) {
            // your route code
        },

        toggleView: function(viewID) {
            // your toggleView code
        }
    }
}();

これは、オブジェクトにEventListenerインターフェースを実装させることを意味します。したがって、オブジェクト自体が有効なイベントハンドラーになりaddEventListener、関数の代わりにに渡すことができます。

したがって、何かが発生した場合でも、handleEventメソッドが呼び出されます。をテストして、.typeそれがどのイベントであったかを確認できます。

thishandleEventはオブジェクトになり、そのメソッドに直接アクセスできます。


この手法は、コンストラクター関数を使用している場合にも役立ちます。handleEvent他のメソッドを使用してプロトタイプを作成するだけで、そのプロトタイプを継承するすべてのオブジェクトがEventListenerインターフェイスを実装するためです。


クロージャを使用する場合Game.Routerは、すべてのメソッドがそれを利用できるように、関数にクロージャ変数を配置します。

Game.Router = function() {
    var self = this;
    return self = {
        init: function() { // using 'self' in case 'init' becomes detached
            window.addEventListener('hashchange', self.route, false);
        },

        route: function(e) {
            // use 'self' to refer to the object
        },

        toggleView: function(viewID) {
            // use 'self' to refer to the object
        }
    }
}();
于 2012-11-23T15:48:04.367 に答える
4

私が提供したリンクがあなたの問題の理由を明らかにすることを願っています。

通常のクロージャーソリューションを提供しないために、ここにもっと単純なものがあります(IE8-と互換性がありません):

 window.addEventListener('hashchange', this.route.bind(this), false);
于 2012-11-23T15:49:27.987 に答える
2

クロージャーを使用する必要があります。

route: (function(context){
    return function(e){

        //your original function, but with all
        //references to this changed to
        //context

    }
})(this),
于 2012-11-23T15:43:23.583 に答える