我正在使用关于页脚的自定义选项扩展Backbone View,我在另一个类中评估。
看起来像:
var EditUserView = Backbone.View.extend({
footer: {
name: "Hello",
label: function() {
//Return "Create" if it's a new model without id, or else "Save"
return this.model.id ? "Save" : "Create";
}
}
});
如您所见,属性应该能够定义为返回字符串或普通字符串值的函数。 我使用_.result:
在FooterView中评估这些选项initialize: function(options) {
//"options" is the footer-object from the view.
this.data = {
name: _.result(options, "name"),
label: _.result(options, "label")
};
}
但问题是我无法访问上面定义的标签函数中的EditUserView。我也无法定义var that = this
因为我正在扩展对象而没有局部变量的位置。
如何使我在footer-object中定义的函数具有UserEditView的这个范围?
我也可以:
footer: {
name: "Hello",
label: this.getName
},
getName: function() {
return this.model.id? "Save":"Create";
}
如果不可能采用其他方式,或者这种方式更容易。
答案 0 :(得分:0)
通常,函数内的this
仅取决于函数的调用方式(当然,除非你有一个绑定函数)。鉴于此:
var V = Backbone.View.extend({
m: function() { console.log(this) }
});
var v = new V;
然后这些做了不同的事情:
var f = v.m; f();
v.m();
他们正在调用相同的函数,但在第一种情况下this
将是全局对象,在第二种情况下它将是v
;差异不在于函数本身,区别在于它的调用方式。
如果我们查看_.result
,我们可以看到它如何调用该函数:
_.result = function(object, property) {
if (object == null) return void 0;
var value = object[property];
return _.isFunction(value) ? value.call(object) : value;
};
请注意其中的call
,这意味着,如果_.result(obj, 'm')
是m
的函数属性,则说obj
,就像说:
obj.m()
将其应用于:
_.result(options, "label")
我们看到你有效地说:
options.label()
和this
函数中的label
将为options
。
我在上面提到了绑定函数。创建绑定函数的官方方法是使用Function.prototype.bind
:
bind()方法创建一个新函数,在调用时,将其
this
关键字设置为提供的值,并在新的函数前面提供任何给定的参数序列函数被调用。
这意味着您可以使用bind
指定函数内部this
,无论函数如何调用。您还可以使用_.bind
,_.bindAll
,$.proxy
以及其他各种方法来模拟函数上的原生bind
方法。
在您的视图initialize
中,您可以将footer
中的函数绑定到相应的this
。但要注意,你必须克隆整个footer
以避免通过原型意外分享内容:
initialize: function() {
var footer = {
name: this.footer.name,
label: this.footer.label.bind(this)
};
this.footer = footer;
}
使用_.clone
,_.isFunction
的任意组合以明显的方式概括,并且迭代器会让你开心。
缺点是视图的每个实例都有自己独特的footer
副本,如果您有大量实例或footer
很大,则可能会造成浪费。如果这是一个问题,那么您可以编写自己的_.result
版本,类似这样(未经测试的代码):
_.mixin({
i_cant_think_of_a_good_name_for: function(object, property) {
if(object == null)
return void 0;
return _.isFunction(property) ? property.call(object) : property;
}
});
然后说:
_.i_cant_think_of_a_good_name_for(this, options.name);
_.i_cant_think_of_a_good_name_for(this, options.label);
在你看来。请注意,这里的第一个参数是您希望用于函数的this
,第二个参数是整个属性而不仅仅是它的名称。