Trong JavaScript, các phương thức call và apply được sử dụng để ràng buộc ngữ cảnh thực thi (giá trị this) của một hàm và truyền tham số khi gọi hàm. Sự khác biệt chính giữa chúng nằm ở cách truyền tham số, điều này quyết định việc sử dụng chúng trong các trường hợp cụ thể.
Tác dụng
- Thay đổi hướng
thisBắt buộc ràng buộcthistrong hàm đến đối tượng chỉ định, cho phép hàm thực thi trong ngữ cảnh cụ thể.
const obj1 = { name: "Alice" };
const obj2 = { name: "Bob" };
function greet() { console.log(this.name); }
greet.call(obj1); // In ra "Alice"
greet.apply(obj2); // In ra "Bob"
- Truyền tham số
call: Truyền tham số dưới dạng danh sách (ví dụ:func.call(thisArg, arg1, arg2, ...).apply: Truyền tham số dưới dạng mảng hoặc cấu trúc giống mảng (ví dụ:func.apply(thisArg, [argsArray]).
Sự khác biệt
| Phương thức | Cách truyền tham số | Trường hợp sử dụng |
|---|---|---|
call |
Truyền từng tham số (cách nhau bởi dấu phẩy) | Khi số lượng tham số đã biết và rõ ràng |
apply |
Truyền tham số qua mảng | Khi số lượng tham số không xác định hoặc đã có sẵn mảng |
Trường hợp sử dụng
1. Lent Method từ đối tượng khác
Khi một đối tượng cần sử dụng phương thức từ đối tượng khác:
const arrayLike = { 0: "a", 1: "b", length: 2 };
// Sử dụng phương thức push của mảng
Array.prototype.push.call(arrayLike, "c"); // arrayLike trở thành {0: "a", 1: "b", 2: "c", length: 3}
2. Thực hiện kế thừa (chuỗi constructor)
Gọi constructor cha trong constructor con:
function Parent(name) {
this.name = name;
}
function Child(name, age) {
Parent.call(this, name); // Kế thừa thuộc tính từ Parent
this.age = age;
}
3. Xử lý mảng tham số
Giải nén mảng thành danh sách tham số (thông dụng trước ES6):
const numbers = [1, 3, 5, 2];
const max = Math.max.apply(null, numbers); // In ra 5
// Thay thế ES6: Math.max(...numbers)
4. Thao tác với đối tượng giống mảng
Chuyển đổi đối tượng giống mảng (như arguments, danh sách nút DOM) thành mảng thực sự:
function example() {
const args = Array.prototype.slice.call(arguments); // Chuyển thành mảng
// Thay thế ES6: const args = Array.from(arguments);
}
5. Ràng buộc ngữ cảnh hàm rõ ràng
Đảm bảo this trong hàm callback hoặc xử lý sự kiện được ràng buộc đúng:
const handler = {
message: "Hello",
handleClick() { console.log(this.message); }
};
button.addEventListener("click", () => {
handler.handleClick.call(handler); // Ràng buộc `this` đến handler
});
// Cách viết ngắn gọn hơn: sử dụng bind()
button.addEventListener("click", handler.handleClick.bind(handler));
Tóm tắt
- Ưu tiên sử dụng
call: Khi tham số rõ ràng và số lượng cố định. - Ưu tiên sử dụng
apply: Khi tham số đã tồn tại trong mảng hoặc số lượng không xác định. - Thay thế ES6+: Toán tử giải nén (
...) vàArray.from()giảm thiểu việc sử dụngapply, nhưngcall/applyvẫn có giá trị trong các trường hợp yêu cầu tương thích cao hoặc đặc biệt.