The ’this’ Keyword and Context Binding
The this keyword refers to the object that a function belongs to. Understanding this is crucial for object-oriented JavaScript.
What is ’this'?
this refers to the context in which a function is executed:
const person = {
name: "Alice",
greet: function() {
console.log(this.name);
}
};
person.greet(); // "Alice" - this refers to person
Global Context
In global scope, this refers to the global object:
// In browser
console.log(this); // window object
// In Node.js
console.log(this); // global object (or module.exports)
Function Context
When a function is called without an object, this is the global object (or undefined in strict mode):
function test() {
console.log(this);
}
test(); // window (browser) or global (Node.js)
Strict Mode
In strict mode, this is undefined:
"use strict";
function test() {
console.log(this); // undefined
}
test();
Method Context
When a function is called as a method, this refers to the object:
const calculator = {
value: 0,
add: function(n) {
this.value += n;
return this;
},
subtract: function(n) {
this.value -= n;
return this;
},
getValue: function() {
return this.value;
}
};
calculator.add(5).subtract(2);
console.log(calculator.getValue()); // 3
Method Extraction Problem
const person = {
name: "Alice",
greet: function() {
console.log(this.name);
}
};
const greet = person.greet;
greet(); // undefined - this is now global
call() Method
Call a function with a specific this context:
function greet(greeting) {
return `${greeting}, ${this.name}!`;
}
const person = { name: "Alice" };
console.log(greet.call(person, "Hello")); // "Hello, Alice!"
Multiple Arguments
function introduce(greeting, punctuation) {
return `${greeting}, I'm ${this.name}${punctuation}`;
}
const person = { name: "Bob" };
console.log(introduce.call(person, "Hi", "!")); // "Hi, I'm Bob!"
apply() Method
Similar to call(), but arguments are passed as an array:
function greet(greeting, punctuation) {
return `${greeting}, ${this.name}${punctuation}`;
}
const person = { name: "Charlie" };
console.log(greet.apply(person, ["Hello", "!"])); // "Hello, Charlie!"
Practical Use: Math Functions
const numbers = [5, 6, 2, 3, 7];
const max = Math.max.apply(null, numbers);
console.log(max); // 7
// Or with spread operator
const max2 = Math.max(...numbers);
console.log(max2); // 7
bind() Method
Create a new function with a fixed this context:
function greet(greeting) {
return `${greeting}, ${this.name}!`;
}
const person = { name: "Diana" };
const greetPerson = greet.bind(person);
console.log(greetPerson("Hello")); // "Hello, Diana!"
Partial Application
function multiply(a, b) {
return a * b;
}
const double = multiply.bind(null, 2);
console.log(double(5)); // 10
console.log(double(10)); // 20
Event Handlers
const button = {
label: "Click me",
handleClick: function() {
console.log(this.label);
}
};
// Without bind - this is the button element
// element.addEventListener("click", button.handleClick);
// With bind - this is the button object
// element.addEventListener("click", button.handleClick.bind(button));
Arrow Functions and this
Arrow functions don’t have their own this - they inherit from parent scope:
const person = {
name: "Eve",
greet: function() {
console.log(this.name); // "Eve"
},
greetArrow: () => {
console.log(this.name); // undefined (this is global)
}
};
person.greet(); // "Eve"
person.greetArrow(); // undefined
Arrow Functions in Methods
const person = {
name: "Frank",
hobbies: ["reading", "gaming"],
listHobbies: function() {
this.hobbies.forEach(hobby => {
console.log(`${this.name} likes ${hobby}`);
});
}
};
person.listHobbies();
// Frank likes reading
// Frank likes gaming
Practical Examples
Class Methods
class Counter {
constructor(initial = 0) {
this.count = initial;
}
increment() {
this.count++;
return this.count;
}
decrement() {
this.count--;
return this.count;
}
getCount() {
return this.count;
}
}
const counter = new Counter(10);
console.log(counter.increment()); // 11
console.log(counter.decrement()); // 10
Event Handler with Context
class Button {
constructor(element) {
this.element = element;
this.clickCount = 0;
// Bind the handler to maintain this context
this.element.addEventListener("click", this.handleClick.bind(this));
}
handleClick() {
this.clickCount++;
console.log(`Clicked ${this.clickCount} times`);
}
}
// Usage
// const btn = new Button(document.getElementById("myButton"));
Callback with Context
const user = {
name: "Grace",
friends: ["Henry", "Iris", "Jack"],
listFriends: function() {
this.friends.forEach(function(friend) {
console.log(`${this.name} is friends with ${friend}`);
}.bind(this)); // Bind this to user object
}
};
user.listFriends();
// Grace is friends with Henry
// Grace is friends with Iris
// Grace is friends with Jack
Method Chaining
const calculator = {
value: 0,
add(n) {
this.value += n;
return this; // Return this for chaining
},
multiply(n) {
this.value *= n;
return this;
},
subtract(n) {
this.value -= n;
return this;
},
result() {
return this.value;
}
};
const result = calculator
.add(5)
.multiply(2)
.subtract(3)
.result();
console.log(result); // 7 (5 + 5 = 10, 10 * 2 = 20, 20 - 3 = 17... wait, let me recalculate)
// Actually: (0 + 5) * 2 - 3 = 10 - 3 = 7
call vs apply vs bind
| Method | Syntax | Invokes | Use Case |
|---|---|---|---|
| call() | fn.call(obj, arg1, arg2) |
Immediately | Direct invocation |
| apply() | fn.apply(obj, [arg1, arg2]) |
Immediately | Array of arguments |
| bind() | fn.bind(obj, arg1, arg2) |
Returns function | Event handlers, callbacks |
Common Mistakes
Losing Context
// Problem
const person = {
name: "Henry",
greet: function() {
console.log(this.name);
}
};
const greet = person.greet;
greet(); // undefined - lost context
// Solution
const greet2 = person.greet.bind(person);
greet2(); // "Henry"
Arrow Functions in Objects
// Problem - arrow function loses this
const obj = {
name: "Iris",
greet: () => {
console.log(this.name); // undefined
}
};
// Solution - use regular function
const obj2 = {
name: "Jack",
greet: function() {
console.log(this.name); // "Jack"
}
};
Summary
- this: refers to the object context
- Global: this is global object (or undefined in strict mode)
- Method: this refers to the object
- call(): invoke with specific this
- apply(): invoke with this and array of arguments
- bind(): create new function with fixed this
- Arrow functions: inherit this from parent scope
- Best practice: be explicit about context
Related Resources
Official Documentation
- MDN: this
- MDN: Function.prototype.call()
- MDN: Function.prototype.apply()
- MDN: Function.prototype.bind()
Next Steps
- ES6 Classes: Syntax and Features
- Closures: Understanding Function Scope
- Callbacks and Asynchronous JavaScript
Comments