This post serves as a quick refresher on how the this
-keyword works in different contexts in the JavaScript language. It might help someone to not fall for one of the many traps I already fell for.
Note that I will only talk about strict mode here. Sloppy mode has way too many gotchas on its own and is generally discouraged. Going forward, ES6 modules will always be in strict mode, anyway.
this in the global context
Calling this
in the global execution context (outside of any function) refers to the global object. In the browser the global object is called window
, in Node.js it’s called global
. But beware: in node modules the code is wrapped in a wrapper function, so this now points to module.exports
.
this in function calls
The this value in a regular function call is undefined (in sloppy mode it referred to the global object):
1"use strict";2function Foo() {3 console.log(this);4}5Foo(); // undefined
this in constructor calls
Calling a function with new
is called a constructor call. A new object will be created and this
set as a reference to this instance. This works as expected and is pretty straight-forward:
1function Something(first, second) {2 console.log(this);3 this.firstName = first;4 this.secondName = second;5}6const foo = new Something("John", "Doe"); // Something {}7console.log(foo.firstName); // 'John'
this in method calls
In method calls this
refers to its receiver, the object on which the method was invoked on:
1const o = {2 f: function() {3 console.log(this);4 },5};6o.f(); // { f: [Function: f] }
Another object could call o.f()
and this
would still refer to the original o
object.
this in call() or apply()
With call
and apply
you can set the this
value for this one time explicitly. They differ only in the way you are able to additionally set arguments: either comma-separated with call
or in an array with apply
.
1function f(a, b) {2 console.log(this); // 'new this value'3 console.log(a); // 'firstArg'4 console.log(b); // 'secondArg'5}6f.call("new this value", "firstArg", "secondArg");7f.apply("new this value", ["firstArg", "secondArg"]);
If you keep forgetting which one takes an array and which one doesn’t: apply and array both start with a and each has five letters.
this in bind()
ES5 introduced function.prototype.bind(thisArg [, args])
. This creates a new function with this
permanently bound to the used thisArg (as well as optional, comma-separated, arguments).
1function foo() {2 console.log(this);3}4foo(); // undefined5const bar = foo.bind("newThis");6bar(); // 'newThis'
this in arrow functions
Arrow functions don’t bind this
(neither arguments
, super
and new.target
):
1function f(a) {2 const anon = c => {3 return console.log(arguments);4 };5 anon("new arg");6}7f("old arg"); // { '0': 'old arg' }
No need for the const self = this
hack if used properly.
this in ES6 classes
While I’m not a fan of them, ES6 introduced classes anyway. Under the hood they still work with the JavaScript prototype system and are basically syntactic sugar over it.
this
inside a normal class method refers to the instance, in static methods to the class itself.
1class Foo {2 constructor() {3 console.log(this);4 }5 static bar() {6 console.log(this);7 }8}9const foo = new Foo(); // instance of Foo10Foo.bar(); // class Foo
Conclusion
There are lots and lots of edge cases for this
that I haven’t talked about here which could fill books. I try to code without this
as much as possible and it works out fine (usually).