1

さまざまな変数のアドレスを配列に格納できるようにしたいと思います。これにより、名前で変数にアクセスしたり、必要に応じて変数を反復処理したりできます。これはJSで可能ですか?

(function(ns){

    ns.obj = new function(){

        var foo = "foo";
        var bar = "bar";

        //i really want this:
        //var ary = [&foo, &bar];
        var ary = [foo, bar];


        this.print = function() {
            console.log( foo );
            console.log( bar );
        }

        this.setFoo = function( newFoo ) {
            //i really want this:
            //*(ary[0]) = newFoo;
            ary[0] = newFoo;
        }

        this.printAry = function() {
            for( var i=0; i < ary.length; ++i ) {
                console.log( ary[i] );
            }
        }
    };

}(window.ns = window.ns || {}) );

ns.obj.print();
ns.obj.setFoo("newfoo!");
ns.obj.printAry();
ns.obj.print();

私はこれを見ました:

C++のようなポインタのJavaScript配列

しかし、割り当てのLHSでの要素を使用できるようにしたいとary思います。この状況では、この例は機能しないと思います。

なぜ私はこれをしたいのですか?

これまでのところ、多くのコメントが(当然のことながら)私がこれをやりたい理由を尋ねてきました。非同期オブジェクト初期化メカニズムを含む独自のAPIを扱っています。基本的に、オブジェクトのインスタンスを作成し、それをこの初期化子に渡して、実際に使用できるようにします。イニシャライザには、初期化が成功したことを通知するonSuccessハンドラのフィールドが含まれています。完全に初期化されたオブジェクトは、引数としてこの成功ハンドラーに渡されるため、オブジェクトへの参照を取得できます。

その後、次のオブジェクトを自由に初期化できます。それはちょっとこのように見えます:

     var a = new api.ApiObject();
     var b = new api.ApiObject();
     var c = new api.ApiObject();
     var d = new api.ApiObject();

     //omg this is ugly
     api.initializeObject( {
         objToInit: a,
         onSuccess: function(args) {
             a = args.obj;
             api.initializeObject( {
                 objToInit: b,
                 onSuccess: function(args) {
                     b = args.obj;
                     api.initializeObject( {
                         objToInit: c,
                         onSuccess: function(args) {
                             c = args.obj;
                             api.initializeObject( {
                                 objToInit: d,
                                 onSuccess: function(args) {
                                     d = args.obj;
                                 }
                             } );
                         }
                     } );
                 }
             } );
        }
    } );

    a.doCoolStuff();
    //and so on

この深くネストされた混乱は、私がさらに追加するにつれて悪化しますapi.ApiObjects()。では、これを修正するにはどうすればよいですか?APIを変更することはできませんが、再帰関数が役立つ可能性があります。

    //maybe a recursive function could make this more concise?
    function doInitialize( ary ) {
        api.initializeObject( {
            objToInit: ary[0];
            onSuccess: function(args) {
                //i'd like to assign this passed in reference to my local
                //reference outside this function (var a, b, etc).  
                //An array of pointers would be useful here.
                //how else can I get this assigned out, cuz this doesn't work...
                ary[0] = args.obj;
                if( ary.length > 1 ) {
                    ary.splice( 0, 1 );
                    doInitialize( ary );
                }
            }
        }
    }

    doInitialize( [a,b,c,d] );

    //this won't work because I don't have a reference to the fully initialized object
    a.doCoolStuff();

したがって、おそらくより良い質問は、このような非同期の成功連鎖を処理するための確立されたパターンがありますか?他のパブリックJSフレームワーク(dojoなど)がこの種のonSuccessチェーンを使用しているのを見たことがあると思います...これを醜くしないようにするにはどうすればよいですか?

4

2 に答える 2

2

これの主な目的が非同期コールバックのネストに関する利便性である場合は、遅延/約束システムを検討する必要があることをお勧めします。

私はいくつかの異なるpromiseライブラリを手作業で作成しました。
jQueryには1つが組み込まれています(ほとんどの「ajaxライブラリ」と同様)。

より良い世界では、これは次のようになります。

doThingOne()
    .then(doThingTwo)
    .then(doThingThree)
    .then(launch);

doThingOneそれが約束を返すと仮定します。

jQuery(または他のほとんどのpromiseを使用する大規模なライブラリ)を使用する人々にとって、より見慣れたインターフェイスは、次のようになります。

var imageLoader = $.Deferred(),
    loading     = imageLoader.promise();

loading
    .done(gallery.render.bind(gallery))
    .done(gallery.show.bind(gallery));

var img = new Image(),
    url = "...";

img.onload  = function () { imageLoader.resolve(img); };
img.onerror = function () { imageLoader.reject("error message"); };
img.src = url;

非常に基本的に、Deferred上記は2つのプライベート配列(1つは「成功」用、もう1つは「失敗」用)を保持し、アプリケーションの非同期部分を「成功」または「失敗」させて渡すことができるインターフェイスを拡張します。データ/コールバックなどとして選択されたものは何でも。

またpromise、2つのプライベート配列のサブスクリプション関数を含むpromiseオブジェクトを返すメソッドを拡張します。.resolveしたがって、promiseオブジェクトを関係者に渡し、関係者は、非同期操作の成功/失敗時に、繰り返されるコールバックをサブスクライブします(そして、操作の/.rejectメソッドに渡されるものはすべて渡します)。

これは、カスタムイベント/リスナーなどを追加するだけの反転または拡張のように見えるかもしれません...そしてそれはそうです。

抽象化の利点は、インターフェースがよりクリーンになることです。

このようなものをオブジェクトインターフェイス内に隠し、非同期のpromise-objectsを渡すだけで、コードを100%同期しているように見せることができます。

var images  = ImageLoader(),
    gallery = ImageGallery(),
    photo;


photo = images.load("//url.com/image.png"); // assuming `.load` returns a promise object
gallery.show(photo); // just a promise object, but internally,
                     //`.show` would subscribe a private method to the promise object

そして、3つの別々の非同期操作を行うなど、任意の順序で到着できますが、先に進む前にすべて成功する必要があります。そうすれば、次のようなことができます(jQueryも同様ですが、手動で行うことも可能です)。

$.when(promise_obj_1, promise_obj_2, promise_obj_3)
.done(nextPhase);

もちろん、nextPhaseは、3つのプロミスがすべて正常に完了した場合に発生すると予想されるコールバックです。

あなたが私のようで、各部分がそれ自体でどのように機能するかを最初に理解し、その機能を複製することなく、異なるライブラリを使用するのが好きでない場合は、ベアボーンプロミスシステムの実装の詳細を提供できれば幸いです。コードをコピーしています。

于 2013-03-13T06:55:37.580 に答える
1

質問の最初の部分に対する答えは、オブジェクトを使用することです。あなたは反復可能な構造体を持たないCで考えているので、Cプログラマーは配列に手を伸ばします。JSでは、オブジェクトは反復可能です。したがって、次のように記述する必要があります。

ary = {foo:'foo'、bar:'bar'}

または、2番目の例を見ると:

var apis = {
    a : new api.ApiObject(),
    b : new api.ApiObject(),
    c : new api.ApiObject(),
    d : new api.ApiObject()
}

さて、あなたの質問の2番目の部分についてです。疑似再帰コード(非同期であるため、スタックの意味では実際には再帰的ではないため、疑似)はapis上記のオブジェクトで機能するようになります。ただし、オブジェクトの代わりにキーを渡します。

doInitialize( ['a','b','c','d'] );

明らかに、上記のビットは、apisオブジェクトを反復処理することで動的に実行できます。とにかく、onSuccessコードの一部で、次のように結果を割り当てます。

apis[ary[0]] = args.obj;

ああ、そして明らかにobjToInit今はそうあるべきapis[ary[0]]です。

これを行うと、期待どおりに機能するはずです。

apis.a.doCoolStuff();
于 2013-03-13T07:22:41.527 に答える