The Ambiguity of ‘this’
In many object-oriented languages, this (or self) always refers to the current instance of a class. In JavaScript, however, this is a dynamic reference that is determined not by where a function is defined, but by how the function is called. This is known as call-site binding.
Understanding this requires evaluating four primary binding rules in order of precedence.
1. Default Binding
When a function is called as a standalone function (e.g., func()), this defaults to the global object (window in browsers, global in Node.js). However, if strict mode is active, this will be undefined.
2. Implicit Binding
When a function is called as a method of an object (e.g., obj.method()), this is bound to the object that “owns” or contains the function call.
const user = {
name: "Alice",
greet() {
return `Hello, I'm ${this.name}`;
}
};
console.log(user.greet()); // "Hello, I'm Alice"
Implicit Lost: A common source of bugs occurs when a method is assigned to a variable or passed as a callback. In these cases, the implicit binding is “lost,” and the function reverts to default binding.
3. Explicit Binding: Call, Apply, and Bind
JavaScript provides three methods to explicitly set the this context for a function call.
call(context, arg1, arg2, ...): Invokes the function immediately with the provided context and individual arguments.apply(context, [args]): Invokes the function immediately with the provided context and an array of arguments.bind(context, ...args): Returns a new function with thethiscontext permanently bound to the provided value.
4. New Binding
When a function is called with the new keyword (as a constructor), this is bound to the newly created object. This binding takes precedence over implicit and explicit binding.
Lexical ‘this’ in Arrow Functions
Arrow functions do not have their own this binding. Instead, they inherit this from the surrounding (parent) lexical scope. This is extremely useful for maintaining context in asynchronous callbacks or nested functions without needing to use bind() or closure hacks like const self = this.
Binding Precedence Summary
- New Binding: Was the function called with
new? - Explicit Binding: Was the function called with
call,apply, orbind? - Implicit Binding: Was the function called as a method on an object?
- Default Binding: Is it a standalone function call? (Mind strict mode).