我最近在我的代码中遇到了一个有趣的错误,虽然我找到了一个修复程序但我想知道是否有人可以解释为什么解决方案有效。这是一些代码
var Project = Backbone.Model.extend({
initialize: function() {
// Uncomment this line and you will no longer get the alert
//_.bindAll(this);
},
}, {
parse: function() {
alert('Parsing data');
}
});
var project = new Project({});
project.constructor.parse();
我理解bindAll,当像这样使用时,会将所有函数绑定到当前作用域但我不确定它为什么会影响parse
类属性函数。我希望它只影响实例属性。
答案 0 :(得分:1)
我们将看1.4.4,因为这是Underscore的最后一个版本,_.bindAll
可以(成功)调用而不指定方法名称。
_.bindAll
implementation很简单,审核它应该清楚:
_.bindAll = function(obj) {
var funcs = slice.call(arguments, 1);
if (funcs.length === 0) funcs = _.functions(obj);
each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
return obj;
};
第三行是关键:
funcs = _.functions(obj);
因此,如果您没有指定要绑定的函数,Underscore将获取作为函数的所有对象属性并绑定所有这些属性,请查看_.functions
implementation和documentation以获取详细信息。
但是constructor
属性是什么?好吧,it is:
...对创建实例原型
的Object函数的引用
这将通过_.isFunction
测试,因此constructor
将位于我们上面的funcs
数组中。这意味着constructor
将替换为_.bindAll
第4行中的包装函数:
obj[f] = _.bind(obj[f], obj);
但是包装函数不会包含原始parse
所具有的任何属性(例如project.constructor
),并且所有属性都会在一堆混乱和无意义中崩溃。
这种混淆可能是为什么1.5 + _.bindAll
说:
bindAll
_.bindAll(object, *methodNames)
[...] methodNames 是必需的。
如果尝试通过对象的属性进行迭代,并尝试找出哪些是函数而哪些函数不是函数,那么也可能遇到其他奇怪的问题。
我鼓励你在发生意外情况时查看Underscore和Backbone来源,它们都非常容易阅读和理解。