- PVSM.RU - https://www.pvsm.ru -
Коллеги, использующие Backbone.js! Вы задумывались, как работает наследование в этой библиотеке?
Знаете, как себя ведет Backbone.Model.extend({})
?
И наверняка знаете и помните, что у extend два опциональных параметра: proto props и static props.
Если хотя бы на один выше заданный вопрос вы ответили отрицательно — прошу под кат.
Постараюсь порадовать пошаговым исследованием, схемками, табличками и примерами.
Лично для меня понимание того, как работает используемая библиотека/компонент (особенно та, которую использую чаще всего) является чем-то обязательным и важным. Почему?
Уже давно меня интересовал вопрос наследования в Backbone.js
И вот я решился, открыл исходники, и… приступим!
Сразу же оговорюсь: наследование работает одинаково для всех сущностей библиотеки, будь то Model, View, Collection или Router. В данной статье я для примера буду использовать View.
С документации [1] нам известно, что метод extend имеет два параметра: properties и classProperties.
Backbone.View.extend(properties, [classProperties])
Также можно понять, что только classProperties — параметр необязательный, но на самом деле и properties является таковым.
И если первый аргумент нормально описан для всех сущностей, то о предназначении второго (classProperties) нам намекают лишь в документации к Model и Collection:
To create a Collection class of your own, extend Backbone.Collection, providing instance properties, as well as optional classProperties to be attached directly to the collection's constructor function
Подобно деббагеру developer tools, пройдемся по методу extend.
Испытуемый код:
Backbone.View.extend({
testProp1: true
}, {
testProp2: true
});
// Helper function to correctly set up the prototype chain, for subclasses.
// Similar to `goog.inherits`, but uses a hash of prototype properties and
// class properties to be extended.
var extend = function(protoProps, staticProps) {
var parent = this;
var child;
Из комментариев видим, что это аналог goog.inherits (с которым мне не приходилось сталкиваться) с некоторыми изменениями.
На первом этапе у нас есть:
Сразу же считаю необходимым разъяснить два момента:
1. Backbone.View Constructor — это функция-конструктор, которая служит для обработки опций, подписки на события, вызова метода initialize и прочих действий, которые являются очень важными в работе библиотеки и происходят «за кулисами».
2. Backbone.View.prototype — это набор стандартных методов и свойств: render, remove и т.п.
if (protoProps && _.has(protoProps, 'constructor')) {
child = protoProps.constructor;
} else {
child = function(){ return parent.apply(this, arguments); };
}
С неизвестным ранее существом child происходит кое-что интересное. Оно превращается либо в заданную функцию в первом параметре (protoProps) constructor, либо в Backbone.View Constructor. Пока что не зацикливаемся на этом и идем дальше.
_.extend(child, parent, staticProps);
Расширяем child всеми свойствами и методами Backbone.View Constructor и нашими staticProps.
На самом деле у конструктора Backbone.View нет никаких свойств и методов, скорее всего это сделано на всякий случай. Мало ли, появятся когда-нибудь, и extend не нужно будет переписывать.
var Surrogate = function(){ this.constructor = child; };
Surrogate.prototype = parent.prototype;
child.prototype = new Surrogate;
Появляется некий Surrogate. Это prototype нашего с вами child, у которого свойство constructor — это child (да да, он же) и prototype — Backbone.View.prototype.
Его предназначение в том, что вместо расширения child'a свойствами и методами Backbone.View.prototype мы просто добавляем их в качестве прототипа, тем самым экономим драгоценную память.
if (protoProps) _.extend(child.prototype, protoProps);
child.__super__ = parent.prototype;
return child;
Добавляем к прототипу child (Surrogate) свойства и методы из protoProps (первый аргумент функции extend) и создаем свойство __super__, которое будет ссылкой на Backbone.View.prototype.
В итоге мы получаем жирненький конструктор (child), который выглядит примерно так:
Backbone оказался более гибким, чем я думал.
Используя extend, мы можем задать, помимо стандартных свойств, статические. Они будут доступны для использования в контексте конструктора а также через свойство constructor.
Также мы можем легко использовать свой конструктор, лишь задав его в свойстве constructor в первом параметре метода extend.
Во второй части статьи мы подробно рассмотрим возможности, которые дает нам такой принцип наследования.
Автор: Leestex
Источник [2]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/41204
Ссылки в тексте:
[1] документации: http://backbonejs.org/
[2] Источник: http://habrahabr.ru/post/190374/
Нажмите здесь для печати.