Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> JavaScript

Higher Order Functions trong JavaScript: Hướng dẫn toàn tập

Là nhà phát triển, bạn chắc đã dùng hàm JavaScript thông thường. Gọi là first order functions (hàm bậc nhất), chúng không nhận hàm làm tham số cũng không trả về hàm.

function hello(name) {
  return "Hello," + " " + name
}
console.log(hello("Career Karma")); // Hello, Career Karma

Bài viết này nói về Higher Order Functions (HOF - Hàm bậc cao). Đây là hàm giúp developer rút gọn code, dễ đọc hơn bằng cách nhận hàm làm đối số hoặc trả về hàm. Ta sẽ xem qua ví dụ cơ bản giới thiệu HOF và lập trình hàm (functional programming), và nói về hai phương thức mảng nâng cao phổ biến dùng cấu trúc HOF để hoạt động.

Ví dụ cơ bản Higher Order Functions

Có vài cách dùng Higher Order Functions trong JavaScript.

Máy tính (Calculator)

Bắt đầu với HOF cơ bản nhận hàm callback làm đối số và trả về callback đó với vài đối số:

// higher order function
function higherOrderFunction(num1, num2, cb) {
  return cb(num1, num2); // gọi cb function và truyền đối số vào callback
}

// callbacks
function add(num1, num2) { return num1 + num2; }
function multiply(num1, num2) { return num1 * num2; }
function divide(num1, num2) { return num1/num2; }
function subtract(num1, num2) { return num1 - num2; }
function modulo(num1, num2) { return num1 % num2; }

console.log(higherOrderFunction(43, 13, add));

Ở đây có hai loại hàm: higher order function trả về callback, và tập first order function thực hiện phép toán trên hai số. Cuối snippet, gọi higherOrderFunction(). Hàm này trả về kết quả gọi cb được truyền vào với tham số cho trước. Nếu viết callback cho tất cả phép toán số học, có thể dùng higherOrderFunction gọi phép toán cần thiết.

Event Listener (Trình lắng nghe sự kiện)

Ví dụ khác của higher order function là khi gắn event listener cho phần tử trên DOM (document object model). Ví dụ:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title></title>
  <meta name="description" content="">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="">
</head>
<body>
  <button>Nhấn vào đây!</button>
  <script async defer>
    const button = document.querySelector("button");
    button.addEventListener("click", (e) => {
      alert("Nút đã được nhấn!");
    })
  </script>
</body>
</html>

Trong ví dụ này, ta tạo nút trong HTML, chọn nó bằng JavaScript, gắn event listener. Cấu trúc event listener là higher order function đơn giản – nhận hàm nặc danh làm đối số thứ hai.

Higher Order Functions trong JavaScript: Hướng dẫn toàn tập
Phần highlighted là higher order function của bạn

Phương thức mảng nâng cao (Advanced Array Methods)

JavaScript Built-In Array Methods là những higher order functions đặc biệt mới trong ES6 dùng để lặp qua mảng và thao tác nó hoặc trả về mảng hoàn toàn mới với giá trị đã thao tác.

Khi bắt đầu giải quyết vấn đề phức tạp hơn trong JavaScript, hãy tư duy về trừu tượng hóa logic khi lặp mảng. Dùng các higher order function array methods giúp bạn trở thành JS developer tốt hơn.

Giả sử có mảng giảng viên:

Higher Order Functions trong JavaScript: Hướng dẫn toàn tập
Mảng giảng viên mẫu

forEach

Muốn lặp mảng và thao tác từng mục trước ES6, code như sau:

function forEachES5(arr){
  for(let i = 0; i < arr.length; i++) {
    arr[i] = "Giảng viên " + arr[i];
  }
  return arr;
}
console.log(forEachES5(professors));

Cú pháp ES6 cho phép rút gọn code bằng phương thức forEach:

function forEachES6(arr) {
  arr.forEach((professor, index, origArr) => {
    origArr[index] = "Giảng viên " + professor;
  });
  return arr;
}

Phương thức forEach nhận hàm callback làm tham số đầu tiên khiến nó thành higher order function. Callback này cơ bản là "hành động" thực hiện trên từng mục trong mảng. Ngoài ra, forEach cũng nhận index và mảng làm tham số tùy chọn thứ hai và thứ ba.

Thứ tự tham số quan trọng trong forEach (cũng như các built-in array methods khác). Thứ nhất luôn là callback, thứ hai luôn là index, thứ ba luôn là bản sao mảng gốc.

forEach là cách khác trình diễn vòng lặp for trong JavaScript. Nó không trả về gì. Phương thức thao tác thứ đã có và lưu vào mảng bạn đang làm việc nếu chỉ định hành động.

Map

Phương thức gần forEach nhất là map. Hoạt động rất giống, trừ việc method này trả về mảng mới. Mọi thứ thao tác trong callback sẽ không ảnh hưởng mảng gốc.

Xem map trông như thế nào pre-ES6:

function mapES5(arr){
  let newArr = [];
  for(let i = 0; i < arr.length; i++) {
    newArr.push("Giảng viên " + arr[i]);
  }
  return newArr;
}

Trước đây phải khởi tạo mảng mới ngoài for loop để push giá trị mới. Sau đó phải return mảng mới mới dùng được!

Với ES6 và map method, có thể trừu tượng hóa logic để dễ đọc hơn:

function mapWithES6(arr) {
  const mapped = arr.map(professor => {
    return "Giảng viên " + professor;
  })
  return mapped;
}

Đặc điểm của map method (cũng như reduce, filter) là có thể gán cho biến và return hoặc return toàn bộ function! Không cần push vào mảng mới – map method làm giúp bạn. Nhớ có giá trị return trong logic bên trong callback của map method!

Kết luận

Higher Order Functions là khái niệm cực kỳ quan trọng trong JavaScript giúp bạn trở thành developer tốt hơn. Nó giúp trừu tượng hóa logic khiến code dễ đọc hơn, và trong một số trường hợp, hiệu năng hơn.

Trong tutorial này, ta khám phá các cách viết Higher Order Functions, từ phương thức máy tính cơ bản đến event listeners và advanced array functions. Khi đã thành thạo, bạn sẵn sàng giải quyết các bài toán phức tạp hơn!