2

登録されたすべてのアニメーションが終了したときに、いくつかのアニメーション(ただし、ajax呼び出しまたは何らかの「onComplete」機能を持つものでもかまいません)がいつ終了するかを教えてくれる単純なエンジンが必要です。

簡単なjsFiddleを書きました。

そして、私はいくつかの疑問を持っています:

  1. this.iorを書くことができないのにorthis.finishを使わなければならないのはなぜですか? このような単純なクラスを作成するより良い方法はありますか? ここで少し文書化しようとしましたが、まだ明確ではありません。これはエンジン内で呼び出されるため div ですが、オブジェクト エンジンで静的 (??) 変数を使用することが正しい方法であるかどうかはわかりません。Engine.iEngine.finish$("#somediv").bind('click', function() { })この回答のおかげで、「この自己重複」で解決しました(このメソッドをどのように呼び出すことができますか?)

  2. この場合、 jquery遅延オブジェクトは私を助けることができますか? おそらく、遅延オブジェクトでそれを書くためのより簡単で効果的な方法があるでしょう。私は何でも呼び出すことができるものが必要です (アニメーション、プリロードの完了時、ajax)。

それが明確であることを願っています..同様の状況を処理する何かへのアドバイスやリンクは大歓迎です!

最後のコード

最後のコード:

engine = new Engine(); 

$("#clickme").bind('click', function() {
    $(".bar").each(function() {
        engine.add()
        $(this).animate({width:200}, getRandomInt(500, 3000), 
                        engine.oncomplete);                      
    });
});

// animation engine
function Engine() {   
    var self = this;
    this.i = 0;
    this.add = function() {
        self.i++;
    }
    this.oncomplete = function() {
        self.i--;
        if(self.i<=0){
            self.finish();
        }
    }     
    this.finish = function() {
        alert("done!");           
    }
}

</p>

4

2 に答える 2

1

更新:
私はあなたのフィドルを詳しく調べました。いくつかの修正が必要でした。コンストラクター内ですべてのメソッドを定義しています。インスタンスを作成するたびに、同じ関数を何度も作成することになります。それは完全にやり過ぎです。これは、すべてのメソッドがプロトタイプのプロパティである実用的なフィドルです。

特に、いくつかの問題を引き起こしている 1 つの行がありました。

$(this).animate({width:200}, getRandomInt(500, 3000), engine.oncomplete);

ここでは、コールバックとしてメソッドへの参照oncompleteを渡していますが、関数オブジェクトが呼び出されるコンテキストはad-hocと判断されるため、これはもはやインスタンスを参照していませんでしたengineが、それは簡単な修正です:ラッパー関数:

$(this).animate({width:200}, getRandomInt(500, 3000), function()
{//this anonymous function will get some context
    engine.oncomplete();//but invokes oncomplete in the context of engine, this references engine here
});

var self別のアプローチは次のようになります:プロトタイプ メソッドをオーバーライドするクロージャ (あなたのように、おそらく無意識のうちに で作成されたもの):

engine.oncomplete = (function(that,prototypeMethod)
{//argument is reference to engine object, and the original method, that we're overriding
{
    return function()
    {//new version of the method, you can do this right after the instance is created
     //or even in the constructor
        return prototypeMethod.apply(that,[]);//call in correct context
    };
}(engine,engine.oncomplete));
$(this).animate({width:200}, getRandomInt(500, 3000),engine.oncomplete);
delete engine.oncomplete;//reset to prototype method, optional

いずれにせよ、それだけです。この問題に関する詳細情報は次のとおりです-私は思います.
まだ微調整できる点がいくつかありますが、全体としては順調に進んでいると思います。覚えておいてください: メソッドは、コンストラクターから十分に離しておくのが最善です。2番目のオプションが少しあいまいな場合(IMOです)。これが、この回答に追加する最後のリンクになることを約束しました。JavaScript のメモリ リーク
についてしばらく前に質問しました。これは私の巨大な投稿の 1 つですが、コード スニペットの一部: 関数がどのように呼び出されるかを見てください。また、私が自分の質問に投稿した「回答」も見てください。どのようにネイティブであるかの例があります。reusableCallbackprototypesに使える。退屈したり、興味がある場合は、コードを読んthisで、いつでも何が参照されるかを考えてみてください。それを解決できれば、JS がスコープを決定する基本原則を知っていると言っても過言ではありません。


には というプロパティがないthis.finishため、 と書くことはできません。変更するだけです:thisfinish

Engine.finish = function(){};

Engine.prototype.finish = function(){};

なんで?JS関数はファーストクラスのオブジェクトだからです(変数に割り当てることができ、とにかく関数オブジェクトへの参照が可能であり、引数として関数に渡すことができ、関数の戻り値にすることができます...
)試してみてくださいconsole.log(Engine instanceof Object);、それはtrueをログに記録します。だからあなたがやっていることはこれです:

function Engine(){};
//is hoisted, and interpreted as:
var Engine = function(){};//<-- a function object, that is referenced by a var: Engine
Engine.finish = function(){};
//just like any object, assign a property to the object that Engine is referencing

ただし、新しい Engine オブジェクトを作成すると、次のようになります。

var myEngine = new Engine();

JS は、参照しているオブジェクトのプロトタイプをチェックしEngineます。この場合は、関数を参照しています。関数はnewキーワードを使用して呼び出されるため、JS はオブジェクトを作成します。このためには、プロトタイプ (およびそれらの多く) が必要です。この特定の関数 (コンストラクター) のプロトタイプにはプロパティが定義されていないため、JS はチェーン内の次のプロトタイプであるプロトタイプを探しますObject。そのプロトタイプのすべてのメソッドとプロパティが新しいインスタンスに渡されます ( と を試してみるmyEngine.toString();Object.prototype.toString === myEngine.toString、同じメソッドを共有していることがわかります)。
これは完全に真実/正確ではなく、コンストラクターから新しいオブジェクトを作成するときに行われるすべてのことの 10% でさえないことに注意してください。 :

すべての新しいインスタンスにfinishメソッドが必要で、ご存じのとおり、すべての新しい Engine インスタンスが にあるメソッドを継承するとします。次のObject.prototypeようにします。

Object.prototype.finish = function(){};//!!

確かにうまくいきますが、これもうまくいきますsomeArray.finish。はい、配列はオブジェクトであり、関数、DOM 要素への参照、およびあなたが持っているものと同様です。オブジェクトのプロトタイプを変更しないでください。
代わりに、JS では、特定のコンストラクターのすべてのインスタンスで共有されるプロトタイプ レベルで特定のメソッドを定義できます。

function Engine(){};//emtpy
Engine.prototype.i = 0;
var newEngine = new Engine();
console.log(newEngine.i);//0
var anotherEngine = newEngine();
newEngine.i = 1234;
console.log(anotherEngine.i);//0
console.log(newEngine.i);//1234

これにより、次のような基本的なプロトタイプ チェーンが作成されます。

EngineInstance {list of instance properties}
   ||
   ====>Engine.prototype {list of properties that all Engine instances have}
           ||
           ====> Object.prototype {properties for all objects, Engine is an object, so it should have these, too}

したがって、新しいインスタンスが作成されるたびに、その新しいインスタンスには、プロトタイプで定義されているプロパティが割り当てられます。結論として、メソッドは (インスタンスごとに新しい関数を作成するコンストラクター内ではなく) 1 回作成することができ、すべてのインスタンスがそのメソッドを共有します。詳細については MDN を参照してください

1 つだけ: JS は、オブジェクトが作成されるのと同じ方法でオブジェクトのプロパティにアクセスしますが、順序が逆になります:
を呼び出すnewEngine.finishと、JS は最初にそのインスタンスに独自のfinishプロパティがあるかどうかを確認し、そうでない場合はEngineプロトタイプを調べます。 、それにも終了メソッドがない場合、JS は、目的のプロパティが見つかるまで ( までObject.prototype)、プロトタイプ チェーンを続行します。または、オブジェクト プロトタイプにプロパティがない場合は、それは単に を返すだけです。undefinedこれは、本当にすべてを物語っています。このプロパティはundefinedです。

この結果として、デフォルトの動作とは異なる動作をさせる必要がある限り、プロトタイプのメソッド/プロパティをマスクdeleteし、その後は単純に変更されたメソッドをマスクすることができます。実際の例を次に示します。

function doAjax(data, url, method)
{
    var xhr = makeAjaxInstance();
    data.toString = function()
    {
        return JSON.stringify(this);
    };
    //some more stuff, but then:
    xhr.send(data + '');//<-- add empty string forces implicit call to the toString method
    delete data.toString;
}
doAjax('my/url',{foo:'bar'},'post');

JS は通常のルーチンを実行しますtoString。メソッドのインスタンスをチェックし、それを見つけます。関数が呼び出され、適切な JSON 文字列が送信されます。その後、toStringメソッドは削除されます。
JS は、インスタンス自体でそのプロパティを検索します。メソッドが削除されるため、プロトタイプの toString メソッドはマスクされなくなります。次に呼び出されると、JS は同じトリックを実行しますが、メソッドを見つける代わりにdata、プロトタイプをスキャンし、通常のサービスが再開されます。
この答えが混沌としすぎていないことを願っていますが、私は非常に疲れているので、そうであれば: ごめんなさい

于 2012-12-05T12:52:39.857 に答える
0

対処ポイント 1: Engine.i と Engine.finish を使用して、静的フィールドを定義します。Engine.prototype.i と Engine.prototype.finish を使用するとよいでしょう。

于 2012-12-05T12:28:33.200 に答える