Bind, Call và Apply trong javascript
Xin chào mọi người, bài viết này ta sẽ tìm hiểu về 3 hàm khá quan trọng khi làm việc với javascript đó là bind(), call() và apply(). Khi học Javascript mình đã rất thắc mắc sự khác biệt và khi nào nên sử dụng hàm call() và hàm apply(), Javacript không dư thừa đến mức tạo ra hai hàm có công dụng y ...
Xin chào mọi người, bài viết này ta sẽ tìm hiểu về 3 hàm khá quan trọng khi làm việc với javascript đó là bind(), call() và apply(). Khi học Javascript mình đã rất thắc mắc sự khác biệt và khi nào nên sử dụng hàm call() và hàm apply(), Javacript không dư thừa đến mức tạo ra hai hàm có công dụng y chang nhau. Hãy cùng tìm hiểu về sự khác biệt của chúng.
Bind là một hàm nằm trong Function.prototype, do đó chỉ có function mới có khả năng gọi nó. Bind được dùng để xác định tham số this cho một function. Hãy cùng xem ví dụ khá phổ biến dưới đây.
var person = { firstName: 'Hoang', lastName: 'Pham', 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);
Trong quá trình làm việc với Jquery nếu không để ý sẽ dễ gặp bugs vì nghĩ this ở đây sẽ trỏ đến person nhưng thực tế là nó lại trỏ đến button do đó sẽ dẫn đến kết quả không mong muốn. Để fix lỗi trên ta sẽ sử dụng hàm bind()
// Dùng bind để xác định giá trị this $('button').click(person.showName.bind(person)); //this ở đây vẫn là object person
Hàm bind() cho phép mượn method
var user = { data :[ {name:"T. Woods", age:37}, {name:"P. Mickelson", age:43} ], showData:function (event) { var randomNum = ((Math.random () * 2 | 0) + 1) - 1; console.log (this.data[randomNum].name + " " + this.data[randomNum].age); } } var cars = { data:[ {name:"Honda Accord", age:14}, {name:"Tesla Model S", age:2} ] } // Ta có thể cho phép cars mượn hàm showData () từ object use cars.showData = user.showData.bind (cars); cars.showData (); // Honda Accord 14
Với 2 công dụng phổ biến trên, hàm bind() được sử dụng khá linh hoạt, cho phép ta có thể dễ dàng "gắn" this vào một object và không cần phải lo lắng là this sẽ trỏ đến một object khác mỗi khi gọi.
Đây là 2 hàm khá phổ biến hay được sử dụng trong JavaScript. Hai hàm này nằm trong prototype của Function (Function.prototype), do đó chỉ function mới có thể gọi. Chúng có chung một chức năng lại: Gọi 1 function, xác định tham số this, truyền các tham số còn lại vào.
Điểm khác nhau là apply() truyền vào một array chứa toàn bộ các tham số, còn call() truyền lần lượt từng tham số. Hãy cùng tìm hiểu thông qua các ví dụ dưới đây để hiểu rõ hơn về công dụng của 2 hàm này.
Set this sử dụng call và apply
Giống như việc sử dụng bind(), chúng ta cũng có thể set được this bằng cách sử dụng apply() và call() với tham số đầu tiên trong 2 hàm này sẽ xác định object mà ta muốn set this trỏ đến khi gọi hàm. Hãy cùng xem ví dụ dưới đây
// khai báo một biến toàn cục var avgScore = "global avgScore"; // hàm tính trung bình của một mảng các điểm truyền vào function avg (arrayOfScores) { //Thêm điểm số vào mảng và trả về tổng điểm var sumOfScores = arrayOfScores.reduce (function (prev, cur, index, array) { return prev + cur; }); // Sử dụng "this" ở đây sẽ trỏ đến global object thay vì trỏ đến object mà ta mong muốn, // ta sẽ sử dụng apply và call để thực hiện hành động này this.avgScore = sumOfScores / arrayOfScores.length; } var gameController = { scores :[20, 34, 55, 46, 77], avgScore:null } // Nếu ta chạy function tính điểm trung bình trên thì this sẽ trỏ đến global object (window) do đó dẫn đến kết quả không mong muốn avg (gameController.scores); console.log (window.avgScore); // 46.4 console.log (gameController.avgScore); // null // reset biến global avgScore avgScore = "global avgScore"; // Để set this trỏ đến objct gameController, ta sẽ gọi hàm call() avg.call (gameController, gameController.scores); console.log (window.avgScore); //global avgScore // Lúc này this đã trỏ đúng đến object mong muốn do đó sẽ cho ra kết quả đúng console.log (gameController.avgScore); // 46.4
Sử dụng Call hoặc Apply để set this trong callback function
2 hàm call() và apply() có thể sử dụng trong các hàm callback function
// Định nghĩ một object với các thuộc tính và hàm // Sau đó ta sẽ truyền hàm như một callback function vào một hàm khác var clientData = { id: 094545, fullName: "Not Set", // setUserName is a method on the clientData object setUserName: function (firstName, lastName) { // this refers to the fullName property in this object this.fullName = firstName + " " + lastName; } }
function getUserInput (firstName, lastName, callback, callbackObj) { // Sử dụng apply để set "this" vào object callbackObj, tham số đầu tiên là object muốn set this trỏ vào, tham số thứ 2 là một mảng các tham số của hàm. callback.apply (callbackObj, [firstName, lastName]); }
Mượn hàm sử dụng apply và call
Cách sử dụng phổ biến nhất của apply và call đó là mượn hàm trong javascript. Ta sẽ thực hiện việc mượn function giống như cách thưc hiện với bind.
Mượn methods của Array
Hãy cùng xem xét ví dụ sau
var anArrayLikeObj = { 0:"Martin", 1:78, 2:67, 3:["Letta", "Marieta", "Pauline"], length:4 };
Tiếp theo nếu ta muốn mượn các hàm của Array ta sẽ thực hiện như sau
var newArray = Array.prototype.slice.call (anArrayLikeObj, 0); console.log (newArray); // ["Martin", 78, 67, Array[3]] // Search chữ "Martin" trong array sử dụng hàm call console.log (Array.prototype.indexOf.call (anArrayLikeObj, "Martin") === -1 ? false : true); // true // Sử dụng Array method không sử dụng call() hoặc apply() console.log (anArrayLikeObj.indexOf ("Martin") === -1 ? false : true); // Error: Object không có hàm 'indexOf' // Sử dụng call để dùng hàm reverse console.log (Array.prototype.reverse.call (anArrayLikeObj)); // {0: Array[3], 1: 67, 2: 78, 3: "Martin", length: 4} // Ta cũng có thể sử dụng hàm pop bằng cách sử dụng hàm call(): console.log (Array.prototype.pop.call (anArrayLikeObj)); console.log (anArrayLikeObj); // {0: Array[3], 1: 67, 2: 78, length: 3} // Và push console.log (Array.prototype.push.call (anArrayLikeObj, "Jackie")); console.log (anArrayLikeObj); // {0: Array[3], 1: 67, 2: 78, 3: "Jackie", length: 4}
Mượn hàm từ object khác
Ta cũng có thể mượn hàm từ object giống như cách thực hiện với ví dụ trên như hàm bind trên, hãy cùng xem ví dụ sau
var gameController = { scores :[20, 34, 55, 46, 77], avgScore:null, players :[ {name:"Tommy", playerID:987, age:23}, {name:"Pau", playerID:87, age:33} ] } var appController = { scores :[900, 845, 809, 950], avgScore:null, avg :function () { var sumOfScores = this.scores.reduce (function (prev, cur, index, array) { return prev + cur; }); this.avgScore = sumOfScores / this.scores.length; } } // Ta sử dụng hàm apply() như sau appController.avg.apply (gameController); console.log (gameController.avgScore); // 46.4 // appController.avgScore vẫn nhận giá trị null mà không được updated, chỉ có gameController.avgScore được update console.log (appController.avgScore); // null
Mở rộng chức năng của hàm sử dụng call và apply
var obj = { method: function() { console.log("This is method of obj"); } } // Sử dụng call để thêm log vào trước và sau hàm var obj = { method: function() { console.log("This is method of obj"); } } var oldFunction = obj.method; obj.method = function() { console.log("before function"); oldFunction.apply(this.arguments); console.log("after function"); } obj.method(); // before function // This is method of obj // after function
Trên đây là cách cách sử dụng phổ biến của 2 hàm apply và call, 2 hàm này còn các công dụng khác nhưng ở đây mình sẽ chỉ tìm hiểu cách hay sử dụng nhất.
Như vậy bài viết đã giúp tìm hiểu về 3 hàm rất quan trọng trong javascript - bind, call và apply. Cách sử dụng của chúng trong các trường hợp khác nhau. Hi vọng bài viết giúp ích cho mọi người, nếu có gì góp ý hay thảo luận xin hãy để lại bình luận phía dưới. (See you)