7

我是中等水平的 javascript 开发人员,试图了解骨干库在内部是如何工作的,如果有人帮助我解决一些挑战,我将不胜感激。

所以这就是我的理解

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

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

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

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

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

var user = new Backbone.Model() 

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

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

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;
};

请解释一下继承函数内部发生了什么以及扩展方法方法的好处是什么

4

1 回答 1

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 - 不要重复自己)。

现在,对于 Backbone 的Model.extend函数,它充当工厂方法来返回一个构造函数,该构造函数可用于创建模型的新实例,内部inherits函数完成大部分工作。该inherits函数将 mixin 概念更进一步,并在提供的对象和父对象(在本例中为对象)之间创建了一个继承链。Backbone.Model

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

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

_.extend(child, parent);

接下来我们调用 underscore 的 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;

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

这种方法的要点是,它允许您提供属性和函数的散列,生成的 Constructor 函数将用作蓝图,例如:

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"
于 2012-08-16T14:11:59.253 回答