Understanding and changing 'this' in JavaScript with bind(), call() and apply()

I’ve been a web developer for some three years now and in this time I feel as though I had a reasonable handle on understanding JavaScript. There’s one thing that I have seen more often recently which is the use of bind() call() abd apply() and how they relate to the this keyword in JavaScript.

I have written JavaScript in Angular which uses classes to produce components, services, directives etc where the use of this refers to the class context. In Angular, I have been writing this blindly, as it just works, but I haven’t considered why this is what it is!

Understanding this, bind call and apply is not something that I picked up in the course of my regular learning, so here’s my understanding and explanation of these things! This has helped to give me greater depth to the JavaScript I am writing and why this is this and that is that.

What is ‘this’ in JavaScript

The this oject refers to the context in which ‘this’ is being accessed. For example as seen below

function scottsFunction() {
  console.log("Function:", this)
}
scottsFunction()
// context of this at this point is the Window object as
// the function is not being invoked by any 'parent' element.

const scottsObj = {
  name: "scott",
  method() {
    console.log("Object:", this)
  },
}

scottsObj.method()
// context of 'this' will be scottsObj, as it is the object that is
// invoking the method

class ScottsClass {
  name: string = "scott"
  classMethod() {
    console.log("class", this)
  }
}

const instanceOfClass = new ScottsClass()
instanceOfClass.classMethod()
// context of 'this' will be the instanceOfClass const. This is because
// It is the instance of the class that is invoking the method.

As we can see, the value of this is dependent on the context in which it is being used/ the owner or parent. It is possible to set up the context ourselves so that we can dependably understand what this will be referring to.

How can we change what ‘this’ is pointing to?

The bind(), call() and apply() methods are admittedly the reason why I am writing this post. I had seen then used in production, gotten scared just looking at them, and then subsequenetly never used them. I’ve overcome this by getting a better understanding of what they do.

call() and apply()

The call() and apply() methods exists on the function prototype and allows us to pass in an argument to set the context of this.

Consider the below:

function scottsFunction() {
  console.log("Function:", this)
}

const scottsObj = {
  name: "Scott",
  method() {
    console.log("Object:", this)
  },
}

scottsFunction()
// invoking scottsFunction(), this is referring to window object.

scottsFunction.call(scottsObj)
// invoking scottsFunction(), this is now referring to scottsObj.

scottsFunction.call({ name: "Scott" })
// invoking scottsFunction(), this is now referring to object argument.

In my mind, I consider it to be similar to scottsObj.scottsFunction() or:

const obj = {
  name: "Scott",
  scottsFunction() {
    console.log(this)
  },
}

apply() can be used in almost the same way. The main difference between call and apply though is how we can pass in arguments to the method. Consider the below:

function myFunction(thisContext: string) {
  console.log(this, `is parent element is ${thisContext}`)
}

// On it's own, myFunction('window') would be accurate.

// Using `call` and `apply` though, we can change `this`
// whilst also passing in arguments.
// `call` will take arguments as comma separated,
// whereas `apply` will take an array.

const newContext = {}

myFunction("window")
myFunction.call(newContext, "the passed in object")
myFunction.apply(newContext, ["the passed in object"])

call and apply are part of the function prototype and always things I have avoided, until now!

As can be seen, call and apply will invoke method instantly with the new this context.

bind()

The bind method allows us to set up the binding to the new this and use when required. Consider the below:

function myFunction(thisContext: string) {
    console.log(this, `the parent element is the ${thisContext}` )
}

const newContext = {};

const myBoundFunction = myFunction.bind(newContext);
// By calling bind on myFunction we can bind the function context to
// a new `this` and then invoke when we need it. Rather than instantly as
// seen with call and apply

myBoundFunction('object newContext');
// The bound function needs to be invoked. Calling `.bind` does not invoke
// the method.
// {} "the parent element is the object newContext"

Whilst I thought I had a good handle on scoping and this in JavaScript, going into more depth with these function prototype methods has given me a greater understanding of context in JavaScript programming.

Get in contact

Complete the form below to get in contact with me 😃