对于一个继承的已有7年历史的Backbone站点,我有一个视图“PaymentInfoForm”,需要在其中实现一个新的小部件来处理在线支付。(让我们称之为inceptionLib)基本上是第三方API第三方UI和验证 Package 器。inceptionLib是全新的、专有的,而且没有很好的文档记录,因此它是一个相当不透明的黑盒子,但是我可以让它在独立的演示JavaScript中工作得很好。但是,试图与Backbone集成给我带来了麻烦。
inceptionLib要求我创建一个新的函数inceptionLibFieldListener,作为PaymentInfoForm视图的一部分,以处理用户与小部件交互时的状态变化。在该函数中,我需要做的是能够设置视图的几个属性。我在使用“this”关键字时遇到了问题。我知道,当在内部函数中使用“this”时,它会失去视图的作用域。但我不知道为什么会这样如果我试图将函数 Package 在_.bind中作为这类问题的通用解决方案,'this'只是成为对窗口对象的引用-就像它在我的对象模型中向上“跳过一级”一样。我不知道如何强制'this'成为我的视图-这样我就可以在这里修改视图属性。
感觉就像inceptionLib正在劫持“这个”,好吧,我真的需要它回来!任何帮助都表示感谢。
App.PaymentInfoForm = Backbone.View.extend({ // existing view
oldProperty1: null, // existing property
myNewProperty2: null, // new property that I need to modify from inceptionLibFieldListener()
initialize: function (){...}, // create objects & stuff, doesn't matter
render: function(){ // render, including putting the inceptionLib widget on the page
{...}
var inceptionLibForm = inceptionLib.createForm();
var that = this;
vgsForm.initInceptionLib().then(function(){
inceptionLibForm.renderCreditCard('#cc-container', that.inceptionLibFieldListener);
inceptionLibForm.renderExpirationDate('#exp-container', that.inceptionLibFieldListener);
})
return this;
},
inceptionLibFieldListener: function(newState, prevState, flags) { // inceptionLib listener function
console.log(this); // result is output for the inceptionLib object
},
// if I change the inceptionLibFieldListener to this:
inceptionLibFieldListener: _.bind(function(newState, prevState, flags) { // _.bind should fix it
console.log(this); // but result is Window object
// }, this),
somethingElse: function(){ // unrelated function just to test the difference in 'this'
console.log(this); // result is console output for the view, as expected
},
...
1条答案
按热度按时间jtoj6r0c1#
您的问题是由于对
this
工作原理的误解。我不会详细解释this
,因为MDN有一个关于这个主题的good, comprehensive article。但是,我可以简短地解释为什么您的代码不工作以及如何修复它。当你这样做
that
确保inceptionLibFieldListener
是从PaymentInfoForm
示例中获得的,这是您尝试实现的一半。但是,执行x.aMethod
并没有将aMethod
* 绑定 * 到x
。换句话说,当aMethod
运行时,this
仍然可以是任何值。下面的代码演示了这一点:你可能会想,在上一个例子中,
aMethod
* 为什么看起来 * 绑定到x
?为什么x.aMethod()
可以工作,而aMethod = x.aMethod; aMethod()
不行?为什么不总是需要调用aMethod.call(x)
?这是因为JavaScript引擎将x.aMethod(a, b, c)
识别为特殊情况,并自动将其转换为x.aMethod.call(x, a, b, c)
。你可能会觉得这是违反直觉的,你会有一个点,但这只是JS的工作方式。当你这样做
问题是
this
是在任何函数上下文之外求值的。全局作用域中的this
总是window
对象,或者ES6模块作用域中的undefined
。因此,_.bind
正在做它应该做的事情,但是你传递给它的是错误的this
。有两种方法可以解决这个问题。第一种方法是在更合适的时候使用
_.bind
,当this
确实有你需要的值时,例如在你的render
方法中:另一个选择是使用
_.bindAll
,它永久地将方法更改为始终绑定到PaymentInfoForm
示例。这是您可以在contructor
或initialize
方法中执行的操作,尽管如果您还想以未绑定的形式使用该方法,我不推荐这样做:使用后一种方法,现有的
render
代码应该可以按原样工作。