我的问题是,当我尝试调用 this.getTimeCardData() 时,它说我的对象没有这样的方法。
听起来this 不再指代您的实例。您必须向我们展示实际调用才能确定,但在 JavaScript 中,this 主要由函数的调用方式设置,而不是在哪里定义,因此相当容易this 最终会变得与众不同。
这是一个假设的例子:
TimeCard.prototype = {
// ...
doSomething: function() {
// here, `this` probably refers to the timecard
someArray.forEach(function() {
this.getTimeCardData(); // <=== Problem, `this` has changed
});
}
// ...
};
如果我在TimeCard 对象上调用this.doSomething();,则在调用this 中将引用时间卡。但在forEach 回调中,this 将不再引用时间卡。各种回调都会发生同样的事情。 ajax等
要解决这个问题,您可以将this 记住为一个变量:
TimeCard.prototype = {
// ...
doSomething: function() {
var thisCard = this;
someArray.forEach(function() {
thisCard.getTimeCardData(); // <=== Problem
});
}
// ...
};
根据您的具体情况,还有多种其他方法可以解决此问题。例如,您有selectAll 调用getTimeCardData。但是假设selectAll 被错误的this 值调用?在您的评论中,您说您是这样做的:
$('#container').on('click', '#selectAll', tc.selectAll);
这意味着当selectAll 被调用时,this 将引用 DOM 元素,而不是您的对象。
在这种特定情况下,您有三个选择:
-
由于您使用的是 jQuery,您可以使用 $.proxy,它接受一个函数和一个值用作 this,并返回一个新函数,该函数在调用时将调用带有 this 集合的原始函数到所需的值:
$('#container').on('click', '#selectAll', $.proxy(tc.selectAll, tc));
-
使用 ES5 的Function#bind,它做同样的事情。请注意,IE8 和更早版本没有它,除非您包含“ES5 shim”(因此我在上面提到了$.proxy;您知道您有):
$('#container').on('click', '#selectAll', tc.selectAll.bind(tc));
-
使用闭包(别让名字困扰你,闭包并不复杂):
更多(在我的博客上):
$('#container').on('click', '#selectAll', function() {
tc.selectAll();
});
在上述所有情况下,您将失去 this 引用 DOM 元素的好处。在这种特殊情况下,您可能并不关心,但如果您这样做了,您可以从事件对象的 currentTarget 属性中获取它。例如,这会调用 tc.selectAll 和 this 引用 tc 并传入 would 已经是 this(您挂钩处理程序的 DOM 元素)作为第一个参数:
$('#container').on('click', '#selectAll', function(e) {
tc.selectAll(e.currentTarget);
});
另一个不太可能的可能性与您更新TimeCard.prototype 的方式有关。按照您的操作方式,可以通过 new TimeCard() 创建对象 before 替换 TimeCard.prototype 对象的代码运行,这意味着它们将拥有旧原型。
一般来说,我强烈建议不要替换为构造函数的prototype 属性自动创建的对象。相反,只需添加到已经存在的对象,如下所示:
function TimeCard(){
this.date = new Date();
this.pay_period_begin = null;
this.pay_period_end = null;
}
TimeCard.prototype.getTimeCardData = function(){
//ajax request
};
// ...
原因如下:时机。如果您替换 prototype 属性上的对象,那么您通过new TimeCard() 创建的任何对象在进行替换之前都将具有旧原型,而不是新原型。
我还建议始终在作用域函数中创建这些,以便您知道声明和原型添加是同时发生的:
var TimeCard = (function() {
function TimeCard(){
this.date = new Date();
this.pay_period_begin = null;
this.pay_period_end = null;
}
TimeCard.prototype.getTimeCardData = function(){
//ajax request
};
// ...
return TimeCard;
})();
...主要是因为它可以防止时间问题。