我是一名中等水平的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;
};
请解释我在继承函数中发生了什么以及扩展方法方法的好处
答案 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
)对象的原型之间创建了一个关系。通过这样做,构造函数返回的所有新实例将包含通常的主干模型方法(即:get和set),因为它们是从原型链中解析出来的。如果您想了解有关此特定代码块的更多信息,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"