Giới thiệu
Ba hàm bind, call và apply là các prototype của Function nên chỉ có Function mới có thể gọi được 3 hàm này. Sở dĩ, một Function có thể gọi Function khác vì trong JavaScript, Function cũng là một loại Object, mà đã là Object thì sẽ có prototype, hay nói cách khác là gọi được phương thức của nó.
Lưu ý:
- "bind", "call", "apply" dùng để thiết lập ngữ cảnh ngữ cảnh con trỏ this
- "bind" không tồn tại trong arrow function ()=> {} (vì arrow function không có context)
Video Học Lập trình
Nguồn Yotube - Akshay Saini
Bind()
Bind() cho phép chúng ta dễ dàng thiết lập một đối tượng cụ thể sẽ bị ràng buộc này khi một chức năng hoặc phương pháp được gọi.
Cú pháp: func.bind(thisArg[, arg1[, arg2[, ...argN]]])
- thisArg: Giá trị của this được đưa ra để gọi hàm. Giá trị bị bỏ qua nếu hàm liên kết được xây dựng bằng toán tử new. Khi sử dụng bind để tạo ra một hàm dưới dạng callback trong hàm setTimeout, bất kỳ giá trị nào sơ khai được truyền dưới dạng thisArg sẽ được chuyển đổi thành đối tượng.
- arg1, arg2, ...argN: Các đối số cho hàm.
const teacher = {
firstName: "Thư",
lastName: "Nguyễn",
getFullname: function () {
console.log(`${this.firstName} ${this.lastName}`);
},
};
teacher.getFullname(); //Thư Nguyễn
const callGetFullname = teacher.getFullname;
callGetFullname(); // undefined undefined
-> this ở đây sẽ là đối tượng window
const student = {
firstName: "Nam",
lastName: "Hoài",
};
const useBindForStudent = teacher.getFullname.bind(student);
useBindForStudent(); // Nam Hoài
-> bind sẽ ràng buộc this cho student
- Không chỉ bind được giá trị this, bind còn bind được các tham số truyền vào cho hàm nữa. Do đó, Bind còn được dùng để viết partial function.
- Nói một cách đơn giản, partial function tức là tạo ra 1 function mới từ 1 function cũ bằng cách gán mặc định một số tham số cho function cũ đó.
Ví dụ: Mình có một hàm log đơn giản có 3 tham số
function log(level, time, message) {
console.log(level + ' - ' + time + ': ' + message);
}
Giả sử mình muốn tạo một hàm log khác, ghi lại các log error của hôm nay, mình có thể viết một hàm mới dựa theo hàm log cũ:
function log(level, time, message) {
console.log(level + ' - ' + time + ': ' + message);
}
function logErrToday(message) {
log("Error", "Today", message);
}
logErrToday("Server die."); // Error - Today: Server die.
Thay vì viết như thế, mình có thể viết đơn giản hơn bằng các dùng bind. Ở đây log là function cũ, logErrToday là function mới, được tạo ra bằng cách gán mặc định 2 tham số level và time.
function log(level, time, message) {
console.log(level + ' - ' + time + ': ' + message);
}
// Không có this nên set this là null
// Set mặc định 2 tham số level và time
var logErrToday = log.bind(null, 'Error', 'Today');
// Hàm này tương ứng với log('Error', 'Today', 'Server die.')
logErrToday("Server die.");
// Error - Today: Server die.
Call()
Call gọi một hàm với giá trị của this và các đối số riêng lẻ.
Cú pháp: function.call(thisArg, arg1, arg2, ...)
Trong đó:
- thisArg: Giá trị của this được đưa ra để gọi hàm. Lưu ý rằng this có thể không phải là giá trị thực tế được thấy bởi phương thức: Nếu phương thức là một hàm trong non-strict mode, giá trị null và undefined sẽ được thay thế với global object và các giá trị sơ khai (primitive) sẽ được chuyển thành các đối tượng (objects).
- arg1, arg2, ...argN: Các đối số cho hàm.
Các bạn hãy theo dõi các ví dụ dưới để hiểu rõ về cách sử dụng hàm call trong javascript nhé.
Ví dụ 1: dùng call để thay đổi ngữ cảnh con trỏ this
const person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
const person1 = {
firstName:"John",
lastName: "Doe"
}
const person2 = {
firstName:"Mary",
lastName: "Doe"
}
person.fullName.call(person1); // John Doe
person.fulllname.call(person2): // Mary Doe
Ví dụ 2: Sử dung hàm call để gọi hàm và đưa ra một giá trị cho đối tượng 'this'
function greet() {
var reply = [this.person, 'Is An Awesome', this.role].join(' ');
console.log(reply);
}
var x = {
person: 'Khoa Nguyen', role: 'Javascript Developer'
};
greet.call(x); // Khoa Nguyen Is An Awesome Javascript Developer
Trong ví dụ dưới trên khi chúng ta gọi hàm greet , giá trị của this trong hàm greet chính là đối tượng x.
Ví dụ 3: Sử dung call để chain constructors cho một đối tượng
Bạn có thể sử dụng hàm call để chain constructors cho một đối tượng giống như trong Java. Trong ví dụ dưới đây, hàm khởi tại của đối tượng Product được định nghĩa với 2 tham số, name và price. Hai hàm Food và Toy gọi Product với tham số this , name và price. Product khởi tạo thuộc tính name và price, cả 2 hàm này định nghĩa category.
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}
function Toy(name, price) {
Product.call(this, name, price);
this.category = 'toy';
}
var cheese = new Food('feta', 5);
var fun = new Toy('robot', 40);
Apply()
Apply gọi một hàm với giá trị của this và các đối số được truyền vào dưới dạng mảng.
Cú pháp:
func.apply(thisArg, [ argsArray])
- thisArg: Giá trị của this được đưa ra để gọi hàm. Lưu ý rằng this có thể không phải là giá trị thực tế được thấy bởi phương thức: Nếu phương thức là một hàm trong non-strict mode, giá trị null và undefined sẽ được thay thế với global object và các giá trị sơ khai (primitive) sẽ được chuyển thành các đối tượng (objects).
- argsArray: Một mảng chỉ định các đối số cho hàm, hoặc null hoặc undefined nếu không có đối số nào được cung cấp.
Các bạn hãy theo dõi các ví dụ dưới để hiểu rõ về cách sử dụng hàm apply trong javascript nhé.
Ví dụ 1: Sử dụng hàm apply với built-in functions
const person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
const person1 = {
firstName: "Mary",
lastName: "Doe"
}
// This will return "Mary Doe":
person.fullName.apply(person1);
Ví dụ 2: Sử dụng hàm apply để nối 1 mảng vào 1 mảng khác
const array = ['a', 'b']; const elements = [0, 1, 2]; array.push.apply(array, elements); console.info(array); // ["a", "b", 0, 1, 2]
Ví dụ 3: Sử dung apply để chain constructors
Bạn có thể sử dụng hàm call để chain constructors cho một đối tượng giống như trong Java.
Trong ví dụ dưới đây chúng ta sẽ tạo ra một global Function method gọi là construct, phương thức này sẽ cho phép bạn sử dụng một đối tượng giống mảng với một hàm tạo thay vì một danh sách đối số.
Function.prototype.construct = function(aArgs) {
let oNew = Object.create(this.prototype);
this.apply(oNew, aArgs);
return oNew;
};
Phân biệt Call(), Apply(), Bind()
- Nhìn chung, hàm call và apply là gần giống nhau. Chúng đều gọi hàm trực tiếp. Chỉ khác ở cách truyền tham số vào (với call thì đối số phân cách bởi dấu phẩy và với apply thì đối số cho bởi mảng array)
- Hàm bind thì hơi khác hơn một chút. Hàm này không gọi hàm trực tiếp mà trả về một hàm mới. Sau đó, bạn có thể sử dụng hàm mới này. Về cách truyền tham số vào thì hàm bind giống với hàm call.
Tổng kết
Bằng việc sử dụng bind, call và aplly ta có thể thay đổi được ngữ cảnh thực thi (phạm vi chứa hàm) để sử dụng một hàm với công dụng đa năng hơn như thực thi cho một đối tượng, phạm vi khác khác giúp ta có thể tận dụng tối đa mã nguồn được đã tạo ra, hay tạo shortcut cho hàm, linh hoạt hơn tham số đầu vào.
Với call và apply, chúng ta sử dụng để thực thi hàm đó luôn khi gọi, còn với bind ta có thể thực thi hàm đó nhiều lần sau khi đã được buộc (bind) với một ngữ cảnh nhất định.




