Backbone.js空数组属性

时间:2012-07-12 19:29:43

标签: javascript arrays backbone.js

我遇到了Backbone.js模型的一个奇怪问题,其中一个数组成员显示为空白。它看起来像这样:

var Session = Backbone.Model.extend({
    defaults: {
        // ...
        widgets: []
    },
    addWidget: function (widget) {
        var widgets = this.get("widgets");

        widgets.push(widget);
        this.trigger("change:widgets", this, widgets);
    },
    // ...
    // I have a method on the model to grabbing a member of the array
    getWidget: function (id) {
        console.log(this.attributes);
        console.log(this.attributes.widgets);

        // ...
    }
});

然后我通过addWidget添加一个小部件。在尝试getWidget时,我得到的结果(在Chrome中)是:

Object
    widgets: Array[1]
        0: child
        length: 1
        __proto__: Array[0]
    __proto__: Object
[]

它显示在记录this.attributes时窗口小部件不为空,但在记录this.attributes.widgets时显示为空。有谁知道会导致什么?

修改 我已经更改了模型以在初始化方法中实例化widgets数组,以避免跨多个实例的引用,并且我开始使用backbone-nested而没有运气。

3 个答案:

答案 0 :(得分:22)

小心信任控制台,通常会出现异步行为,可能会让你失望。

您希望console.log(x)的行为如下:

  1. 您致电console.log(x)
  2. x被转储到控制台。
  3. console.log(x)来电后立即继续执行该声明。
  4. 但事实并非如此,现实更像是这样:

    1. 您致电console.log(x)
    2. 浏览器会抓取对x的引用,并将“真正的”console.log电话排队等待以后。
    3. 运行(或不运行)各种其他JavaScript。
    4. 稍后,来自(2)console.log电话会将当前状态x转储到控制台,但此x不一定匹配(2)
    5. 中的x

      在你的情况下,你这样做:

      console.log(this.attributes);
      console.log(this.attributes.widgets);
      

      所以你有(2)

      这样的东西
               attributes.widgets
                   ^         ^
                   |         |
      console.log -+         |
      console.log -----------+
      

      然后在(3)中发生了一些事情,它实际上有this.attributes.widgets = [...](即更改attributes.widget引用),因此,当(4)来了,你有这个:

               attributes.widgets // the new one from (3)
                   ^
                   |
      console.log -+
      console.log -----------> widgets // the original from (1)
      

      这会让您看到两个不同版本的widgets:新版本的(3),而原始版本为空。

      执行此操作时:

      console.log(_(this.attributes).clone());
      console.log(_(this.attributes.widgets).clone());
      

      您抓取this.attributesthis.attributes.widgets附加到console.log来电的副本,因此(3)不会干扰您的参考资料你在控制台中看到了明智的结果。

      这就是答案:

        

      它显示在记录this.attributes时窗口小部件不为空,但在记录this.attributes.widgets时显示为空。有谁知道会导致什么?

      就潜在问题而言,您可能在某处进行了fetch调用,并且您没有考虑其异步行为。解决方案可能是绑定到"add""reset"事件。

答案 1 :(得分:1)

请记住,JS中的[]只是new Array()的别名,并且由于对象是通过引用传递的,因此Session模型的每个实例都将共享同一个数组对象。这会导致各种问题,包括阵列似乎是空的。

要以您想要的方式工作,您需要在构造函数中初始化您的窗口小部件数组。这将为每个Session对象创建一个唯一的widget数组,并且应该可以缓解您的问题:

var Session = Backbone.Model.extend({
    defaults: {
        // ...
        widgets: false
    },
    initialize: function(){
        this.set('widgets',[]);
    },
    addWidget: function (widget) {
        var widgets = this.get("widgets");

        widgets.push(widget);
        this.trigger("change:widgets", this, widgets);
    },
    // ...
    // I have a method on the model to grabbing a member of the array
    getWidget: function (id) { 
        console.log(this.attributes);
        console.log(this.attributes.widgets);
    // ...
    }
});

答案 2 :(得分:0)

使用Chrome和Firefox进行测试:http://jsfiddle.net/imsky/XBKYZ/

var s = new Session;
s.addWidget({"name":"test"});
s.getWidget()

控制台输出:

Object
widgets: Array[1]
__proto__: Object

[
Object
name: "test"
__proto__: Object
]