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.