It's all about context. This is true in general, but even moreso for JavaScript.
Unlike other languages, the value of the this
keyword in JavaScript depends on a number of factors. It's value will change depending on the context it is used in, but also the mode in which the code is executing, and within the function context, the way in which the function is called as well as the type of function used.
To make things a little more interesting, you can even set the value when calling a function!
Global Context
When referenced in the global context (e.g. in window
or worker
contexts), this
is always a reference to the global object itself.
console.log(this); // logs the 'window' object
Function Context
Here's where things get a little messy…
Direct Execution
When functions are executed normally, in non-strict (or 'sloppy') mode, this
will be the global object.
function whatTheHeckIsThis() {
return this;
}
whatTheHeckIsThis(); // returns the 'window' object
However in strict mode, functions called directly like this will have this
set to undefined
. This is because we haven't explicity set the value of this
when we called the function, nor is the function being called as a method of any object.
function strictWhatTheHeckIsThis() {
'use strict';
return this;
}
strictWhatTheHeckIsThis(); // returns undefined
As an Object Method
But, in any mode, and wherever it may be defined, if an object is executed as a method of some instance/object, this
is bound to the instance/object for which the function is a method.
function whatTheHeckIsThis() {
return this;
}
var widget = {
foo: whatTheHeckIsThis
}
widget.foo(); // returns 'widget'
As an Event Handler
Similarly, when a function is used as an event handler for a DOM node, then this
is bound to that DOM node.
function whatTheHeckIsThis() {
return this;
}
var el = document.getElementById('foo');
el.addEventListener(
'click',
whatTheHeckIsThis // the DOM node i.e. 'el'
);
Setting A Custom this
You can call functions and explicitly bind this
to a value of your choice… well, sort of…
Using call
& apply
Functions don't always have to be executed directly, with call
& apply
, you can execute a function while specifying a value to use for this
.
They both do the same thing, and the first argument for both is the value to use for this
. The difference is that call
accepts a list of comma seperated values as additional arguments, while apply
accepts a single array of values as an aditional argument. We'll just look at call
as an example.
function whatTheHeckIsThis() {
return this;
}
var that = {
foo: 'bar'
};
whatTheHeckIsThis.call(that); // returns 'that'
But if only it were that simple!
In sloppy-mode, this
must always be an object
, so if you supply null
or undefined
, the global object is used, but if you provide a primitive value, then JavaScript will instantiate a new instance using that primitive's Object constructor.
function whatTheHeckIsThis() {
return this;
}
whatTheHeckIsThis.call(null); // the 'window' object
whatTheHeckIsThis.call(123); // a 'Number' instance
whatTheHeckIsThis.call('abc'); // a 'String' instance
whatTheHeckIsThis.call(false); // a 'Boolean' instance
But in strict mode, you can provide any value whatsoever, and that exact value is what will be used!
function strictWhatTheHeckIsThis() {
'use strict';
return this;
}
strictWhatTheHeckIsThis.call(null); // null
strictWhatTheHeckIsThis.call(123); // 123
strictWhatTheHeckIsThis.call('abc'); // 'abc'
strictWhatTheHeckIsThis.call(false); // false
Using bind
This method returns a copy of a function, with it's this
value bound to the supplied argument. Whatever way you call it, it will always use the supplied value for it's this
value.
function whatTheHeckIsThis() {
return this;
}
var myThis = { a: 123 };
var boundThis = whatTheHeckIsThis.bind(myThis)
boundThis(); // returns 'myThis'
boundThis.call(123); // returns 'myThis'
boundThis.apply('abc'); // returns 'myThis'
Arrow Functions
ES6 introduced 'arrow functions', which provide anonymous function with terser syntax & the option for implicit returns - but that's not all they do.
An arrow function has a specific feature; they do not set or change the value of this
. In an arrow function, this
is determined by it's enclosing lexical scope.
// So in global contexts...
console.log(this); // the 'window'
var whatTheHeckIsThis = () => this;
whatTheHeckIsThis(); // the 'window'
// While in function contexts...
function whatTheHeckIsThis() {
'use strict';
function standardFunctionThis() {
return this;
};
var arrowFunctionThis = () => this;
console.log(
standardFunctionThis(),
arrowFunctionThis()
);
}
whatTheHeckIsThis(); // logs 'undefined, undefined'
var myThis = { a: 123 };
whatTheHeckIsThis.call(myThis); // logs 'undefined, myThis'
That's a quick overview of this
. Hopefully it's made things a little clearer if you were struggling with it.
this
is a very important keyword for JavaScript, and despite it's confusing implementation, and what seems to be an ever-changing value, it allows you to write better, more contextually catered, as well as reusable code - so be sure to make use of it!