What is context?
What happens when you drop a ball?. If your answer is "the ball will hit the floor", you assumed this happened on Earth (or any place with gravity 😀). What if this happened on Moon?. The answer will be different. Right?. This is because the context is different. So context can be defined as surrounding data that will affect whatever is inside.
Functions and Context
Functions are a block of code that solves a specific problem and functions can be executed anywhere in the program (i.e., you can call it whenever you need it). Functions are never executed in isolation, they will always run in a context. Look at the code below.
var name = "John Doe"
function printName() {
console.log(name);
}
printName();
Output
John Doe
Function printName
can access variable name
just because the context of the function is the global
and the variable is defined on the global
.
I called context as
the global
because when you are running on Node it will beglobal
and on browser, it will bewindow
.
The context of the function will determine what variables or methods a function can access. This can be determined statically by just looking at the code. If there is nothing unusual and if the code is predictable there is nothing to worry about right?. Unless there is this
.
What is this
in JavaScript?
The concept of this
is not entirely exclusive to JavaScript. All programming languages have it. Then what's the hustle about this in JavaScript?.
Let's take a look at this code below.
var name = "John Doe";
function printName() {
console.log(this.name);
}
setTimeout(printName, 1000);
Output - Node
undefined
Output - Browser
John Doe
The output may differ in different browsers as well.
The output in the Browser
differs from Node
because the implementation of setTimeout
in both environments is different.
Why?
Functions in JavaScript are very powerful. Unlike other programming languages, functions in JavaScript can act differently. Like in the above code, the output is different because the value of this
is bonded at the time of execution, which makes it unpredictable, yet JavaScript does this way.
Let's take a look at another piece of code.
var obj = {
name: "John Doe",
};
obj.printName = function () {
console.log(this.name);
};
obj.printName();
Output
John Doe
In the above code, the context of the function printName
is obj
. Since the value of this
is bonded dynamically, you can access name
from the this
keyword. In here, a function is attached later on the obj
, this is possible only if the this
keyword value is bonded dynamically. You can't achieve this on programming languages such as Java or Python.
The Problem
Take a look at the code below.
var name = "John Doe 1";
var obj = {
name: "John Doe 2",
};
function printName() {
console.log(this.name);
}
obj.printName = printName;
obj.printName();
printName();
Output - Node
John Doe 2
undefined
Output - Browser
John Doe 2
John Doe 1
In the above code snippet, we are using the same function in both cases, we are not passing any parameters or anything. But the output is different since the value of this
is dependent on the context. So when you see a code like this.
function printName() {
console.log(this.name);
}
You can't determine the output, since it depends on the context. Getting different outputs for the same function is not a good idea, but if you use it correctly, you can do magic with it.
Playing with this
Strict mode
If you are defining a function like this
var name = "John Doe"
function printName() {
console.log(this.name);
}
What will be the context of the function?. It will bond to the global
, But if you are running in strict mode
, the context will be undefined
.
new
keyword
In JavaScript, you can invoke a function using the new
keyword. In this case, the value of this
will be an empty object.
function printName() {
console.log(this);
}
new printName();
Output:
{}
bind
, call
and apply
Since the context of the function is hard to determine, JavaScript provides some methods on the function to pass context with it.
call/apply
call
and apply
invokes the function immediately with a given context and arguments. The only difference is how the function arguments passed. In the apply
function arguments are passed as an array and in the call
function arguments are passed comma separated.
var obj = {
number: 1,
multiply: function (number1, number2) {
console.log(this.number * number1 * number2);
},
};
obj.multiply.call({ number: 2 }, 3, 4); //arguments as comma separated
obj.multiply.apply({ number: 2 }, [3, 4]); // arguments as an array
Output
24
24
Here the context is changed in the first argument of both call
and apply
, which makes the output 24
instead of 12
.
bind
bind
is another method available on function, which will return a new function with a given context.
var obj = {
number: 1,
multiply: function (number1, number2) {
console.log(this.number * number1 * number2);
},
};
var multiply = obj.multiply.bind({ number: 2 });
multiply(3, 4);
Ouput
24
Arrow functions
Arrow functions are introduced in ES6 to solve this context issue. this
keyword is not bonded in the arrow function.
var obj = {
name: "John Doe",
printName: function () {
setTimeout(function(){
console.log(this.name);
}, 1000);
},
};
obj.printName();
Output - Node
undefined
Output - Browser
""
Here, the context of the function is setTimeout
, so the value will depend on that. To solve this:
var obj = {
name: "John Doe",
printName: function () {
setTimeout(() => {
console.log(this.name);
}, 1000);
},
};
obj.printName();
Output - Node/Browser:
John Doe
There will be no context binding on arrow functions, which makes the output of the code more predictable.
Conclusion
Everything in JavaScript works the same as almost every other programming language except the this
keyword. The value of the this
keyword is determined at the run time. This may make your code unpredictable, but you can achieve almost everything using this
.
Top comments (0)