Ответ 1
Фон
Интересно посмотреть, почему браузер использует "child" для отображения типа объектов Backbone в консоли/отладчике.
Все объекты JavaScript имеют свойство constructor, ссылку на функцию, используемую для создания объекта. Конструктор используется браузером для отображения объектов "type" в консоли/отладчике. Значение свойства имени функции конструктора будет использоваться, если оно не пустое. Однако только функции, определенные с помощью названных функциональных выражений, получают полезное свойство имени:
function A() { }
console.log(A.name); // 'A'
Анонимные функции имеют свойство пустого имени:
var B = function() { };
console.log(B.name); // ''
Итак, что происходит с анонимными функциями? Chrome указывает имя анонимных функций из имени переменной или свойства, которому была назначена функция. Вот несколько примеров:
// 1. named function expression - objects will show as "a" in the console
function a() { … }
// 2. anonymous function assigned to variable - objects will show as "b" in the console
var b = function(){ … };
// 3. anonymous function assigned to property of object - objects will show as "container.c" in the debugger
var container = {
c: function() { … }
};
Более подробный script доступен здесь: http://jsfiddle.net/danmalcolm/Xa7ma/6/
Браузер, как представляется, получает это имя из исходного кода - не существует функции JavaScript, которая может указывать во время выполнения имя первой переменной, которой была назначена функция. Другие браузеры поддерживают соглашение, в котором используется свойство displayName, определенное в функциях анонимного конструктора, но в настоящее время это не происходит в Chrome: http://code.google.com/p/chromium/issues/detail?id=17356.
Возвращаясь к Магине, предполагая, что вы не используете собственный конструктор (см. ниже), ваш тип будет иметь анонимную конструкторскую функцию, созданную в функции продления базы используется Model, View, Collection и Route следующим образом:
child = function(){ return parent.apply(this, arguments); };
Вот почему вы видите "child" рядом с вашими объектами Backbone в консоли/отладчике. Это браузеры лучше всего угадывают подходящее имя для вашего конструктора объектов.
Решения
Чтобы дать вашим объектам лучшее имя типа, вы можете предоставить именованный конструктор через первый аргумент "protoProps" при определении типов Backbone. Просто добавьте свойство конструктора, которое обертывает вызов конструктору "parent" следующим образом:
var Product = Backbone.Model.extend({
constructor: function Product() {
Backbone.Model.prototype.constructor.apply(this, arguments);
}
});
В отладчике теперь будут выглядеть действительно хорошие экземпляры модели продукта.
Это немного громоздко сделать для каждого вида, модели, коллекции и маршрута, которые вы определяете. Вы можете использовать обезьянную патч Backbones, чтобы выполнять работу за вас.
Сначала вам нужно установить соглашение для определения имен ваших типов. Здесь мы используем свойство __name__
, которое вы указываете следующим образом:
var Product = Backbone.Model.extend({
__name__: 'Product'
// other props
});
Затем вы заменяете функцию расширения, используемую Model, View, Collection и Route, чтобы прочитать это свойство и добавить именованный конструктор к вашему типу. Вам не нужно изменять сам backbone.js, просто включите следующее в отдельный script, который загружается после backbone.js.
(function () {
function createNamedConstructor(name, constructor) {
var fn = new Function('constructor', 'return function ' + name + '()\n'
+ '{\n'
+ ' // wrapper function created dynamically for "' + name + '" constructor to allow instances to be identified in the debugger\n'
+ ' constructor.apply(this, arguments);\n'
+ '};');
return fn(constructor);
}
var originalExtend = Backbone.View.extend; // Model, Collection, Router and View shared the same extend function
var nameProp = '__name__';
var newExtend = function (protoProps, classProps) {
if (protoProps && protoProps.hasOwnProperty(nameProp)) {
// TODO - check that name is a valid identifier
var name = protoProps[nameProp];
// wrap constructor from protoProps if supplied or 'this' (the function we are extending)
var constructor = protoProps.hasOwnProperty('constructor') ? protoProps.constructor : this;
protoProps = _.extend(protoProps, {
constructor: createNamedConstructor(name, constructor)
});
}
return originalExtend.call(this, protoProps, classProps);
};
Backbone.Model.extend = Backbone.Collection.extend = Backbone.Router.extend = Backbone.View.extend = newExtend;
})();