Backbone类模型不继承默认值

时间:2015-02-09 04:16:34

标签: javascript backbone.js coffeescript

我有一个骨干类:

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

class ExtendClass extends BaseClass
   defaults:
    last_name: "Doe"

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

我是否误解了Backbone如何扩展?

2 个答案:

答案 0 :(得分:3)

我认为您误解了 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")

这会在first_name默认值中为您提供last_nameExtendClass

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

答案 1 :(得分:2)

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