我最近一直在努力制作更干净的Javascript代码,并使用原型等对象。但我对某些方面感到困惑......
function TimeCard(){
this.date = new Date();
this.pay_period_begin = null;
this.pay_period_end = null;
}
这是我的timecard对象,带有一些初始值。我有一堆函数,我已经编写过,而且还有更多属于那个时间卡的函数,如果我理解正确的话,它们将是原型函数。以下是我目前的一些内容:
TimeCard.prototype = {
init : function(){
this.pay_period_begin = $("#pay_period_begin");
this.pay_period_end = $("#pay_period_end");
},
getTimeCardData : function(){
//ajax request
},
selectAll : function(){
this.getTimeCardData();
}
...
};
我的问题是,当我尝试拨打this.getTimeCardData()
时,它说我的对象没有这样的方法。我显然可以访问其他变量,因为它们是在我的构造函数中声明的,但我不明白我猜的原型范围。到目前为止,我使用tc.getTimeCardData()
而不是this.getTimeCardData()
来解决这个问题,tc
是我在外面声明的对象的实例 - var tc = new TimeCard();
。我确信这不是解决这个问题的正确方法,但究竟是什么?
答案 0 :(得分:8)
我的问题是,当我尝试拨打
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
});
}
// ...
};
如果我在this.doSomething();
对象上拨打TimeCard
,则在通话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垫片”(因此我注意到$.proxy
以上;你知道你有那个):
$('#container').on('click', '#selectAll', tc.selectAll.bind(tc));
使用闭包(不要让名字打扰你,闭包不复杂): 更多(在我的博客上):
$('#container').on('click', '#selectAll', function() {
tc.selectAll();
});
在上述所有情况中,您将失去this
引用DOM元素的好处。在这种特殊情况下,您可能并不关心,但如果您这样做,则可以从事件对象的currentTarget
属性中获取它。例如,这会调用tc.selectAll
this
引用tc
并传入将已经this
(您挂钩处理程序的DOM元素) on)作为第一个论点:
$('#container').on('click', '#selectAll', function(e) {
tc.selectAll(e.currentTarget);
});
另一种不太可能的可能性与您如何更新TimeCard.prototype
有关。你正在这样做,可以通过new TimeCard()
创建对象,然后替换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;
})();
...主要是因为它可以防止时间问题。