extend
принимает два параметра protoProps
и staticProps
. protoProps
- это свойства, которые будут назначены прототипу Class, чтобы при создании экземпляра объекта это свойство было частью его цепочки прототипов 1 . staticProps
- это реквизиты, которые недоступны для объектов, созданных из класса (используя new
), но доступны из самого класса, например, путем вызова CatClass.defaultMeow
.
var extend = function(protoProps, staticProps) {
var parent = this;
var child;
В приведенном ниже обсуждении parent
- это то, что мы будем называть Базовым классом, классом, прототип которого мы хотим расширить до child
, который здесь мы будем называть Расширенным классом.
// The constructor function for the new subclass is either defined by you
// (the "constructor" property in your `extend` definition), or defaulted
// by us to simply call the parent constructor.
if (protoProps && _.has(protoProps, "constructor")) {
child = protoProps.constructor;
, если protoProps
является функцией или имеет свойство constructor
(это свойство, которое вызывается (как метод) всякий раз, когда вы вызываете new
для класса).
} else {
child = function() {
return parent.apply(this, arguments);
};
}
Если нет, то расширенный класс будет использовать constructor
родителя (при вызове new
он вызовет метод constructor
родителя).
// Add static properties to the constructor function, if supplied.
_.extend(child, parent, staticProps);
_.extend(target, src1,...,srcN)
метод UnderscoreJS делает поверхностную копию свойств исходных объектов для целевого объекта. Здесь копировались все родительские (статические) свойства, и все свойства передавались объекту staticProp
(если имеется) в новый расширенный класс.
// Set the prototype chain to inherit from `parent`, without calling
// `parent`'s constructor function and add the prototype properties.
child.prototype = _.create(parent.prototype, protoProps);
Это, вероятно, самая важная функция подпрограммы Backbone.extend: именно здесь Расширенный класс «наследует» цепочку прототипов базового класса. Например, если AnimalClass.prototype.walk
является методом в цепочке прототипов для AnimalClass
, _.create(parent.prototype, protoProps)
создаст новый класс с методом walk
в этой цепочке прототипов нового класса, а также все переданные protoProps
in. Это, по сути, _extended prototype chain`, и он назначается расширенному классу, как и его прототип.
child.prototype.constructor = child;
Эта строка сначала сбивает с толку, поскольку в приведенном выше условном выражении мы видели, что расширенному классу уже был назначен конструктор. Да, это так, но в последнем утверждении, когда мы сделали _.create(...)
, мы переписали конструктор расширенного класса конструктором базового класса! Теперь мы переназначаем это.
// Set a convenience property in case the parent's prototype is needed
// later.
child.__super__ = parent.prototype;
Как сказано в комментарии, расширенный класс имеет доступ к базовому классу в статическом свойстве *** * __super__
. Это удобное свойство, доступ к которому осуществляется из самого объекта Extended Class. В нашем предыдущем примере, если CatClass
расширен от AnimalClass
, то верно следующее: CatClass.__super__ === AnimalClass
.
return child;
};