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 []
它显示了在loggingthis.attributes
时widgets不是空的,但是在loggingthis.attributes.widgets
时显示为空。 有谁知道这会导致什么?
编辑我已经改变了模型实例初始化方法中的小部件数组,以避免跨多个实例的引用,我开始使用骨干嵌套与没有运气。
小心信任控制台,经常有asynchronous行为,可以让你起来。
你期待console.log(x)
的行为是这样的:
- 你可以调用
console.log(x)
。 -
x
被转储到控制台。 - 在
console.log(x)
调用之后立即执行语句。
但事实并非如此,现实更像是这样:
- 你可以调用
console.log(x)
。 - 浏览器抓取对
x
的引用,并在稍后将“真实”console.log
调用队列。 - 各种其他的JavaScript运行(或不)。
- 后来,来自(2)的
console.log
调用开始将x
的当前状态转储到控制台中,但是这个x
不一定与(2)中的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)中接收到的新widgets
和空的原件。
当你这样做:
console.log(_(this.attributes).clone()); console.log(_(this.attributes.widgets).clone());
你正在抓取连接到console.log
调用的this.attributes
和this.attributes.widgets
副本,所以(3)不会干扰你的引用,并且在控制台中看到明智的结果。
这就是答案:
它显示了在logging
this.attributes
时widgets不是空的,但是在loggingthis.attributes.widgets
时显示为空。 有谁知道这会导致什么?
就基本问题而言,您可能在某个地方有一个fetch
调用,并且没有考虑其asynchronous行为。 该解决scheme可能绑定到"add"
或"reset"
事件。
请记住,JS中的[]
只是new Array()
的别名,并且由于对象是通过引用传递的,所以Session模型的每个实例都将共享相同的数组对象。 这会导致各种问题,包括数组显示为空。
要按照你想要的方式工作,你需要在构造函数中初始化你的widgets数组。 这将为每个Session对象创build一个唯一的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); // ... } });
使用Chrome和Firefox进行testing: 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 ]