解释骨干对象和类创建模式

时间:2012-08-16 13:22:26

标签: javascript backbone.js

我是一名中等水平的javascript开发人员,他正试图了解骨干图书馆如何在内部工作,如果有人帮我解决一些挑战,我会深表感激。

所以这就是我的理解

Backbone中构造函数的基本定义是

Backbone.Model = function(attributes, options) { }

然后他们使用通用扩展方法在我们的构造函数原型中添加常用功能。

_.extend(Backbone.Model.prototype, Backbone.Events, {...})

现在直到这一部分我确切知道发生了什么,并且很乐意通过以下代码实例化新对象

var user = new Backbone.Model() 

,这是我发现具有挑战性的部分

当然,这不是我们在Backbone中实例化对象的方式,但我们使用extend方法

var Users = Backbone.Model.extend({});
var user = new Users()

和骨干代码

Backbone.Model.extend = extend;

var extend = function(protoProps, classProps) {
        var child = inherits(this, protoProps, classProps);
        child.extend = this.extend;
        return child;
};

var inherits = function(parent, protoProps, staticProps) {
    var child;
    if (protoProps && protoProps.hasOwnProperty('constructor')) {
        child = protoProps.constructor;
    } else {
        child = function() {
            return parent.apply(this, arguments);
        };
    }
    _.extend(child, parent);
    ctor.prototype = parent.prototype;
    child.prototype = new ctor();
    if (protoProps) _.extend(child.prototype, protoProps);
    if (staticProps) _.extend(child, staticProps);
    child.prototype.constructor = child;
    child.__super__ = parent.prototype;
    return child;
};

请解释我在继承函数中发生了什么以及扩展方法方法的好处

1 个答案:

答案 0 :(得分:10)

Underscore的extend函数将第二个参数的成员(函数和属性)合并到第一个参数中。例如:

var reciever = { 
    name: "Jonny",
    age: 29
};

var supplier: {
    languages: [ "javascript", "actionscript" ];
    sayHi: function () { 
        console.log("Hi, name name is " + this.name);
    }
};

_.extend(receiver, supplier);

执行上面的代码后,接收器对象将被扩充(修改),现在看起来像这样:

/*
    {
        age: 29,
        languages: [ "javascript", "actionscript" ],
        name: "Jonny",
        sayHi: <<function>>
    }
*/
console.dir(receiver);

请注意,供应商对象保持不变,接收方对象从供应商处获得所有属性和功能。此过程通常称为mixin,用于避免重新声明函数(作为更广泛的编程原则的一部分,知道DRY - Don't Repeat Yourself)。

现在对于Backbone的Model.extend函数,它充当factory method以返回构造函数,该函数可用于创建模型的新实例,内部inherits函数正在执行大部分工作。 inherits函数将mixin概念更进一步,在提供的对象和父对象之间创建inheritance chain(在此特定情况下为Backbone.Model对象)。

var child;
if (protoProps && protoProps.hasOwnProperty('constructor')) {
    child = protoProps.constructor;
} else {
    child = function() {
        return parent.apply(this, arguments);
    };
}

第一个代码块试图在提供的对象哈希中找到构造函数;如果一个不存在,那么它会为你创建一个新的构造函数,它会自动将提供的参数传递给Backbone.Model自己的constructor function

_.extend(child, parent);

接下来,我们调用下划线的extend方法,将所有属性和函数从提供的属性和函数的散列混合到构造函数中;这可以确保您创建的每个实例都拥有自己的数据(例如:属性不是静态的,并且在您创建的所有实例中共享)。

ctor.prototype = parent.prototype;
child.prototype = new ctor();
if (protoProps) _.extend(child.prototype, protoProps);
if (staticProps) _.extend(child, staticProps);
child.prototype.constructor = child;
child.__super__ = parent.prototype;

这个最后的块是最令人兴奋的,它在新创建的Constructor函数的原型和父(Backbone.Model)对象的原型之间创建了一个关系。通过这样做,构造函数返回的所有新实例将包含通常的主干模型方法(即:getset),因为它们是从原型链中解析出来的。如果您想了解有关此特定代码块的更多信息,Douglas Crockford's article on Prototypal inheritance是一个很好的起点。

这种方法的关键在于它允许您提供属性和函数的哈希值,结果构造函数将用作蓝图,例如:

var Person = Backbone.Model.extend({
    name: "Jon Doe",
    sayHi: function () { 
        console.log("Hi, my name is " + this.get("name"));
    }
});

现在,您实例化的每个Person对象都将具有name属性和sayHi函数,例如:

var dave = new Person();
dave.sayHi();   // "Hi, my name is Jon Doe"

dave.set("name", "Dave");
dave.sayHi();   // "Hi, my name is Dave"

// You can also supply properties when invoking the constructor.
var jimmy = new Person({ name: "Jimmy" });
jimmy.sayHi();  // "Hi, my name is Jimmy"