Keeping your head square about JavaScript’s this
variable can be a little challenging. A wonderfully concise summary on the issue is found in chuckj’s answer to a StackOverflow question (modified here to account for differences between ECMAScript 5’s strict and non-strict modes):
this
can be thought of as an additional parameter to the function that is bound at the call site. If the function is not called as a method then the global object (non-strict mode) orundefined
(strict mode) is passed asthis
.”
Let’s see what this means (pun intended?) for various scenarios.
Disclaimer
Here I’m only concerned with functions and methods that use conventional function definition syntax. Things behave a little differently when using ES6’s arrow functions.
While I use function expressions throughout, the results are unchanged if you use function declarations. The results shown are also unchanged if you use ES6’s let
instead of var
to define variables.
Unattached functions
With unattached functions running in non-strict mode, this
will be the global object, which in the browser is the window
.
var foo = function() { console.log(this); // this is the window }; foo();
In strict mode, this
will be undefined
.
'use strict'; var foo = function() { console.log(this); // this is undefined }; foo();
Nested functions
The same rule applies to nested functions: this
will be global object (window
in browsers) in non-strict or undefined
in strict mode:
var foo = function() { var bar = function() { console.log(this); // window (or undefined in strict mode) }; bar(); console.log(this); // window (or undefined in strict mode) }; foo();
Closures
Again, the same rule: this
will be the global object (window
) or undefined
depending on strict-mode.
var foo = function() { var bar = function() { console.log(this); // window (or undefined in strict mode) }; return bar; }; var cl = foo(); cl();
Methods
With methods, this
will be bound to the object, independent of strict mode.
var ob1 = { who: 'an object', foo: function() { console.log(this); // this is ob1 } } ob1.bar = function() { console.log(this); // this is ob1 }; ob1.foo(); ob1.bar();
Methods with nested functions
A bit of a surprise here perhaps. Functions nested in methods are attached to the global object (window
) or undefined
. The way to think about this is, “Nested functions are not methods.”
var ob1 = { who: 'an object', foo: function() { var bar = function() { console.log(this); // this is the window (or undefined in strict mode) }; bar(); console.log(this); // this is ob1 } } ob1.foo();
Methods with closures
If you’re adventurous enough to use a method with a closure, “Nested functions are not methods,” again applies.
var ob1 = { who: 'an object', foo: function() { var bar = function() { console.log(this); // this is the window (or undefined in strict mode) }; return bar; } } var cl = ob1.foo(); console.log(cl());
Overriding the context
You can override the default context with the apply
and call
methods.
var ctx = { who: 'ctx' }; var foo = function() { console.log(this); // in both calls, this is the ctx object }; foo.apply(ctx); foo.call(ctx);
Summing up
Given what we’ve learned, we can distill things down into a very concise this
mantra:
“Functions use the global object or
undefined
, methods use the object.”
This mantra applies to functions defined using classic function definition syntax. When using ES6’s arrow functions, things will change.
Copyright © 2018 Mithat Konar. All rights reserved.
One thought on “JavaScript and ‘this’”