2013-03-13 88 views
1

我希望能够将一堆不同变量的地址存储在数组中。这允许我通过名称访问变量,或者如果需要的话遍历它们。这在JS中可能吗?我可以在JavaScript中模拟C类指针数组吗?

(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(); 

我看了看这个:

JavaScript array of pointers like in C++

但我希望能够在赋值的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链接...我怎么做这不丑陋?

+1

为什么?你试图解决什么更大的问题?当然,有可能的解决方法,比如存储一个你可以改变的对象数组,但是这很糟糕,并且可能有更好的方法来实现你的最终目标。许多高级语言不允许您直接使用指针,但在绝大多数情况下您并不需要。我把我的钱放在这是其中的一种情况。 – 2013-03-13 05:00:07

+0

您当然无法访问任何实际的机器地址或获得性能改进。 – bchurchill 2013-03-13 05:02:18

+0

默认情况下,所有变量都是JavaScript中的引用,使得您想要做的事情不在门外。如果它已经是一个参考,将它放入另一个容器不会加快速度。 – 2013-03-13 05:21:25

回答

1

您的问题的第一部分的答案是使用一个对象。你在用C语言思考C程序员没有迭代结构,因此C程序员需要使用数组。在JS对象中是可迭代的。所以,你应该把它写成:

元= { 富: '富', 吧: '棒' }

或者,如果我们看看你的第二个例子:

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

现在,至于你的问题的第二部分。您的伪递归代码(伪代码,因为它不是真正的递归堆栈意义上的,因为它是异步的)现在可以与上面的apis对象一起使用。但是你通过键而不是对象:

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

显然,以上位可动态地通过API的对象迭代完成。总之,在代码的onSuccess部分分配的结果是这样的:

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

哦,明明objToInit现在应该apis[ary[0]]

现在做你期望这应该工作:

apis.a.doCoolStuff(); 
+0

是的,这基本上是我在找的东西。我可以使用字符串字段名称作为指向此对象的“指针”。我曾使用过对象迭代来解决这个问题,但我发现JS中的对象迭代有点丑陋和浪费。 for-in迭代对象的所有*字段,包括原型中的东西。当然,我可以使用'hasOwnProperty()'来避免那些东西,但重点是for-in应该只循环4次(在这种情况下)。额外的周期浪费时间。无论如何,谢谢你看这个! – awm129 2013-03-13 13:42:48

+0

如果您执行以下两项操作之一,则只需执行hasOwnProperty操作:使用继承或您(或第三方代码)修改Object对象的原型。否则,普通香草JavaScript不会通过空对象的原型导出任何东西,所以hasOwnProperty不是必需的。 – slebetman 2013-03-13 13:48:22

2

我可能会建议,如果您的主要目的是为了方便嵌套异步回调,您应该考虑延迟/承诺系统。

我已经手写了几个不同的承诺库。
jQuery自带了一个(就像大多数“ajax库”一样)。

下面是这可能是什么样子,在一个更美好的世界:

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

假设doThingOne返回一个承诺。

一个更熟悉的找接口谁使用jQuery(或其他大多数的承诺,利用大型图书馆),可能是这样的人:

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以上将举行两次私人阵列(一个为“成功”,一个为“失败”),并将扩展一个接口,允许应用程序的异步部分“成功”或“失败”,并将传入任何选择的数据/回调/等。

它还扩展了promise方法,该方法返回一个promise对象,该对象包含两个私有数组的订阅函数。因此,您将承诺对象传递给感兴趣的各方,并且在异步操作成功/失败时,它们预订回调以迭代遍历(并传递任何传递给操作方法的任何内容)。

这看起来像是添加自定义事件/侦听器等的倒置或扩展... 它就是这样。

抽象的好处是界面更清洁。

隐藏这玩意对象接口的内部,刚好路过周围异步承诺对象可以使你的代码看起来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 

而且做这样的事情有三个独立的异步操作,这可到达任何顺序,但必须在推进前都成功,那么你可以有这样的事情(再次jQuery,但也可以手动做)。

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

nextPhase,当然,如果所有三个承诺都成功完成,预计会被解雇。

我很乐意为准系统承诺系统提供实现细节,如果您像我一样,并且不喜欢在不首先了解每个部分如何独立工作并且能够复制的情况下使用不同的库其功能,无需复制代码。

+0

我非常喜欢这个解决方案的优雅。虽然它在游戏中有点迟了,以至于不能用于当前的应用程序,但我有兴趣看到未来的准系统实施。是的,像你一样,我鄙视使用巨型图书馆,直到我明白每件作品是如何独立运作的。 – awm129 2013-03-13 13:28:57