Introduction

Hi, I'm Elie!

The keyword 'this'

Objectives

  • Define what the keyword 'this' is
  • Understand the four ways to always figure out what the keyword 'this' is
  • Try as hard as possible not to use the word "this" in a sentence

So what is 'this'?

  • A reserved keyword in JavaScript
  • Usually determined by how a function is called (what we call 'execution context')
  • Can be determined using four rules (global, object/implicit, explicit, new)

1 - Global Context

console.log(this) // window

function whatIsThis(){
    return this
}

function variablesInThis(){
    // since the value of this is the window
    // all we are doing here is creating a global variable
    this.person = "Elie"
}

console.log(person) // Elie

whatIsThis() // window

When 'this' is not inside of a declared object

Strict Mode

"use strict"

console.log(this) // window

function whatIsThis(){
    return this
}

function variablesInThis(){
    // since we are in strict mode this is undefined
    // so what happens if we add a property on undefined?
    // let's see what happens when we call the function...
    this.person = "Elie"
}

variablesInThis() // TypeError, can't set person on undefined! 

whatIsThis() // undefined

When we enable strict mode and we are not inside a declared object

2 - Implicit/Object

// strict mode does NOT make a difference here

var person = {
    firstName: "Elie",
    sayHi: function(){
        return "Hi " + this.firstName
    },
    determineContext: function(){
        return this === person
    }
}

When the keyword 'this' IS inside of a declared object

person.sayHi() // "Hi Elie"
person.determineContext() // true

Nested Objects

var person = {
    firstName: "Colt",
    sayHi: function(){
        return "Hi " + this.firstName;
    },
    determineContext: function(){
        return this === person;
    },
    dog: {
        sayHello: function(){
            return "Hello " + this.firstName;
        },
        determineContext: function(){
            return this === person;
        }        
    }
}

What happens when we have a nested object?

person.sayHi() // "Hi Colt"
person.determineContext() // true

// but what is the value of the keyword this right now?
person.dog.sayHello() // "Hello undefined"
person.dog.determineContext() // false

3 - Explicit Binding

Choose what we want the context of 'this' to be using call, apply or bind

NAME OF METHOD PARAMETERS INVOKE IMMEDIATELY?
Call thisArg, a, b, c, d , ... Yes
Apply thisArg, [a,b,c,d, ...] Yes
Bind thisArg, a, b, c, d , ... No

Fixing Up With Call

var person = {
    firstName: "Colt",
    sayHi: function(){
        return "Hi " + this.firstName
    },
    determineContext: function(){
        return this === person
    },
    dog: {
        sayHello: function(){
            return "Hello " + this.firstName
        },
        determineContext: function(){
            return this === person
        }        
    }
}

person.sayHi() // "Hi Colt"
person.determineContext() // true

person.dog.sayHello.call(person) // "Hello Colt"
person.dog.determineContext.call(person) // true

// Using call worked! Notice that we do NOT invoke sayHello or determineContext

Using Call in the Wild

var colt = {
    firstName: "Colt",
    sayHi: function(){
        return "Hi " + this.firstName 
    }
}

var elie = {
    firstName: "Elie",
    // Look at all this duplication :(
    sayHi: function(){
        return "Hi " + this.firstName 
    }
}

colt.sayHi() // Hi Colt
elie.sayHi() // Hi Elie (but we had to copy and paste the function from above...)

// How can we refactor the duplication using call? 

// How can we "borrow" the sayHi function from colt 
// and set the value of 'this' to be elie?

Let's examine a very common use case

Using Call in the Wild

var colt = {
    firstName: "Colt",
    sayHi: function(){
        return "Hi " + this.firstName 
    }
}

var elie = {
    firstName: "Elie"
}

colt.sayHi() // Hi Colt
colt.sayHi.call(elie) // Hi Elie 

// much better! 

Solution

What about Apply?

var colt = {
    firstName: "Colt",
    sayHi: function(){
        return "Hi " + this.firstName 
    },
    addNumbers: function(a,b,c,d){
        return this.firstName + " just calculated " + (a+b+c+d);
    }
}

var elie = {
    firstName: "Elie"
}

colt.sayHi() // Hi Colt
colt.sayHi.apply(elie) // Hi Elie 

// well this seems the same....but what happens when we start adding arguments?

It's almost identical to call - except the parameters!

colt.addNumbers(1,2,3,4) // Colt just calculated 10
colt.addNumbers.call(elie,1,2,3,4) // Elie just calculated 10
colt.addNumbers.apply(elie,[1,2,3,4]) // Elie just calculated 10

// What differences do you see?

And what about bind?

var colt = {
    firstName: "Colt",
    sayHi: function(){
        return "Hi " + this.firstName 
    },
    addNumbers: function(a,b,c,d){
        return this.firstName + " just calculated " + (a+b+c+d);
    }
}

var elie = {
    firstName: "Elie"
}

The parameters work like call, but bind returns a function with the context of 'this' bound already!

var elieCalc = colt.addNumbers.bind(elie,1,2,3,4) // function(){}...
elieCalc() // Elie just calculated 10
// With bind - we do not need to know all the arguments up front!

var elieCalc = colt.addNumbers.bind(elie,1,2) // function(){}... 
elieCalc(3,4) // Elie just calculated 10  

Bind in the wild

var colt = {
    firstName: "Colt",
    sayHi: function(){
        setTimeout(function(){
            console.log("Hi " + this.firstName)
        },1000)
    }
}

Very commonly we lose the context of 'this', but in functions that we do not want to execute right away!

var colt = {
    firstName: "Colt",
    sayHi: function(){
        setTimeout(function(){
            console.log("Hi " + this.firstName)
        }.bind(this),1000)
    }
}

Use bind to set the correct context of 'this'

colt.sayHi() // Hi undefined (1000 milliseconds later)
colt.sayHi() // Hi Colt (1000 milliseconds later)

4 - The 'new' keyword

function Person(firstName, lastName){
    this.firstName = firstName
    this.lastName = lastName
}

We can set the context of the keyword 'this' using the 'new' keyword - it does quite a bit more as well which we will discuss further when we talk about OOP

var elie = new Person("Elie", "Schoppik");
elie.firstName // "Elie"
elie.lastName // "Schoppik"

Recap

  • The keyword 'this' is a reserved keyword in JavaScript and its value is determined at execution
  • It is either set using the global context, object binding, explicit binding, or the new keyword
  • When set in the global context in a function, it is either the global object (window if in the browser) or undefined (if we are using strict mode)
  • To explicitly set the value of the keyword 'this', we use call, apply, or bind
  • We can also use the 'new' keyword to set the context of 'this', which we will discuss when we talk about Object Oriented Programming

The keyword 'this'

By Elie Schoppik

The keyword 'this'

What the keyword 'this' is in JavaScript and how we determine its value

  • 2,426