In the previous article, we uncovered the fundamental rules around how the value of this
is determined when inside a function. If you haven’t read it yet, head over to the first article, and pop back here when you’re done.
From this point onwards, we’re going to explore a number of JavaScript features that throw those rules out of the window, and allow the caller to choose the value of this
.
- Changing the value of
this
usingcall()
andapply()
We know if you callsomeObject.foo()
thatthis
insidefoo
will besomeObject
. What if we want it to beanotherObject
?Well, we could do this;
anotherObject.foo = someObject.foo; anotherObject.foo(); delete anotherObject.foo;
Bit of a hack, no? Enter
call()
andapply()
. All you have to do is;someObject.foo.call(anotherObject);
What if you want to pass arguments to
foo()
as well? No problem!someObject.foo.call(anotherObject, 1, 2, "abc");
apply()
works exactly the same, but the difference is how they let you pass arguments to the function.call()
expects each argument as a separate parameter, whereasapply()
expects a single array, whose elements are all the parameters. The equivalentapply()
call for the above would be;someObject.foo.apply(anotherObject, [1, 2, "abc"]);
- Forcing the value of
this
usingbind()
bind()
is a tricky addition to the JavaScript language (introduced in ES5). If you callsomeObject.foo.bind(anotherObject)
,bind()
will return a new function; and no matter how you call the returned function (even usingcall()
andapply()
), the value ofthis
will always beanotherObject
.var obj = { val: 4 }; function foo() { alert(this.val); } var bar = foo.bind(obj); foo(); // behaves as expected; alerts `undefined` as `foo` is not attached to an object bar(); // breaks the rules! alerts `4` because `bind()` sets `this` to `obj`. bar.call(window); // this has no effect; still alerts `4`.
You might wonder how
bind()
works; but even if ES5 hadn’t includedbind()
; well, we could roll out our own really easily;Function.prototype.ourBind = function(thisArg) { var that = this; return function() { return that.apply(thisArg, arguments); }; };
We could then use
ourBind()
exactly how we’d usebind()
; see it in action on jsFiddle! - The
new
keyword has the last say…One last feature in JavaScript that I’d like to mention before finishing this article is thenew
keyword.If you’re not quite clued up on the behaviour of
new
you can read more about it here.Using
new
when calling a function is the final way to change the value ofthis
when calling a function. When you usenew
,this
points to a new object, whose “prototype” is set to the prototype of the function you callednew
on. Yep; that might take a few reads to sink in.The only use case for this is when creating instances of a object; but I just wanted to complete the list of “ways-this-can-be-changed”.
That concludes the articles on this
; I hope you now have a much better understanding about how it works! If you want to read a few more articles to help it sink in, I’d recommend this quirksmode article and this Stack Overflow question