为什么我的 javascript Backbone.js 模型共享相同的“实例”他们的父类?
编辑:修复了我的示例以演示行为。
我希望 AbstractParent 的 details
属性成为我所说的“实例属性”,但它的行为更像是“静态属性”财产”。我意识到这些术语不适合 javascript,那么为什么当我创建一个新的子类时它没有获得自己独特的 AbstractParent 原型呢?为什么他们共用同一个?
在下面的代码中,我期望一个空警报,但我得到的是“新详细信息”,
var AbstractParent = Backbone.Model.extend({
details: [],
addDetail: function(detail) {
this.details.push(detail);
},
getDetails: function() {
var rtn = '';
for(var i=0;i<this.details.length;i++) {
rtn += this.details[i];
}
return rtn;
}
});
var Child = AbstractParent.extend({});
var ch1 = new Child;
ch1.addDetail("new details");
var ch2 = new Child;
alert(ch2.getDetails()); // => 'new details'
这似乎只有当 details
是数组时才有效。如果它是字符串或对象,则它不会被 ch1
和 ch2
共享。
EDIT: Fixed my example to demonstrate the behavior.
I wanted the details
property of AbstractParent to be what I would call an "instance property" but it's acting more like a "static property". I realize these terms are not appropriate for javascript, so why when I create a new child class does it not get its own unique AbstractParent prototype? Why do they share the same one?
In the code below I expect an empty alert, but instead I get 'new details'
var AbstractParent = Backbone.Model.extend({
details: [],
addDetail: function(detail) {
this.details.push(detail);
},
getDetails: function() {
var rtn = '';
for(var i=0;i<this.details.length;i++) {
rtn += this.details[i];
}
return rtn;
}
});
var Child = AbstractParent.extend({});
var ch1 = new Child;
ch1.addDetail("new details");
var ch2 = new Child;
alert(ch2.getDetails()); // => 'new details'
This seems to only work this way when details
is an array. If it is a string or an object then it is not shared by ch1
and ch2
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
好吧,我明白了这个问题。我原来的问题的代码不准确,所以我向其他响应者道歉(他们在我提供的代码的上下文中是正确的)。
解决方案描述如下:
原型化的 Javascript 对象成员因为数组被所有类实例共享
基本上,两个 Child 实例共享同一个 AbstractParent 函数作为其原型,这意味着 AbstractParent 中的任何更改都将反映在两个子实例的原型中。
这只在使用数组时才会显现出来,因为我在原型中初始化了数组,然后只是更改它,而不是在 addDetail 函数中覆盖它。当我使用对象或字符串作为属性名称然后进行赋值时,函数调用时上下文中的
this
属于 Child 实例,因此执行this.name = AbstractParent 函数中的 'Billy';
实际上是将其附加到 Child 实例,而不是 AbstractParent 中。我认为每个 Child 实例都会获得自己的 AbstractParent 原型实例,并且当我访问 this.name 时,它不会在 Child 上找到它,而是会转到this.prototype.name
。在我的问题的代码中,我可以通过向 AbstractParent 添加一个
initialize
函数来实例化详细信息数组来解决此问题。但是,如果我向 Child 添加一个initialize
函数,并且没有调用其中的父构造函数,那么我将遇到与以前相同的问题。Okay, I figured out the issue. My original question's code was not accurate so I apologize to the other responders (they were correct in the context of the code I presented).
The solution is described here:
Javascript object members that are prototyped as arrays become shared by all class instances
Basically, the fact that both Child instances share as their prototype the same AbstractParent function means that changing anything in AbstractParent will be reflected in both of the children's prototypes.
The reason this only manifests itself when using an array is because I initialized the array in the prototype and then just alter it rather than overwriting it in the
addDetail
function. When I used objects or strings for the property names and then did an assignment, thethis
in the context at the time of the function call belongs to the Child instance, so doingthis.name = 'Billy';
in an AbstractParent function is in fact attaching that to the Child instance instead, and not in the AbstractParent. I was thinking each Child instance would get its own AbstractParent prototype instance and that when I accessed this.name it wouldn't find it on the Child and would go tothis.prototype.name
instead.In the code in my question I can fix this by adding an
initialize
function to AbstractParent that instantiates the details array. But if I were to add aninitialize
function to the Child and I did not make a call to the parent constructor in it then I would have the same issue as before.您已将名称属性(或对象)分配给基础 AbstractParent,并且定义了从该基础扩展的两个对象。因此,每个对象都独立地具有此名称对象,尽管它们默认为在基类中分配的值。
在您的代码中,尽管您已将 ch1.name 分配给“Billy”,但您没有执行任何操作来更改 ch2 的 name 值。我认为你的代码示例实际上是错误的。警报显示的值应为“默认名称”。
您可以在浏览器中加载backbone.js,然后转到调试器控制台,然后再次输入上述语句吗?如果你这样做,我想你会发现你所期望的行为。
You have assigned a name property (or object) to the base, AbstractParent, and you have defined two Objects which extend from this base. As such, each independently has this name object, though they default to the value assigned in the base.
In your code, though you have assigned ch1.name to 'Billy', you have done nothing to change the value of name for ch2. I contend that your code example is actually wrong. The value displayed by the alert should be 'Default Name'.
Could you load backbone.js in a browser, then go to the debugger console, and enter your above statements in again? If you do, I think you'll find the behavior you expect.
您是说当您更改 ch1.name 时,它也会更改 ch2.name 吗?我运行了您的确切代码,但没有得到该结果。 ch2.name 仍然是“默认名称”。
在查找 name 属性时,我的浏览器在设置 ch1.name = "Billy"...
ch1
inherits.child (您的 ch1 实例)
后采用以下路线
ch2
打开调试控制台,Firefox 中的 Firebug 或 Chrome 中的开发人员工具/Javascript 控制台。
Are you saying when you change ch1.name, it also changes ch2.name? I ran your exact code and did not get that result. ch2.name was still "Default name".
When looking for the name property, my browser took the following routes after setting ch1.name = "Billy"...
ch1
inherits.child (your ch1 instance)
ch2
Open up a debug console, either Firebug in Firefox or Developer Tools / Javascript console in Chrome.