背景
看看爲什麼瀏覽器使用「child」在控制檯/調試器中顯示Backbone對象的類型是很有趣的。
所有的JavaScript對象都有一個構造函數屬性,它是用於創建對象的函數的引用。瀏覽器使用構造函數在控制檯/調試器中顯示對象的「類型」。如果構造函數的名稱屬性不爲空,它的值將被使用。
function A() { }
console.log(A.name); // 'A'
匿名函數有一個空的name屬性:但是,只有功能使用命名函數表達式得到一個有用的name屬性定義
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() { … }
};
更詳細的腳本可以在這裏找到:http://jsfiddle.net/danmalcolm/Xa7ma/6/
瀏覽器似乎從源代碼中得到這個名字 - 沒有一個JavaScript功能,可以在運行時告訴你函數分配給的第一個變量的名稱。其他瀏覽器支持使用在匿名構造函數上定義的displayName屬性的約定,但目前在Chrome中不存在:http://code.google.com/p/chromium/issues/detail?id=17356。
回到骨幹,你不使用自定義構造函數(見下文)假設,你的類型將最終獲得一個匿名構造函數中使用的模型,視圖,收集和路線爲Backbone's extend function創建如下:
child = function(){ return parent.apply(this, arguments); };
這就是爲什麼你在控制檯/調試器中看到Backbone對象旁邊的「孩子」。這是瀏覽器在對象構造函數的合適名稱下的最佳猜測。
解決方案
爲了讓你的對象更好的類型名稱,您可以通過第一個「protoProps」的說法提供了一個名爲構造函數時您可以在定義骨幹類型。只需添加一個包裝了呼叫「父」的一個構造屬性,如下所示:
var Product = Backbone.Model.extend({
constructor: function Product() {
Backbone.Model.prototype.constructor.apply(this, arguments);
}
});
您的產品型號實例現在看起來真的不錯在調試器。
對於您定義的每個視圖,模型,集合和路由,執行此操作有點麻煩。你可以猴子補丁骨幹的擴展功能爲你做的工作。
您首先需要建立一個用於定義類型名稱的約定。這裏,我們使用一個__name__
屬性,它可以指定如下:
var Product = Backbone.Model.extend({
__name__: 'Product'
// other props
});
你再更換所使用的模型,視圖,收集和路線來讀取此屬性和一個名爲構造函數添加到您的類型擴展功能。您不需要修改backbone.js本身,只需在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;
})();
哇,這應該只包括在骨幹默認....感謝萬丹,這是偉大的。 – MattyP 2013-02-26 16:50:10