When talking about the this
keyword in JavaScript, you may find the concept quite confusing. The meaning of this
changes in different contexts, making it one of the most common challenges JavaScript developers encounter. Understanding the behavior of this
in different contexts is key to writing efficient, maintainable code. In this article, we’ll take a closer look at the multiple identities of this
in JavaScript. From global scopes to function calls to object methods and constructors, we’ll break down the behavior of this
in various contexts to help you better understand and apply this key concept.
- Why do we need this?
To give functions in an object the ability to access the object’s own properties
- Let’s look at the following code
let obj = {
myname:'xiaoxiao',
age:18,
bar: function(){
console.log(myname);
}
}
obj.bar()
When executing this code, we will find that it doesn’t print out Tao, but reports an error, why is that? At this point, we change console.log(myname);
to console.log(this。myname);
, we access myname through this, and it finally prints out successfully.
-
The beauty of this: it can significantly improve code quality and reduce the passing of contextual parameters
function identify(){
return this.name.toUpperCase()
}
function speak(){
var greeting = 'Hello i am' + identify.call(this)
console.log(greeting);
}
var me = {
name:'xiaoxiao',
}
speak.call(me)
In this code we are in the speak()
function and we have created a variable greeting
whose value is the splice of the result of 'Hello i am'
and identify.call(this)
. The call to means that we are binding in the function to in the function. identify.call(this)
This call means that we are binding this
in the identify()
function to this
in the speak()
function. This is called an explicit binding, and the call()
method allows us to manually specify where this
should point within the function.
We then call thespeak()
function on theme
object, which bindsthis
from thespeak()
function to theme
object. As a result,this
inidentify.call(this)
will point to theme
object, and so theidentify()
function returns the uppercase form of thename
property of theme
object.
Finally,console.log(greeting)
will print out'Hello i am XIAOXIAO'
where'XIAOXIAO'
is the uppercase form of thename
property of theme
object.
We can control the pointing ofthis
within theidentify()
function from within thespeak()
function. This flexibility allows us to reuse functions in different contexts and dynamically change the pointing ofthis
inside functions.
Binding rules for this
– [ ] 1. Default binding: When a function is called independently, without any modifiers, the lexical scope under which the function is in effect is wherever this in the function points — (as long as it’s bound by default, this must point to the window)*.
function foo(){
console.log(this);
}
foo();
This code prints out the window:
var obj = {
a: 1,
foo: function(){
console.log(this);//obj
}
}
obj.foo()
And this code prints out the object in the obj:
-
When a function is referenced by the following object (when the function is owned by an object) the function’s this points to the object that references it
const obj = {
name: 'John',
greet: function() {
console.log('Hello, ' + this.name);
}
};
obj.greet(); // Output: Hello, John
In this example, the greet
function is called as a method of the obj
object. Inside the greet
function, the this
keyword points to the object that called it, the obj
object, so this.name
will output John
.
-
Implicitly lost: when a function is chained by multiple objects, the function’s this points to the nearest one
const obj1 = {
name: 'John',
greet: function() {
console.log('Hello, ' + this.name);
}
};
const obj2 = {
name: 'Alice'
};
obj1.greet.call(obj2); // Output: Hello, Alice
In this example, the greet
function was originally intended as a method on the obj1
object, but the greet
function was extracted from the obj1
object via the call
method and called on the obj2
object. In this case, the this
keyword inside the greet
function points to the obj2
object instead of the obj1
object, so the output is Hello, Alice
instead of Hello, John
.
Implicit loss occurs here because the greet
function was expected to be called in the obj1
context, but the context changed to obj2
at the time of the call. In this case, special attention needs to be paid to the context in which the function is called to avoid the implicit loss problem.
Show bind: call apply bind
-
The call:call
method calls a function whose first argument is the object to be set as the function’s execution context. The subsequent arguments are the list of parameters passed to the function
function greet(name) {
console.log(`Hello, ${name}! My name is ${this.name}.`);
}
const person = {
name: 'Alice'
};
greet.call(person, 'Bob');
This will print out: Hello, Bob! My name is Alice.
. In this example, the call
method sets the execution context of the greet
function to the person
object and passes a parameter 'Bob'
to the greet
function.
apply: The apply
method is similar to the call
method, except that its second argument is an array whose elements are passed as arguments to the function.
function greet(name, age) {
console.log(`Hello, ${name}! I am ${age} years old. My name is ${this.name}.`);
}
const person = {
name: 'Alice'
};
greet.apply(person, ['Bob', 30]);
This will print out: Hello, Bob! I am 30 years old. My name is Alice.
. apply
The method sets the execution context of the greet
function to the person
object and passes two parameters 'Bob'
and 30
to the greet
function.
bind: The bind
method creates a new function and binds the specified object to the execution context of that function. Unlike call
and apply
, bind
does not execute the function immediately, but returns a new function that you can call later.
function greet(name) {
console.log(`Hello, ${name}! My name is ${this.name}.`);
}
const person = {
name: 'Alice'
};
const greetPerson = greet.bind(person);
greetPerson('Bob');
This will print out: Hello, Bob! My name is Alice.
. bind
The method creates a new function greetPerson
and binds the person
object to the execution context of that function. When the greetPerson
function is called later, the person
object becomes the this
value of the greet
function.
In summary, all three methods allow you to explicitly set the value ofthis
inside a function when you call it, and to pass arguments to the function.call
Whileapply
is very similar to in terms of setting the function context and passing parameters,bind
creates a new function and binds the specified object as the execution context for that function.
- new binding: this points to the created instance object
function Person(name, age) {
this.name = name;
this.age = age;
}
const person1 = new Person('Alice', 30);
console.log(person1.name); // Alice
console.log(person1.age); // 30
new
Binding is a way of creating a new object that binds the constructor’s this
to the newly created instance object. When you call a function using the new
keyword, JavaScript performs the following steps:
Create an empty normal JavaScript object (i.e., the empty object{}
).- Link the prototype of this empty object to the prototype object of the constructor.
Execute the constructor and bind this empty object tothis
inside the constructor.
If the constructor does not explicitly return an object, this newly created object is returned.
In general, the value of this
is dynamic in JavaScript and depends on how the function is called. Understanding the behavior of this
is important for proper use of JavaScript functions and object-oriented programming.