Hi 🤓 Cảm ơn bạn đã ghé thăm blog này, nếu những bài viết trên blog giúp ích cho bạn. Bạn có thể giúp blog hiển thị quảng cáo bằng cách tạm ngừng ad blocker 😫 và để giúp blog duy trì hoạt động nếu bạn muốn.
Cảm ơn bạn!

các hàm trong JavaScript là các đoạn mã có thể tái sử dụng để thực hiện một số bài toán. Các đối số của function là input và giá trị trả về là output.

Đây là một function đơn giản tính tổng một mảng số:

function sum(numbers) {
  let sum = 0;
  numbers.forEach(number => sum += number);

  return sum;
}

sum([1, 2, 3]); // 6

Ở ví dụ trên, các chữ số là input, hàm sum() sẽ tính tổng các số này và trả về tổng - ouput.

Giả sử đề bài yêu cầu, xây dựng một hàm tổng quát hỗ trợ các phép toán như: cộng, trừ, nhân, chia. Chúng ta sẽ làm nó thế nào?

Để xây dựng hàm tổng quát như đề bài yêu cầu, chúng ta sẽ tìm hiểu về Higher order functions nhé.

Higher order functions

Như chúng ta đã biết trong JavaScript, các function có thể sử dụng primitive types như số, chuỗi, các object như array, plain objects,... làm đối số và trả về primitive type hoặc object.

Ở ví dụ trên, hàm sum([1, 2, 3]) nhận một array làm đối số và trả về kết quả là một primitive type.

Vậy câu hỏi đưa ra là có thể sử dụng các function làm đối số hay làm cho function return về một function không? câu trả lời là có 😁

Gán function cho biến

Để gán các function cho biến chúng ta làm như sau:

const sayHi = function() { 
  return 'hi! 🥴' ;
};
sayHi(); // kết quả: hi!

Sử dụng function làm đối số

Để sử dụng function làm đối số cho function khác chúng ta cũng truyền vào function như cách thông thường:

function sayHi(f) {
  return f(); // thực thi hàm được truyền vào và return về kết quả từ function f.
}
sayHi(function() { return 'hi!' }); // => 'hi!'

Return function từ function

function sayHi() {
  return function() { return 'hi!'; };
}
const result = sayHi();
result(); // => hi!

Hàm sayHi() sẽ return về một function. Để thực thi sayHi chúng ta cần sử dụng cặp dấu ().

Kết quả từ sayHi() là một function, function này sẽ được gán vào biến result, Cuối cùng thực thi function này bằng cách gọi result().

Các bạn đã phần nào hiểu về Higher order functions chưa nhỉ? tóm lại, Các hàm sử dụng các hàm khác làm đối số hoặc hàm trả về được gọi là Higher order functions. 😁

Các hàm chỉ sử dụng primitives hay objects làm đối số và chỉ trả về primitives hay objects, chúng được gọi là first-order functions.

hàm sayHi() return về một function nên nó là Higher order functions, còn hàm sum() return về một primitives nên là first-order functions.

Vì vậy, trong JavaScript, một hàm có thể là first-order hoặc higher-order.

Higher order functions in practice

Ở ví dụ đầu tiên, chúng ta có bài toán: xây dựng một hàm tổng quát hỗ trợ các phép toán. Vậy chúng ta sẽ giải quyết như thế nào? Câu trả lời là chúng ta sẽ sử dụng higher order function.

Chúng ta sẽ làm như sau:

function calculate(operation, initialValue, numbers) {
  let total = initialValue;

  numbers.forEach(num => {
  	total = operation(total, num);  
  });

  return total;
}

function sum(n1, n2) {
  return n1 + n2;
}

function multiply(n1, n2) {
  return n1 * n2;
}

calculate(sum, 0, [1, 2, 4]); // 7
calculate(multiply, 1, [1, 2, 4]);  // 8

hàm calculate nhận vào 3 đối số:

  1. operation: là function để tính toán và trả về kết quả, ở đây sum()multiply() được truyền vào.
  2. initialValue: giá trị khởi tạo của phép tính.
  3. numbers: mảng các số cần tính toán.

Từ đoạn code trên ta có thể thấy: calculate(operation, initialValue, numbers) là một higher-order function vì nó nhận function làm đối số đầu tiên của hàm.

Ngoài ra, trong calculate(sum, 0, [1, 2, 3, 4]), đối số đầu tiên còn được gọi là callback function (hàm gọi lại). Chúng ta có thể nói một Higher order functions chấp nhận hoặc trả về các callback function.

Nếu các bạn để ý thì trong các hàm tích hợp của Javascript như map, forEach, DOM method, promise method chúng có sử dụng Higher order functions.

arr.map(func) là một Higher order functions vì nó nhận func là một function làm đối số.

const numbers = [-1, 2, -4];
const positiveNumbers = numbers.map(function positiveNumbers(number) {
  return Math.abs(number);
});
positiveNumbers; // [1, 2, 4]

element.addEventListener(type, func) chúng ta thường dùng cũng là một Higher order functions vì nó chấp nhận một function làm đối số thứ hai:

document
  .getElementById('#button')
  .addEventListener('click', function showMore() {
    // ...
  });

Lợi ích mà Higher order functions đem lại

Ở ví dụ trên, khi sử dụng Higher order functions, chúng ta có thể reuse hàm calculate() để thực hiện các phép tính toán.

Ngoài ra, ta còn có thể kết hợp các function nhằm thực hiện một hoạt động có nhiều bước hay các bài toán yêu cầu nhiều phép tính,...

Ví dụ, sử dụng Higher order functions để tính tổng giữa phép tính sum() với multiply(), hoặc sử dụng kết quả của calculate()multiply() để tính tổng ^^.

Nhờ khả năng kết hợp giữa các function thông qua Higher order functions mà chúng được sử dụng trong functional programming.

Các bạn có thể đọc thêm về bài viết: Compose và Pipe trong Javascript là gì? những lợi ích mà nó mang lại cho lập trình viên

Kết luận

Như vậy là chúng ta đã tìm hiểu về Higher order functions trong javascript. Đây là một nội dung khá thú vị đúng không nào. Hi vọng bài viết sẽ giúp ích cho các bạn.

Bài viết này mình tham khảo tại: What are Higher-Order Functions in JavaScript?.

Chúc các bạn học tốt ^^.

Có thể bạn thích ⚡
homiedev
About Me

Hi, I'm @devnav. Một người thích chia sẻ kiến thức, đặc biệt là về Frontend 🚀. Trang web này được tạo ra nhằm giúp các bạn học Frontend hiệu quả hơn 🎉😄.

Chúc các bạn tìm được kiến thức hữu ích trong blog này 😁😁.