调试Javascript(Backbone和Marionette)

Mat*_*tyP 14 javascript google-chrome-devtools backbone.js marionette

现在,而我使用的是Chrome浏览器开发工具,调试骨干或提线木偶,我最终设置断点和诸如此类的东西,但一旦代码暂停,其很难说哪种类型的我和由于Chrome标签一切工作的对象"儿童".
(我想因为那是构造函数)

是否有任何简单的方法来更改此声明或确定我正在使用的模型/集合类型.

这导致我的疯狂欲望开始做这样的事情:

MyModel = Backbone.Model.Extend({
    // the $$$ puts it at the top of the inspector, the NAME is just for other devs
    $$$NAME = "MyModel",  
    ...
});
Run Code Online (Sandbox Code Playgroud)

我真的不喜欢它,因为它......丑陋,它是一个变量......它只有在我检查和扩展变量时才有用......更改名称chrome用来显示它会很棒.

无论如何,有谁知道如何更改名称?或者你使用其他一些清洁惯例?

谢谢!

马特

Dan*_*olm 33

背景

有趣的是,为什么浏览器使用"child"来显示控制台/调试器中的Backbone对象的类型.

所有JavaScript对象都有一个构造函数属性,即对用于创建对象的函数的引用.浏览器使用构造函数在控制台/调试器中显示对象的"类型".如果构造函数的name属性不为空,则将使用它的值.但是,只有使用命名函数表达式定义的函数才能获得有用的name属性:

function A() {  }
console.log(A.name); // 'A' 
Run Code Online (Sandbox Code Playgroud)

匿名函数具有空名称属性:

var B = function() {  };
console.log(B.name); // ''
Run Code Online (Sandbox Code Playgroud)

那么,匿名函数会发生什么?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() { … }
};
Run Code Online (Sandbox Code Playgroud)

这里有一个更详细的脚本:http://jsfiddle.net/danmalcolm/Xa7ma/6/

浏览器似乎从源代码中获取此名称 - 没有JavaScript功能可以在运行时告诉您功能分配给的第一个变量的名称.其他浏览器支持使用匿名构造函数定义的displayName属性的约定,但目前在Chrome中不会发生这种情况:http://code.google.com/p/chromium/issues/detail?id = 17356.

回到Backbone,假设你没有使用自定义构造函数(见下文),你的类型将最终得到一个匿名构造函数,在Backbone的模型,视图,集合和路由使用的扩展函数中创建,如下所示:

child = function(){ return parent.apply(this, arguments); };
Run Code Online (Sandbox Code Playgroud)

这就是您在控制台/调试器中看到Backbone对象旁边的"child"的原因.这是浏览器对对象构造函数的合适名称的最佳猜测.

解决方案

为了给对象提供更好的类型名称,在定义Backbone类型时,可以通过第一个"protoProps"参数提供命名构造函数.只需添加一个构造函数属性,该属性包含对"父"构造函数的调用,如下所示:

var Product = Backbone.Model.extend({
    constructor: function Product() {
        Backbone.Model.prototype.constructor.apply(this, arguments);
    }
});
Run Code Online (Sandbox Code Playgroud)

您的产品模型实例现在在调试器中看起来非常好.

对于您定义的每个视图,模型,集合和路由,执行此操作有点麻烦.您可以通过猴子补丁Backbone的扩展功能为您完成工作.

首先需要建立一个约定来定义类型的名称.这里我们使用的__name__属性如下所示:

var Product = Backbone.Model.extend({
    __name__: 'Product'
    // other props
});
Run Code Online (Sandbox Code Playgroud)

然后,您可以替换Model,View,Collection和Route使用的extend函数来读取此属性,并为您的类型添加命名构造函数.您不需要修改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;
})();
Run Code Online (Sandbox Code Playgroud)

  • 哇,这应该只是默认包含在骨干中....感谢百万丹,这太棒了. (3认同)