为什么我的javascript Backbone.js模型共享其父类的相同“实例”?

时间:2011-05-26 19:05:58

标签: javascript backbone.js prototypal-inheritance

编辑:修复我的示例来演示行为。

我希望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是一个数组时,这似乎只是这样。如果它是字符串或对象,则ch1ch2不会共享它。

3 个答案:

答案 0 :(得分:2)

好的,我发现了这个问题。我的原始问题的代码不准确所以我向其他响应者道歉(他们在我提供的代码的上下文中是正确的。)

此处描述了解决方案: Javascript object members that are prototyped as arrays become shared by all class instances

基本上,两个Child实例共享相同的AbstractParent函数作为其原型的事实意味着在AbstractParent中更改任何内容将反映在两个子项的原型中。

这个仅在使用数组时表现出来的原因是因为我在原型中初始化了数组,然后只是改变它而不是在addDetail函数中覆盖它。当我使用对象或字符串作为属性名称然后进行赋值时,函数调用时上下文中的this属于Child实例,因此在AbstractParent函数中执行this.name = 'Billy';是实际上将它附加到Child实例,而不是在AbstractParent中。我认为每个Child实例都会获得自己的AbstractParent原型实例,当我访问this.name时,它不会在Child上找到它,而是转到this.prototype.name

在我的问题中的代码中,我可以通过向AbstractParent添加initialize函数来解决这个问题,该函数实例化了details数组。但是,如果我要向Child添加一个initialize函数,并且我没有调用其中的父构造函数,那么我将遇到与以前相同的问题。

答案 1 :(得分:1)

您已经为基础AbstractParent分配了一个名称属性(或对象),并且您已经定义了两个从此基础扩展的对象。因此,每个都独立地具有此名称对象,但它们默认为基础中指定的值。

在您的代码中,虽然您已将ch1.name指定给'Billy',但您没有做任何更改ch2的name值。我认为你的代码示例实际上是错误的。警报显示的值应为“默认名称”。

您可以在浏览器中加载backbone.js,然后转到调试器控制台,再次输入上述语句吗?如果你这样做,我想你会找到你期望的行为。

答案 2 :(得分:1)

你是说当你改变ch1.name时,它也会改变ch2.name?我运行了你的确切代码并没有得到那个结果。 ch2.name仍然是“默认名称”。

在查找name属性时,我的浏览器在设置ch1.name =“Billy”之后采用了以下路由......

<强> CH1

  • inherits.child(你的ch1实例)

    • 姓名:“Billy”

<强> CH 2

  • inherits.child(你的ch2实例)
    • __ proto__(你的SecondChild原型)
      • __ proto__(您的AbstractParent原型)
        • 名称:“默认名称”

打开调试控制台,Firefox中的Firebug或Chrome中的Developer Tools / Javascript控制台。