1

Javascript 内でのプロトタイピングとクロージャーに頭を悩ませ始めていますが、完全ではありません。以下のこの例では、私の 2 つのオブジェクトで、2 番目のオブジェクトはスコープ/コンテキストを失い、最初のオブジェクトの ID を引き継いでいるようです。

function broker()
{
    var _q = [];
    this.add = function(delegate) {_q[_q.length] = delegate; }
    this.broadcast = function(message)
    {
        for(qi = 0; qi < _q.length; qi++)
        {
            _q[qi](message);
        }
    }
}

function subscriber(abroker, yourname)
{
    me = this;
    this.myprop = yourname;
    this.subby = function(message){ alert(message + " " + me.myprop + me.dosomething() + secret()); };
    this.dosomething = function() {return "...abc";};
    function secret(){return "...def";}

    abroker.add(this.subby);
}

var thebroker = new broker();
var mysub = new subscriber(thebroker, 'mysub');
var myothersub = new subscriber(thebroker, 'myothersub');
thebroker.broadcast("hello from");

サブスクライバー オブジェクトでデリゲートを呼び出し、内部で関数を実行できる共通のブローカー オブジェクトが存在するという考え方です。しかし、ブローカーによって呼び出された関数内でスコープが失われています。

出力: 2 つの警告ウィンドウ、両方の出力: "myothersub"、mysub がスコープを失ったようです?

元のオブジェクトの外側で subby デリゲートを明示的に宣言し、オブジェクト全体を参照することで、正しい応答を得ることができました。

サブスクライバー オブジェクト内で this.subby を宣言する代わりに、次のようにします。

mysub.subby = function(message)
{
    alert(message + " " + mysub.myprop); // obv the dosomething his hidden
}

thebroker.add(mysub.subby);

メモリから直接入力したため、上記の構文のいずれかが間違っている場合はすみません。実際には機能しますが、慣れ親しんだカプセル化が失われます。

オブジェクトのスコープ/コンテキストを失うことなく、元の手法を使用してカプセル化するにはどうすればよいですか?

4

1 に答える 1

0

短い答え:問題は単にコンストラクターmeでの宣言に関係しているように見えます。subscriber少なくともvar、各オブジェクトのローカル/プライベート変数にするために、その前に a を置く必要があります。の代わりvar me = this;me = this;

説明: JavaScript では、変数を で明示的に宣言しないとvar、変数がグローバルになります。元のスクリプトで起こっていたことは、オブジェクト内へのグローバル参照としてmysub宣言されたものを作成したことです。しかし、グローバルを作成するとすぐに、新しいオブジェクトの内部に上書きされました。methismysubmyothersubmethismyothersub

subbyメソッドはそれに基づくアラートを作成したためme、どちらのオブジェクトから呼び出しても問題ありませんでした。これは、両方のオブジェクトのメソッドがオブジェクトにローカルまたは固有のものを使用しておらず、単に同じグローバル変数を参照していたためですthis。そのようなオブジェクトが作成される

上書きされるオブジェクトではなく、新しいオブジェクトを作成するたびに、クロージャ内にのローカル バージョンを作成するvar me = this;代わりに、単に書き込むだけです。me = this;me

...

PS。余分なヒント。特にグローバルにするつもりがない場合は、できるだけグローバルを少なくするために、すべての変数でこれを行う必要があります。したがって、コンストラクターqi内の変数に対して同じ宣言を行います。brokerループ条件内で宣言するだけでこれを行うことができますfor (var qi = 0; qi < _q.length; qi++)qiそれは、グローバル変数であることをやめるには十分です。

ただし、コードを読みやすくするために、すべての変数を関数の先頭で宣言することをお勧めします。broadcastしたがって、メソッドを次のように単純に書き直すことをお勧めします。

this.broadcast = function(message) {
    var qi,             // STOPS `qi` BECOMING A GLOBAL
        ql = q.length;  // SO DON'T HAVE TO CHECK LENGTH OF `q` EVERY LOOP
    for(qi = 0; qi < ql; qi += 1) {
        _q[qi](message);
    }
};

Douglas Crockford は、クロージャ、オブジェクトの作成、および優れたコード記述規則に関しては、JavaScript に関する非常に優れたライターです。このページにはたくさんのヒントがあり、このトピックについて講義している彼のビデオを簡単に見つけることができます。クロージャーや JavaScript の他の側面をより詳しく調べ始めたとき、これらすべてが本当に役に立ちました。それもあなたに役立つことを願っています。

于 2013-01-27T14:24:21.703 に答える