Reputation: 519
So, this is probably answered somewhere on this site, but I can't find it, if it is.
I'm having trouble figuring out why one of my this
references inside functions seems to be resolved when I create the object, and one when I call the function that has the reference inside it. Here's some code:
function MyObj (name) {
this.locked = false;
this.name = name;
this.elem = null;
this.func1 = function () {
if (this.locked) return;
/* code that changes this.name here */
this.elem.innerHTML = this.name;
};
this.func2 = function () {
this.locked = !this.locked;
if (this.locked) this.elem.className = "locked";
else this.elem.className = "unlocked";
};
}
var myObjGlobal = new MyObj("foo");
function callFunc1 () {
myObjGlobal.func1();
}
Then I have a function that is called on document load:
function onLoad() {
var myElem = document.getElementById("myElem");
myObjGlobal.elem = myElem;
myElem.onclick = myObjGlobal.func2;
document.getElementById("myButton").onclick = callFunc1;
}
I've made sure all my html elements have the right ids. When I click myButton
, I get no errors. However, when I click myElem
, I get Uncaught TypeError: Cannot set property 'className' of undefined
.
Why is the first this
set when I call the function, and the second this
set when I create the object? (Or so it seems?)
here's a working jsfiddle showing the problem (with the given example code).
Thanks in advance!
Upvotes: 0
Views: 49
Reputation: 224952
myElem.onclick = myObjGlobal.func2;
This loses myObjGlobal
entirely; myObjGlobal.func2
is just a function, with nothing tying its this
to anything. In JavaScript, the this
of a function is determined when it’s called, not when it’s defined. This is a fantastic and useful feature of JavaScript that’s much more intuitive than, say, Python. When myElem.onclick
is called, it’ll be called with this
bound to myElem
.
Function.prototype.bind
is a utility to do what you’re doing with callFunc1
, by the way:
myElem.onclick = myObjGlobal.func2.bind(myObjGlobal);
Upvotes: 2
Reputation: 48546
myElem.onclick = myObjGlobal.func2;
This doesn't do what you think inn JavaScript. It doesn't give you func2
with the object "attached" to it in any way; it just gives you func2
. When it gets called later, it's called as a method of myElem
, so that's what this
is.
This is a gigantic and awful wart in JS. :)
You can either wrap it in another function:
myElem.onclick = function() {
myObjGlobal.func2();
};
Or use .bind
, which does effectively the same thing, and which is supported almost universally nowadays:
myElem.onclick = myObjGlobal.func2.bind(myObjGlobal);
Note also that assigning to onclick
is a little rude, since you'll clobber any existing click handler. You may want addEventListener
instead.
Upvotes: 3