NỘI DUNG BÀI VIẾT
Trong bài viết này, chúng ta sẽ nói về các phương thức bind, call và apply của prototype. Chúng là một số khái niệm quan trọng, thường được sử dụng trong JavaScript và có liên quan rất chặt chẽ với từ khóa this. Vì vậy, để nắm bắt được thông tin trong bài viết này, trước tiên bạn phải làm quen với khái niệm và cách sử dụng của từ khóa this và các object trong JavaScript.
Chúng ta bắt đầu tìm hiểu các method này nào.
Phương thức bind trong JavaScript
Bind là một phương thức nằm trong Function.prototype, do đó chỉ có function mới có khả năng gọi nó. Chúng ta gọi phương thức bind để xác định tham số this cho một function. Phương thức bind tạo ra một phương thức mới, khi được gọi, từ khóa this của nó được đặt thành giá trị được cung cấp, với một chuỗi đối số nhất định đứng trước bất kỳ đối số nào được cung cấp khi phương thức mới được gọi.
Cú pháp:
fun.bind(thisArg[, arg1[, arg2[, ...]]])
Code language: CSS (css)
Như trong trường hợp dưới đây, khi ta truyền hàm showName vào như một callback cho hàm button.click, giá trị this ở đây chính là button đó. Để hàm chạy đúng, ta dùng phương thức bind để bind giá trị person và this.
Tìm hiểu thêm về từ khóa this tại đây
var person = {
firstName: 'Hoc',
lastName: 'JavaScript',
showName: function() {
console.log(this.firstName + ' ' + this.lastName);
}
};
//showName truyền vào như callback, ở đây this chính là button
$('button').click(person.showName);
// Dùng bind để xác định giá trị this
$('button').click(person.showName.bind(person)); //this ở đây vẫn là object person
Code language: JavaScript (javascript)
Không chỉ bind được giá trị “this” , phương thức bind còn có thể bind được các tham số truyền vào cho hàm. Tức là ta có thể tao ra một function mới từ function cũ bằng cách gắn mặc định một tham số cho function cũ đó . Đó là cách tạo một Curry Function.
Bạn hãy xem ví dụ cụ thể sau. 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);
}
Code language: JavaScript (javascript)
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 logErrToday(message) {
log("Error", "Today", message);
}
Code language: JavaScript (javascript)
Ta có thể tạo function mới bằng cách sử dụng bind bằng cách gán mặc định 2 tham số đầu tiên như sau:
var logErrToday = log.bind(null, 'Error', 'Today');
Code language: JavaScript (javascript)
Phương thức call và apply trong JavaScript
Hai phương thức này đều nằm trong function prototype cho nên chỉ có function mới có thể gọi được
Chức năng chung của chúng là xác định một tham số, xác định this và truyền các tham số còn lại vào.
Điểm khác nhau cơ bản giữa chúng là apply sẽ truyền các tham số dưới dạng một array hoặc array-like objects, còn call sẽ truyền lần lượt các tham số.
Cú pháp:
call()
Function.prototype.call(thisArg[, arg1[ , arg2, …]])
apply()
Function.prototype.apply(thisArg, argArray)
Code language: CSS (css)
Cùng xem ví dụ đơn giản này về call và apply, bạn sẽ hiểu ngay:
// Tìm max bằng cách gọi hàm Math.max
Math.max(4, 3, 2, 10);
// Thay vì gọi trực tiếp hàm Math.max, ta có thể dùng call
// Set this bằng null
Math.max.call(null, 4, 3, 2, 10);
// Apply tương tự call, nhưng không truyền lần lượt
// Mà truyền một array chứa toàn bộ các tham số
Math.max.apply(null, [4, 3, 2, 10]);
Code language: JavaScript (javascript)
Call và apply còn có thể được dùng để mượn hàm (borrowing function). Hãy cũng xem ví dụ dưới đây
function test(firstParam, secondParam, thirdParam){
var args = Array.apply(null, arguments);
console.log(args);
}
test(1, 2, 3); // [1, 2, 3]
Code language: JavaScript (javascript)
Arguments là một object giống array nhưng không phải là array. Arguments giống array vì nó có fieldlength, có thể truy cập các giá trị nó chứa thông qua index 0,1,2. Tuy nhiên, do arguments không phải là array nên nó không thể gọi các hàm của Array.prototype.
Do đó, ta phải sử dụng call/apply để mượn một số hàm trong Array.prototype, các hàm này sẽ trả ra một array cho ta xử lý. Dòng code phía trên chuyển object arguments thành một array
Ngoài ra, call và apply còn được dùng để monkey-patching hoặc tạo spy. Ta có thể mở rộng chức năng của một hàm mà không cần sửa source code của hàm đó. Ví dụ ta có hàm accessWeb của object computer.
var computer = {
accessWeb : function(site) {
// Đi tới site nào đó
console.log ('Go to: ' + site);
}
};
computer.accessWeb('hocjavascript.net'); //Go to: hocjavascript.net
Code language: JavaScript (javascript)
Sử dụng call, ta có thể ghi thêm log trước và sau khi hàm accessWeb được gọi mà không can thiệp vào code của hàm đó
var oldFunction = computer.accessWeb;
// Tráo function accessWeb bằng hàm mới
computer.accessWeb = function() {
console.log('Bạn đã truy cập vào web');
oldFunction.apply(this, arguments); // giữ nguyên hàm cũ
console.log('Bạn đã truy cập vào web');
}
computer.accessWeb('hocjavascript.net');
Code language: JavaScript (javascript)
Kết quả ta thấy 2 console.log đc tạo → việc mở rộng hàm thành công rồi đó
Kết luận
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.
Cảm ơn các bạn đã theo dõi bài viết!
Các bạn có thể tham khảo các bài viết hay về JavaScript tại đây.
Hãy tham gia nhóm Học lập trình để thảo luận thêm về các vấn đề cùng quan tâm.
TỔNG HỢP TÀI LIỆU HỌC LẬP TRÌNH CƠ BẢN CHO NGƯỜI MỚI BẮT ĐẦU
KHOÁ HỌC BOOTCAMP JAVA/PHP/.NET TRỞ THÀNH LẬP TRÌNH VIÊN TRONG 5-6 THÁNG