admin管理员组文章数量:1302277
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 e 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?
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 e 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?
-
2
can you show us the function where you call
this.getTimeCardData()
please ? – axelduch Commented Mar 3, 2014 at 10:19 -
Yeah, it's already in the code shown under the
selectAll
function. – tannerwj Commented Mar 3, 2014 at 16:51
1 Answer
Reset to default 8My 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 ment, 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 plicated): 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);
});
- Mythical methods
- You must remember
this
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 remend 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 remend 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.
本文标签: oopJavascript multiple prototype functionshow to call one from anotherStack Overflow
版权声明:本文标题:oop - Javascript multiple prototype functions - how to call one from another - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741711267a2393857.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论