Backbone class 模型不继承默认值

Backbone class model not inheriting defaults

我有一个 backbone class:

class BaseClass extends Backbone.Model
   defaults:
    first_name: "John"

class ExtendClass extends BaseClass
   defaults:
    last_name: "Doe"

但是,当我制作new ExtendClass时,它没有first_name

我是不是误解了 Backbone 的扩展方式?

我认为您误解了 CoffeeScript 的扩展方式。当你说:

class A
    p: ...
class B extends A
    p: ...

B::p 值完全隐藏了 A::p,CoffeeScript 不会尝试合并它们或链接它们或做任何特殊的事情。

Backbone 模型中的 defaults 可以是对象或函数,因此您可以使用函数和 CoffeeScript 的 super 自己合并它们:

class BaseClass extends Backbone.Model
   defaults: ->
       first_name: "John"

class ExtendClass extends BaseClass
   defaults: ->
       _(super).extend(last_name: "Doe")

这将为您提供 ExtendClass 默认值中的 first_namelast_name

演示:http://jsfiddle.net/ambiguous/wz6usg36/

Backbone 中的 extend() 助手允许您扩展原型。在没有 Backbone 的扩展方法的普通 JavaScript 中,我们可以设置原型链,如下例所示:

function BaseClass(opts) {
  // Here `this.defaults` will point to `BaseClass.prototype.defaults` 
  // when we create an instance of BaseClass. 
  // 
  // When we create an instance of ChildClass `this.defaults` will 
  // point to `ChildClass.prototype.defaults` if it exists, otherwise
  // it will point to `BaseClass.prototype.defaults`.
  this.attrs = _.extend({}, this.defaults, opts);

  // Call `BaseClass.prototype.initialize` or `ChildClass.prototype.initialize`, 
  // depending on what instance we're creating.
  this.initialize();
}

BaseClass.prototype.defaults = {
  first_name: 'anonymous',
  friend_count: 500
};

BaseClass.prototype.initialize = function() {
  console.log('Hello ' + this.attrs.first_name);
};


function ChildClass(opts) {
  // Let the base class set the `attrs` property 
  // and call the initialize() method.
  BaseClass.call(this, opts);
}

// Set the prototype chain
ChildClass.prototype = Object.create(BaseClass.prototype);

// Create own `defaults` object, therefore overriding
// the one higher in the prototype chain.
ChildClass.prototype.defaults = {
  last_name: 'backbone',
  parent_name: 'Unknown'
};

ChildClass.prototype.initialize = function() {
  // Do something...
};

从上面的示例中您可以看到 ChildClass 在其原型上设置了自己的 defaults 属性,因此当其中一个 ChildClass 实例查询 defaults、JavaScript 将在 ChildClass 原型对象中找到那个,不再进一步查找。

这正是 Backbone 在后台发生的情况。 Backbone 将查找名为 defaults 的 属性 并将其与实例的属性合并,因为 ChildClass 有自己的 defaults 属性、Backbone 不会再进一步​​查找,它不会自动为您合并 BaseClass 默认值。

但是,在 Backbone 中,您可以将 defaults 属性 设置为一个函数,然后您可以手动访问 BaseClass 的默认值,以便将它们与 ChildClass 的默认值合并。这种手动连接是有意的,因为 Backbone 不想假设任何关于您的对象层次结构(在这种情况下您的模型)。

在 JavaScript 中看起来像这样:

var Note = Backbone.Model.extend({
  defaults: {
    title: 'Untitled',
    message: 'Lorem ipsum dolor...'
  },

  initialize: function() { /* ... */ },
});

var PrivateNote = Note.extend({
  defaults: function() {
    var defaults = _.extend({}, { date: new Date() }, Note.prototype.defaults);

    // You can also do this if you don't want to specify `Note` by its name:
    // var defaults = _.extend({}, { date: new Date() }, this.constructor.__super__.defaults);

    // `__super__` is specific to Backbone and in this case 
    // it gives you access to `Note.prototype`.

    return defaults;
  },

  initialize: function() { /* ... */ },
});

现在我们得到了我们想要的:

var private = new PrivateNote();
private.toJSON();
//=> {date: Mon Feb 09 2015 00:57:14 GMT-0500 (EST), title: "Untitled", message: "Lorem ipsum dolor..."}

如我们所料,笔记实例未受影响:

var note = new Note()
note.toJSON();
//=> {title: "Untitled", message: "Lorem ipsum dolor..."}

这是一个 js2.coffee 示例:Merge defaults with Parent defaults