Sử dụng hàm trong JavaScript sao cho hiệu quả
Sử dụng hàm trong JavaScript, là kỹ thuật hay dùng để giúp mã nguồn dễ đọc và có thể tái sử dụng lại. Nhưng để dùng hàm sao cho hợp lý và hiệu quả? Việc này đòi hỏi chúng ta cần phải có bức tranh tổng quát về hàm trong JavaScript. Ta sẽ cùng nhau tìm hiểu trong bài viết này nhé. Trong ngôn ngữ ...
Sử dụng hàm trong JavaScript, là kỹ thuật hay dùng để giúp mã nguồn dễ đọc và có thể tái sử dụng lại. Nhưng để dùng hàm sao cho hợp lý và hiệu quả? Việc này đòi hỏi chúng ta cần phải có bức tranh tổng quát về hàm trong JavaScript. Ta sẽ cùng nhau tìm hiểu trong bài viết này nhé.
Trong ngôn ngữ JavaScript, bạn hoàn toàn có thể khai báo một biến là hàm như thế này:
var myFunction = function (){ alert("hello CiOne"); }
Để gọi hàm myFunction thì cú pháp khá đơn giản như sau:
myFunction();
Xem kết quả tại đây
Nếu hàm có tham số, thì ta sẽ truyền tham số như thế nào? Bạn sẽ rất ngạc nhiên vì sự đơn giản của nó đấy nhé.
var myFunction = function (siteName){ alert("hello " + siteName); }
Để gọi hàm myFunction thì cú pháp khá đơn giản như sau:
myFunction("CiOne"); myFunction("Google");
Xem kết quả tại đây
Thử chạy đoạn mã trên, bạn sẽ thấy ngay thông báo hiện ra là: “hello CiOne” và “hello Google”.
Vì hàm cũng là một biến, nên ta có thể gán giá trị cho biến đó bằng một biến khác. Ví dụ:
myFunction = function (siteName){ alert("Welcome to "+ siteName); }
Bạn thấy ở đoạn mã trên, chúng ta đã thay hàm myFunction ban đầu, thành một hàm có nội dung khác. Việc này hoàn toàn có thể trong JavaScript.
Bởi vì hàm cũng là một biến, ta có thể truyền một hàm vào trong một hàm khác và gọi nó. Hãy xem đoạn mã sau nhé:
var messages=[]; var showMessage = function(message){ alert(message); messages.push(message); }
Trong đoạn mã trên, bạn thấy nhiệm vụ của hàm showMessage là hiển thị message, đồng thời ghi lại các message mà nó đã thông báo. Nếu chúng ta chỉ sử dụng hàm alert thôi, thì việc ghi lại các thông báo sẽ rất khó khăn. Bây giờ, chúng ta sẽ viết hàm để gửi một request lên server và khi nhận được kết quả từ server thì sẽ hiện thị message và ghi log lại. Tất nhiên, chúng ta sẽ sử dụng hàm showMessage để làm việc đó rồi. Nào, giờ hãy viết hàm gửi request nhé.
function sendRequest(handler) { var xhr = new XMLHttpRequest(); xhr.open("GET","http://ajax-json.cione.vn"); xhr.onreadystatechange=function(){ if(xhr.readyState === this.DONE){ handler(xhr.responseText); } } xhr.send(); }
Chạy thử kết quả tại đây
Ở đây mặc định các bạn biết XMLHttpRequest rồi nhé (Nếu các bạn chưa biết XMLHttpRequest là gì thì có thể tham khảo khoá AJAX & JSON) Như các bạn thấy ở đoạn mã trên, hàm sendRequest có 1 đối số chính là hàm handler. Hàm này có nhiệm vụ xử lý khi server trả về kết quả. Bây giờ, chúng ta muốn hàm showMessage sẽ nhận xử lý khi có kết quả làm thế nào? Có phải là chúng ta chỉ việc gọi hàm sendRequest với đối số đưa vào là hàm showMessage. Đoạn mã sẽ như sau:
sendRequest(showMessage);
Lúc này, bên trong hàm sendRequest sẽ không hề biết hàm showMessage, nó chỉ biết đối số handler là một hàm và nó sẽ gọi khi có kết quả mà thôi. Vậy, rõ ràng là showMessage là một hàm, nhưng ta đã truyền vào như là một tham số. Đây là một ưu điểm của JavaScript. Bạn cần lưu ý rằng, nếu chúng ta truyền null vào hàm sendRequest, thì sẽ có lỗi ngay, bởi vì chúng ta chưa kiểm tra điều kiện cho handler.
Chúng ta đã học trong khoá JavaScript đó là: kiểu trả về của một hàm là một biến. Trong bài viết này, bạn đã biết hàm cũng là một biến. Vậy rõ ràng là một hàm có thể có kiểu trả về là một hàm đúng không nào? Để minh hoạ cho trường hợp này, hãy xem một yêu cầu này nhé.
Viết một hàm, cho biết số lần hàm được gọi. Phải đảm bảo sao cho không có cách nào khác can thiệp để thay đổi số lần đã gọi.
Với yêu cầu chương trình như trên, chúng ta buộc phải đảm bảo biến đếm là một local variable. Có nghĩa là biến này chỉ được biết đến bên trong một hàm. Không có cách nào ở bên ngoài hàm có thể thay đổi biến này. Hãy xem mã nguồn sau nhé:
function getCounter(){ var counter = 0; var counterFunction = function (){ counter = counter + 1; console.log(counter); } return counterFunction; } var counter = getCounter(); counter(); // Giá trị in ra là 1. counter(); // Giá trị in ra là 2.
Chạy thử kết quả tại đây
Bạn thấy ở đoạn mã trên, mỗi lần hàm counter() được gọi là biến counter bên trong hàm getCounter được tăng lên 1 giá trị. Và chỉ có cách duy nhất để tăng biến đếm này là gọi hàm counter(). Bạn thấy thú vị chứ. Và bạn có để ý thấy đối số trả về của hàm getCounter là một hàm không?
Quá rõ ràng, là chúng ta có thể trả về kết quả của một function là một function như ví dụ trên.
Theo Wikipedia, một ngôn ngữ lập trình trong đó các kiểu dữ liệu có thể được truyền như đối số hàm hoặc là kết quả trả về từ một hàm hoặc có thể thay đổi hoặc gán bằng một biến khác, thì ta gọi nó ngôn ngữ thoả điều kiện First Class Citizen. Mặc dù thuật ngữ này cũng có nhiều bàn luận là gây khó hiểu và chẳng có tác dụng gì, nhưng vì nó vẫn được sử dụng nên chúng ta cũng nên biết thuật ngữ này để khỏi bỡ ngỡ.
Theo Wikipedia, Higher order functions là thuật ngữ ám chỉ đến một hàm, trong đó nó thoả mãn một trong các điều kiện sau:
- Nhận đối số là 1 hoặc nhiều hàm
- Có kiểu trả về là một hàm
Vậy đố các bạn, trong bài viết này, những hàm nào thoả mãn điều kiện của Higher Order Functions?
- Function as First Class Citizen
- About First Class, Second-Class and Third-Class