Javascript多个原型函数 - 如何从另一个调用 [英] Javascript multiple prototype functions - how to call one from another
问题描述
我最近一直在努力制作更干净的Javascript代码,并使用原型等对象。但我对某些方面感到困惑......
function TimeCard(){
this.date = new Date();
this.pay_period_begin = null;
this.pay_period_end = null;
}
这是我的时间卡对象,带有一些初始值。我有一堆函数,我已经编写过,而且还有更多属于那个时间卡的函数,如果我理解正确的话,它们将是原型函数。以下是我到目前为止的一些内容:
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()时/ code>它说我的对象没有这样的方法。我显然可以访问其他变量,因为它们是在我的构造函数中声明的,但我不明白我猜的原型范围。到目前为止,我通过使用
是我在外面声明的对象的实例 - tc.getTimeCardData()
而不是 this.getTimeCardData()
来解决这个问题。 code> tc var tc = new TimeCard();
。我确定这不是正确的方法,但这是什么?
我的问题是,当我尝试调用
this.getTimeCardData()
时,它说我的对象没有这样的方法。
听起来像这个
不再是指您的实例了。您必须向我们展示我们确实要求的实际调用,但在JavaScript中,此
主要由函数的设置方式设置,而不是它定义的地方,所以这个
很容易就会变得不同了。
这是一个假设的例子:
TimeCard.prototype = {
// ...
doSomething:function() {
//这里,`this`可能是指时间卡
someArray.forEach(function(){
this.getTimeCardData(); //< ===问题,`这个`已改变
});
}
// ... ...
};
如果我打电话给 this.doSomething();
在 TimeCard
对象上,在通话中,此
将引用时间卡。但是在 forEach
回调中,此
将不再引用时间卡。所有类型的回调都会发生同样的变化; ajax等。
要解决它,你可以记住这个
变量:
TimeCard.prototype = {
// ...
doSomething:function(){
var thisCard =这个;
someArray.forEach(function(){
thisCard.getTimeCardData(); //< === Problem
});
}
// ... ...
};
根据您的具体情况,还有其他各种方法可以解决这个问题。例如,您有 selectAll
调用 getTimeCardData
。但是假设使用错误的此
值调用 selectAll
?在你的评论中,你说你这样做:
$('#container')。on('click' ,'#selectAll',tc.selectAll);
这意味着当调用 selectAll
时, 此
将引用DOM元素,而不是您的对象。
在这种特定情况下,您有三个选项:
-
由于你使用的是jQuery,你可以使用
$。proxy
,它接受一个函数和一个值用作this
,并返回一个新函数,当调用它时,将使用调用原始函数
设置为所需的值:$('#container')。on('click', '#selectAll',$ .proxy(tc.selectAll,tc));
-
使用ES5的
功能#bind
,它做同样的事情。请注意IE8及更早版本没有它,除非你包含一个ES5垫片(因此我注意$。proxy
以上;你知道你()<($') .bind(TC));
-
使用闭包(不要让名字打扰你,闭包是并不复杂):
更多(在我的博客上):$('#container')。on('click','#selectAll',function(){
tc.selectAll();
});
在上述所有情况中,你将会失去了这个
引用DOM元素的好处。在这种特殊情况下,您可能不在乎,但如果您这样做,您可以从事件对象的 currentTarget
属性中获取它。例如,这会调用 tc.selectAll
,其中此
指的是 tc
并传入将 c>这个(你将处理程序挂钩的DOM元素)作为第一个参数:
$('#container')。on('click','#selectAll',function(e){
tc.selectAll (e.currentTarget);
});
另一种不太可能的可能性与你的方式有关更新 TimeCard.prototype
。您正在这样做的方式,可以通过新的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()$ c $创建的任何对象c> 之前你做替换将有旧原型,而不是新原型。
我还建议总是在范围函数中创建这些原型。所以你知道声明和原型添加同时发生:
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
};
// ...
返回TimeCard;
})( );
...主要是因为它可以防止时间问题。
I've been working a lot lately on making cleaner Javascript code, and using objects with prototypes etc. But I'm confused on some points...
function TimeCard(){
this.date = new Date();
this.pay_period_begin = null;
this.pay_period_end = null;
}
Here is my timecard object with some initial values. I have a bunch of functions that I've written and more to come that are part of that timecard and, if I understand correctly, they will be prototype functions. Here is some of what I have so far:
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();
}
...
};
My problem is that when I try to call this.getTimeCardData()
it says that my object has no such method. I can obviously access the other variables because they are declared in my constructor, but I don't understand how prototype scopes I guess. So far I have gotten around this by using tc.getTimeCardData()
instead of this.getTimeCardData()
, with tc
being the instance of my object declared outside - var tc = new TimeCard();
. I'm sure that that's not the correct way to go about this, but what is?
My problem is that when I try to call
this.getTimeCardData()
it says that my object has no such method.
It sounds like this
is no longer referring to your instance. You'll have to show us the actual call for us to be sure, but in JavaScript, this
is set primarily by how a function is called, not where it's defined, and so it's fairly easy for this
to end up being something different.
Here's a hypothetical example:
TimeCard.prototype = {
// ...
doSomething: function() {
// here, `this` probably refers to the timecard
someArray.forEach(function() {
this.getTimeCardData(); // <=== Problem, `this` has changed
});
}
// ...
};
If I call this.doSomething();
on a TimeCard
object, within the call this
will refer to the timecard. But within the forEach
callback, this
will no longer refer to the timecard. The same sort of thign happens with all kinds of callbacks; ajax, etc.
To work around it, you can remember this
to a variable:
TimeCard.prototype = {
// ...
doSomething: function() {
var thisCard = this;
someArray.forEach(function() {
thisCard.getTimeCardData(); // <=== Problem
});
}
// ...
};
There are also various other ways to work around it, depending on your specific situation. For instance, you have selectAll
calling getTimeCardData
. But suppose selectAll
is called with the wrong this
value? In your comment, you said you were doing it like this:
$('#container').on('click', '#selectAll', tc.selectAll);
That means that when selectAll
is called, this
will refer to the DOM element, not to your object.
You have three options in that specific situation:
Since you're using jQuery, you can use
$.proxy
, which accepts a function and a value to use asthis
, and returns a new function that, when called, will call the original withthis
set to the desired value:$('#container').on('click', '#selectAll', $.proxy(tc.selectAll, tc));
Use ES5's
Function#bind
, which does the same thing. Note that IE8 and earlier don't have it unless you include an "ES5 shim" (hence my noting$.proxy
above; you know you have that):$('#container').on('click', '#selectAll', tc.selectAll.bind(tc));
Use a closure (don't let the name bother you, closures are not complicated): More (on my blog):
$('#container').on('click', '#selectAll', function() { tc.selectAll(); });
In all of the above, you'll lose the benefit of this
referring to the DOM element. In that particular case, you probably don't care, but if you did, you can get it from the event object's currentTarget
property. For instance, this calls tc.selectAll
with this
referring to tc
and passing in what would have been this
(the DOM element you hooked the handler on) as the first argument:
$('#container').on('click', '#selectAll', function(e) {
tc.selectAll(e.currentTarget);
});
Another, less likely, possibility relates to how you're updating TimeCard.prototype
. The way you're doing it, it's possible to create objects via new TimeCard()
before your code that replaces the TimeCard.prototype
object runs, which means they'll have the old prototype.
In general, I strongly recommend not replacing the object automatically created for the prototype
property of the constructor function. Instead, just add to the object already there, like this:
function TimeCard(){
this.date = new Date();
this.pay_period_begin = null;
this.pay_period_end = null;
}
TimeCard.prototype.getTimeCardData = function(){
//ajax request
};
// ...
Here's why: Timing. If you replace the object on the prototype
property, any objects you create via new TimeCard()
before you do that replacement will have the old prototype, not the new one.
I also recommend always creating these within a scoping function so you know that the declaration and the prototype additions happen at the same time:
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;
})();
...primarily because it prevents the timing issue.
这篇关于Javascript多个原型函数 - 如何从另一个调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!