Michael Hueter
Instructor at Rithm School and Full-Stack Software Developer
this
this
Every* function in JavaScript has a reference to its own
This is determined by the call site (roughly where and how did you invoke the function)
this.
* except arrow functions
The call site is determined by the physical location in code AND the current call stack
The default this is the global object in non-strict mode.
function defaultThis() {
return this;
}
defaultThis() === window; // true
It works with function declarations or expressions.
// define a function
var myFunction = function () {
console.log(this); // [object Window]
};
// call it
myFunction();
There are strange implications for defaulting to global.
function myFunc() {
console.log(this.myGlobal);
}
var myGlobal = 'test';
myFunc(); //'test'
When the function is defined on an object and executed with a dot invocation (e.g. obj.func()) this is the object.
// create an object
var myObject = {};
// create a method on our object
myObject.someMethod = function () {
console.log(this); // myObject
};
// call our method
myObject.someMethod();
This also works with event listeners
// let's assume .elem is <div class="elem"></div>
var element = document.querySelector('.elem');
var someMethod = function() {
console.log(this);
};
element.addEventListener('click', someMethod, false);
This context can be explicitly bound using three built-in function methods: call, apply, and bind.
function.call(thisArg, arg1, arg2, ...)
fun.bind(thisArg[, arg1[, arg2[, ...]]])
func.apply(thisArg, [argsArray])
call takes a this context as its first argument followed by any number of additional arguments to pass to the function.
function.call(thisArg, arg1, arg2, ...)
function speak (speech) {
console.log(`${this.name} says ${speech}`);
};
let dog = {
name: 'Whiskey'
};
speak.call(dog, 'bark'); // Whiskey says bark
speak.call(dog, 'woof'); // Whiskey says woof
apply works exactly the same as call but it accepts an array as a second argument, instead of a variable number of args.
func.apply(thisArg, [argsArray])
function sayThreeThings(one, two, three) {
console.log(`${this.name} says: "${one}", "${two}", "${three}"`);
};
let person = {
name: 'Elie'
};
sayThreeThings.apply(person, ['jQuery is cool', 'python is fun', 'woof']);
// Elie says: "jquery is cool", "python is fun", "woof"
bind is different! Bind does not invoke the function, it merely "sets it up" by binding a this and a variable number of arguments (like call). It returns the bound function.
fun.bind(thisArg[, arg1[, arg2[, ...]]])
function someoneDoesAddition(x, y) {
return `${this.name} adds ${x} and ${y} to get ${x + y}.`;
}
const person = {
name: 'Matt'
};
const mattDoesAddition = someoneDoesAddition.bind(person, 5, 10);
mattDoesAddition();
// "Matt adds 5 and 10 to get 15."
The new keyword is the most powerful way to set this. It will even override explicit bindings.
function Dog(name) {
this.name = name;
this.bark = function() {
console.log(`${name} barks`);
}
}
let Whiskey = new Dog('Whiskey');
Whiskey.bark(); // Whiskey barks
#1 constructor call w/ new | var Elie = new Instructor(); |
#2 Explicit Binding (C/A/B) | doStuff.call(myObj); |
#3 Implicit / Object Binding | dog.bark() |
#4 Default Binding | console.log(this); |
There are some ways where "this" behaves in seemingly unpredictable or unexpected ways.
Arrow functions do not have their own this.
Instead, this follows lexical scoping rules, so it is inherited from the parent scope.
var dog = {
name: 'Whiskey',
bark: () => { console.log(`${this.name} barks`) }
};
dog.bark();
// barks
Consider this example:
var dog = {
name: 'Whiskey',
bark: function() {
setTimeout(function() {
console.log(`${this.name} barks`);
}, 1000);
}
};
dog.bark();
// barks
By Michael Hueter
An introduction to the rules and behavior of the most confusing keyword in JavaScript.