Backbone.js 空数组属性

IT技术 javascript arrays backbone.js
2021-02-02 11:18:55

我遇到了一个 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有谁知道这会导致什么?

编辑 我已经更改了模型以在初始化方法中实例化小部件数组以避免跨多个实例的引用,并且我开始使用骨干嵌套但没有运气。

3个回答

信任控制台时要小心,经常有异步行为会让你失望。

你期望console.log(x)的行为是这样的:

  1. 你打电话console.log(x)
  2. x 转储到控制台。
  3. 在您console.log(x)调用之后立即继续执行语句

但事实并非如此,现实更像是这样:

  1. 你打电话console.log(x)
  2. 浏览器获取对 的引用x,并将“真实”console.log调用排入队列以备后用。
  3. JavaScript 的各种其他位运行(或不运行)。
  4. 后来,console.log从通话(2)得到周围倾倒的当前状态x到控制台,但这x并不一定匹配x,因为它是在(2)

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

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"事件。

那么,如果您不能信任 console.log,您将如何调试您的代码?
2021-04-02 11:18:55
关于 tesis 的精彩解释console.log()可以欺骗你” :)
2021-04-07 11:18:55
@shim:console.log(_(pancakes).clone())或者console.log(model.toJSON())如果您需要获取快照而不必担心console.log.
2021-04-07 11:18:55
这个答案让我开心,让我的头发免于被拔掉。我欠你一瓶啤酒先生。
2021-04-09 11:18:55

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

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

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);
    // ...
    }
});
我可以看到这将如何成为一个问题,但是即使使用模型的单个实例,问题仍然存在。initialize无论如何都尝试实例化数组,但我仍然遇到同样的问题。
2021-03-22 11:18:55

使用 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
] 
没有问题,只需编辑您的问题以反映所采取的所有步骤。
2021-04-03 11:18:55
可能应该更清楚 - 在尝试之前,我实际上向小部件数组添加了一些内容getWidget
2021-04-04 11:18:55