调试 Javascript(Backbone 和 Marionette)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14866014/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Debugging Javascript (Backbone and Marionette)
提问by MattyP
Right now, while I am debugging backbone or marionette using the chrome dev tools, I end up setting break points and whatnot, but once the code pauses, its hard to tell what type of objects i'm working with because chrome labels everything a "child".
(I think because that's the constructor function)
现在,当我使用 chrome 开发工具调试主干或牵线木偶时,我最终设置了断点等等,但是一旦代码暂停,就很难判断我正在使用什么类型的对象,因为 chrome 将所有内容都标记为“孩子”。
(我想是因为那是构造函数)
Is there any easy way to either change this declaration or determine which type of model/collection i'm using.
是否有任何简单的方法可以更改此声明或确定我正在使用哪种类型的模型/集合。
The amount craziness this causes in me wants to start doing something like this:
这在我身上引起的疯狂程度想开始做这样的事情:
MyModel = Backbone.Model.Extend({
// the $$$ puts it at the top of the inspector, the NAME is just for other devs
$$$NAME = "MyModel",
...
});
I don't really like it, because its... ugly, its a variable... and it only helps when I inspect and expand the variable... it would be great to change the name chrome uses to display it.
我真的不喜欢它,因为它......丑陋,它是一个变量......它只在我检查和扩展变量时有帮助......改变chrome用来显示它的名称会很棒。
In any case, does anyone know how to change the name? or have some other cleaner convention you use?
无论如何,有人知道如何更改名称吗?或者您使用其他一些更清洁的约定?
Thanks!
谢谢!
Matt
马特
回答by Dan Malcolm
Background
背景
It is interesting to look at why the browser uses “child” to display the type of Backbone objects in the console / debugger.
看看为什么浏览器在控制台/调试器中使用“child”来显示 Backbone 对象的类型是很有趣的。
All JavaScript objects have a constructor property, a reference to the function used to create the object. The constructor is used by the browser to display the object's “type” in the console / debugger. The value of the constructor function's name property will be used if it is not empty. However, only functions defined using named function expressions get a useful name property:
所有 JavaScript 对象都有一个构造函数属性,它是对用于创建对象的函数的引用。浏览器使用构造函数在控制台/调试器中显示对象的“类型”。如果不为空,将使用构造函数的 name 属性的值。但是,只有使用命名函数表达式定义的函数才能获得有用的 name 属性:
function A() { }
console.log(A.name); // 'A'
Anonymous functions have an empty name property:
匿名函数有一个空的 name 属性:
var B = function() { };
console.log(B.name); // ''
So, what happens with anonymous functions? Chrome infers the name of anonymous functions from the name of the variable or property to which the function was first assigned. Here are some examples:
那么,匿名函数会发生什么?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() { … }
};
A more detailed script is available here: http://jsfiddle.net/danmalcolm/Xa7ma/6/
此处提供更详细的脚本:http: //jsfiddle.net/danmalcolm/Xa7ma/6/
The browser appears to get this name from the source code - there isn't a JavaScript feature that can tell you at runtime the name of the first variable that a function was assigned to. Other browsers support a convention where a displayName property defined on anonymous constructor functions is used, but this doesn't currently happen in Chrome: http://code.google.com/p/chromium/issues/detail?id=17356.
浏览器似乎是从源代码中获取这个名称的——没有 JavaScript 功能可以在运行时告诉您函数被分配给的第一个变量的名称。其他浏览器支持使用在匿名构造函数上定义的 displayName 属性的约定,但目前在 Chrome 中不会发生这种情况:http: //code.google.com/p/chromium/issues/detail?id=17356。
Returning to Backbone, assuming you're not using a custom constructor (see below), your type will end up with an anonymous constructor function, created in Backbone's extend functionused by Model, View, Collection and Route as follows:
回到 Backbone,假设您没有使用自定义构造函数(见下文),您的类型将以匿名构造函数结束,该函数在模型、视图、集合和路由使用的Backbone 的扩展函数中创建,如下所示:
child = function(){ return parent.apply(this, arguments); };
This is why you see “child” next to your Backbone objects in the console / debugger. It is the browser's best guess at a suitable name for your object's constructor.
这就是为什么您会在控制台/调试器中的 Backbone 对象旁边看到“child”。这是浏览器对对象构造函数的合适名称的最佳猜测。
Solutions
解决方案
To give your objects a better type name, you can supply a named constructor via the first “protoProps” argument when you define your Backbone types. Just add a constructor property that wraps a call to the “parent” constructor as follows:
为了给你的对象一个更好的类型名称,你可以在定义你的 Backbone 类型时通过第一个“protoProps”参数提供一个命名的构造函数。只需添加一个构造函数属性来包装对“父”构造函数的调用,如下所示:
var Product = Backbone.Model.extend({
constructor: function Product() {
Backbone.Model.prototype.constructor.apply(this, arguments);
}
});
Your Product model instances will now look reallynice in the debugger.
您的 Product 模型实例现在在调试器中看起来非常漂亮。
It is a bit cumbersome to do this for every View, Model, Collection and Route that you define. You can monkey patch Backbone's extend function to do the work for you.
对你定义的每个 View、Model、Collection 和 Route 都这样做有点麻烦。您可以对 Backbone 的扩展功能进行猴子补丁来为您完成这项工作。
You first need to establish a convention for defining the names of your types. Here we're using a __name__
property, which you specify as follows:
您首先需要建立一个约定来定义您的类型的名称。这里我们使用了一个__name__
属性,您可以按如下方式指定:
var Product = Backbone.Model.extend({
__name__: 'Product'
// other props
});
You then replace the extend function used by Model, View, Collection and Route to read this property and add a named constructor to your type. You don't need to modify backbone.js itself, just include the following in a separate script that is loaded after backbone.js.
然后替换 Model、View、Collection 和 Route 使用的扩展函数来读取此属性,并向您的类型添加命名构造函数。您不需要修改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;
})();
回答by jevakallio
Yes. You can change the console display name by overriding a model/collection/view constructor
using a named function expression. It may also be helpul to override toString
to control the console output when the model is forced to string type with, say, the +
operator:
是的。您可以通过constructor
使用命名函数表达式覆盖模型/集合/视图来更改控制台显示名称。toString
当模型被迫使用例如+
操作符的字符串类型时,覆盖以控制控制台输出也可能会有所帮助:
App.Model = Backbone.Model.extend({
//define constructor using a named function expression
constructor: function Model() {
Backbone.Model.prototype.constructor.apply(this, arguments);
},
//override toString to return something more meaningful
toString: function() {
return "Model(" + JSON.stringify(this.attributes) + ")";
}
});
So with:
所以用:
var model = new Model({id:1,foo:"bar"})
console.log("state: " + model);
console.log(model);
You'll get:
你会得到:
state: Model({"id":1,"foo":"bar"})
? Model
回答by Josh Bedo
Also try adding
也尝试添加
"use strict"
at the top of your application. Instead of giving you stack trace errors like undefined on line 1 of backbone.marionette.js it will output the instance and be more descriptive information like HistoryView was not found.
在您的应用程序的顶部。它不会在backbone.marionette.js 的第1 行给你像undefined 这样的堆栈跟踪错误,它会输出实例并且是更多的描述性信息,比如没有找到HistoryView。