“this” in JavaScript

Ben Aston
4 min readFeb 12, 2015

--

Being a strange chimera of functional and object-oriented language features, JavaScript has a uniquely flexible approach to the this keyword.

Frequently (but slightly erroneously) called the context, occasionally but more accurately the receiver. this is the global object when used in the global context. Used inside a function, this is defined by the way the function is invoked.

The Global Context Itself

OK, this one is fairly self-explanatory:

this; // window (in a browser) / global in Node.js/io.js

“Bare” Invocation

Invoking a function without a receiver, results in the function receiver being bound to the global context.

function foo() { console.log(this); }foo(); // window (in a browser) / global in Node.js/io.js

However; ECMAScript 5 introduced strict mode that changed this behavior so that this would become undefined in this context, thereby avoiding subtle bugs resulting in changes to the global object.

'use strict';function foo() { console.log(this); }foo(); // undefined (in a browser) / undefined in Node.js/io.js

Note that simply running the above in the console will not run it in strict mode because the browser places code before the top of your script. And ‘use strict’ only works if it is at the top of your script (or function). Instead, wrapping this code in a function expression will give the expected outcome in the browser console:

(function() {
'use strict';
function foo() { console.log(this); } foo(); // undefined (in a browser) / undefined in Node.js/io.js
}());

What do you think will be printed by the following when run in a browser?

function bar() { console.log(this); }(function() {
‘use strict’;
function foo() {
console.log(this);
bar();
}
foo(); // What is printed to the console?
}());

The answer is:

undefined
Window

This is because the extent of effect of the use strict directive depends on where functions are defined. bar is defined outside of the function with the use strict statement, thus it runs in sloppy-mode. This example serves to demonstrate that the receiver of a function defaults to the global object in sloppy-mode code, whenever a receiver is not specified by the programmer, no matter how deep the nesting of function calls.

Invocation from Certain Built-In Functions

Some built-in functions make guarantees about the receiver of functions supplied to them. For example, setTimeout is specified to run the callback supplied to it with the global object as the receiver.

(function() {
'use strict';
setTimeout(function foo() { console.log(this); }, 0); // window (in a browser) / global in Node.js/io.js
}());

Invocation as a Method

If a function is invoked as a method (i.e. as a function upon a user-defined object instance) then the reciever for that function is the object it is being invoked as a method upon:

(function() {
'use strict';
function Foo() {
this.bar = function() { console.log(this); }
}
new Foo().bar(); // Foo (in a browser) / Foo in Node.js/io.js
}());

Or:

(function() {
'use strict';
var o = { bar: function() { console.log(this); } } o.bar(); // Object (in a browser) / Object in Node.js/io.js
}());

Some people say that the receiver for a function corresponds to the object on the left-hand side of the invocation. However, this memorization technique can be misleading.

Consider the following:

(function() {
'use strict';
var o = { bar: function() { console.log(this); } } setTimeout(o.bar, 0); // window (in a browser) / global in Node.js/io.js
}());

In the above, the function bar on object o is being invoked in the context of setTimeout, for which the specification defines that the reciever will be the global object. But if you “naively” believe that the receiver is “the object on the left-hand side”, you can see that bar is supplied as the callback using the syntax o.bar.

To anyone with a good understanding of JavaScript, it is obvious that the method bar is being supplied as a function reference for later invocation inside setTimeout; but this memorization rule is for those still learning the language for which this might not be so obvious. For this reason, I recommend against using this rule.

Invocation using call, apply and bind

Since ES3, JavaScript has had the call and apply built-in functions:

(function() {
'use strict';
function Foo() {} var o = { bar: function() { console.log(this); } } o.bar.call(Foo); // Foo (in a browser) / Foo in Node.js/io.js
o.bar.apply(Foo); // Foo (in a browser) / Foo in Node.js/io.js
}());

Finally, since ES5 JavaScript has enabled the binding of the receiver, meaning it will remain unchanged from there-on:

(function() {
'use strict';
function Foo() {} var o = { bar: function() { console.log(this); } } setTimeout(o.bar.bind(new Foo()), 0); // Foo (in a browser) / Foo in Node.js/io.js
}());

Summary

At first sight, the this keyword seems complicated when compared with class-based languages like Java. When you realise that JavaScript supports both functional and object-oriented styles of development, you begin to understand why it works as it does.

Once you have learned the rules outlined above, you quickly begin to appreciate the ability to pass functions around for which the receiver changes depending on the context of invocation — of which you the developer have full control.

My name is Ben Aston and thank you for reading my post today. I am a JavaScript consultant, based in London, available for short-term consultancy globally. I can be contacted at ben@bj.ma.

If you would like to further develop your knowledge of JavaScript you might be interested in my hands-on training course. Full details can be found online at www.learnjavascript.london.

If you enjoyed this piece, please let me know by clicking the “recommend” button below.

You may also be interested in my post on inheritance in JavaScript.

Made in the United Kingdom

--

--