2015-02-09 95 views
1

我有一个主干类:骨干类模型不继承默认

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

class ExtendClass extends BaseClass 
    defaults: 
    last_name: "Doe" 

然而,当我做一个new ExtendClass,它没有first_name

我误解Backbone如何扩展?

回答

3

我想你是误解CoffeeScript如何扩展。当你说:

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

B::p值完全隐藏A::p,CoffeeScript的不会尝试将它们合并或链条他们或做什么特别的。

中的骨干模型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/

2

extend()帮手骨干,您可以扩展原型。在没有骨干网的普通的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