9

私はこの基本的なイベントシステムをJavascriptコードで使用しており、同僚のためにそれを文書化しようとしています。このコードの「スコープ」と「コンテキスト」の違いはよくわかりません。なぜ私が両方を必要とするのかを誰かが理解するのを手伝ってもらえますか?

this.myClass.prototype.on = function (type, method, scope, context) {
    var listeners, handlers, scope;
    if ( !(listeners = this.listeners) ) {
        listeners = this.listeners = {};
    }

    if ( !(handlers = listeners[type]) ) {
        handlers = listeners[type] = [];
    }

    scope = (scope ? scope : window);
    handlers.push({
        method: method,
        scope: scope,
        context: (context ? context : scope)
    });
}

this.myClass.prototype.trigger = function(type, data, context) {
    var listeners, handlers, i, n, handler, scope;
    if (!(listeners = this.listeners)) {
        return;
    }
    if (!(handlers = listeners[type])){
        return;
    }
    for (i = 0, n = handlers.length; i < n; i++){
        handler = handlers[i];
        if (context && context !== handler.context) continue;
        if (handler.method.call(
            handler.scope, this, type, data
        )===false) {
            return false;
        }
    }
    return true;
}
4

2 に答える 2

26

このコードは不必要に混乱します。とという言葉はcontextscope間違ったことを意味するために使用されます。まず、すべてのJavaScript開発者にとってそれらが何を意味するのかを説明しましょう。

関数のコンテキストは、その関数のの値ですthis。つまり、関数がのメソッドとして呼び出されるオブジェクトです。

function F() { this.doSomething('good'); }

この関数は、次のようなさまざまなコンテキストで呼び出すことができます。

obj1 = { doSomething: function(x) { console.log(x); } }

obj2 = { doSomething: function(x) { alert(x); } }

F.call(obj1);
F.call(obj2);

これから生まれる多くの強力なプログラミングパターンがあります。関数バインディング(アンダースコアbindまたはjQuery proxy)はその一例です。

一方、スコープは、JavaScriptが実行時に変数を解決する方法を定義します。JavaScriptには、グローバルスコープ、関数スコープ、ブロックスコープ、モジュールスコープの4つのスコープしかありません。また、クロージャを可能にする「スコープチェーン」と呼ばれるものも扱っています。


onメソッドは変数を保存し、scopeそれをコンテキストとして関数で使用しtriggerます。これは混乱を招きます(名前を付けないでください。scopeコンテキストです)。

handler.method.call(
    handler.scope, this, type, data
)

そして、私はthis上記の呼び出しに何が含まれているのかわかりません。

このonメソッドは、偽の場合contextに提供されたデフォルトのaも受け入れます。次に、これを使用して、で呼び出す関数をフィルタリングします。scopecontextcontexttrigger

context !== handler.context

これにより、ハンドラーを任意のオブジェクト(ハンドラーが呼び出したオブジェクト)に関連付けてcontextグループ化し、を指定するだけでグループ全体を呼び出すことができますcontext

繰り返しになりますが、このコードは非常に複雑で、もっと簡単な方法で記述できたと思います。ただし、そもそもこのような独自のイベントエミッターを作成する必要はありません。すべてのライブラリで、すぐに使用できるようになっています。

于 2013-01-14T17:56:13.420 に答える