Hiểu về Higher-Order Functions trong Javascript
Giới thiệu
Hàm là một khối chứa code có tổ chức, được dùng để thực hiện một hành động có liên quan. Các hàm thường "lấy" dữ liệu, xử lý nó và "trả về" một kết quả. Khi một hàm được viết, nó có thể được sử dụng lặp đi lặp lại. Các hàm có thể được "gọi" từ bên trong của các hàm khác.. Điều này có nghĩa là chúng có thể được gán cho một biến và / hoặc được chuyển dưới dạng giá trị. Trong Javascript, hàm được xem như một "công dân hạng nhất" (first-class citizen) vì như đã biết Javascript là ngôn ngữ viết cho hướng sự kiện (event-base), do đó việc sử dụng hàm diễn ra rất thường xuyên, điều mà chúng ta có thể thay trong các dự án viết bằng ngôn ngữ này.
Phần kiến thức đơn lẻ này cho phép chúng ta viết lập trình hàm bằng ngôn ngữ này. Trong lập trình hàm, chúng ta sử dụng nhiều hàm bậc cao hơn.
Higher-Order function là gì?
Higher-order function là một hàm mà nó có thể gọi một hàm khác như là một tham số của nó (callback function) hoặc trả về các hàm dưới dạng kết quả của chúng.
Lấy một hàm khác làm đối số thường được gọi là hàm callback
function, vì nó được gọi lại bởi hàm bậc cao hơn. Đây là một khái niệm mà Javascript sử dụng rất nhiều.
Ví dụ, map
function trên mảng là một higher-order function. Hàm map
này nhận một hàm làm đối số và trả về một mảng mới sau khi tính toán đối số đó.
function add5(num){ return num + 5 ; } [1,2,3,4,5].map(add5) // [6,7,8,9,10]
Hoặc với một hàm ẩn danh (anonymous function):
[1,2,3,4,5].map(number => number + 5 );
map
function là một trong nhiều higher-order function được tích hợp sẵn trong ngôn ngữ. Ngoài ra, còn một số hàm khác như sort
, filter
, reduce
, forEach
cũng được sử dụng rất phổ biến trong JS.
Hàm higher-order function cho phép bạn viết mã đơn giản và clean hơn. Hãy xem đoạn mã trên sẽ trông như thế nào nếu không có sự trừu tượng như vậy. Hãy thay thế hàm bản đồ bằng một vòng lặp:
let arrNumber = [1,2,3,4,5] let newArray = [] for(let i = 0 ; i < arrNumber.length; i++){ newArray[i] = arrNumber[i] + 5 ; } newArray // [6,7,8,9,10]
The power of composition
function composition là một phép toán nhận hai hàm f và g và tạo ra một hàm h sao cho h (x) = g (f (x)). Trong phép toán này, hàm g được áp dụng cho kết quả của việc áp dụng hàm f cho x
Một trong những lợi thế lớn của việc sử dụng các higher-order function là chúng ta có thể là tách các chức năng trong hàm thành các function nhỏ để chúng xử lý độc lập với nhau thay vì để tất cả vào một hàm sẽ khiến bố cục trong hàm trở nên phức tạp và khó xử lý.
Kỹ thuật này giảm lỗi và làm cho code của chúng ta dễ đọc và dễ hiểu hơn, và dễ bảo trì, tái sử dụng nếu cần thiết.
Bằng cách học cách sử dụng các hàm bậc cao, bạn có thể bắt đầu viết mã tốt hơn.
Ví dụ
Xét thử một ví, giả sử bạn muốn mua một vài món đồ online thông qua một website thương maị điện tử, bạn cần phải đăng nhập hoặc đăng ký thành viên của trang web đó, lúc đó bạn mới có thể tiến hành đặt hàng và thanh toán :
function loginUser(email, password){ const user = { email, password } return user ; } function checkout(user){ let cart = [ { name : "milk", price : 2, quantity : 10 }, { name : "egg", price : 1, quantity : 20 }, { name : "salad", price : 5, quantity : 5 }, ] if(!user){ return; } return { cart, user } } const bill = (checkout) => { const {user, cart} = checkout ; const totalPrice = cart.reduce((accumulator, item) => item.price * item.quantity + accumulator, 0) return { email : user.email, totalPrice, detail : cart } } bill(checkout(loginUser("johndoe", "johndoe@email.com"))) //result { email: 'johndoe', totalPrice: 65, detail: [ { name: 'milk', price: 2, quantity: 10 }, { name: 'egg', price: 1, quantity: 20 }, { name: 'salad', price: 5, quantity: 5 } ] }
Từ các function trên, trước tiên tôi tạo một login
function để giúp người dùng có thể nhập email
, password
. Giả sử là người dùng lúc này đã đăng ký thành công tài khoản của website đó rồi.
Sau khi đăng nhập thành công, người dùng lựa chọn sản phẩm rồi cho vào giỏ hàng. Mỗi sản phẩm đều có tên, đơn giá và số lượng, đơn giá luôn cố định, còn số lượng người mua có thể tăng giảm theo ý muốn.
Xong bước này, người dùng nhấn vào nút Tiến hành thanh toán. Sau khi xác nhận thanh toán, người dùng sẽ nhận được thông tin đơn hàng bao gồm : email khách hàng, tổng tiền, chi tiết đơn hàng.
Quy trình này sử dụng Higher-order function, các hàm lồng trong nhau. Thay vì viết trong một hàm xuất hóa đơn từ bước phải đăng nhập, thì giờ đây, HOC đã giúp ta chia nhỏ function lớn thành các function con bên trong nó, mỗi function có nhiệm vụ riêng, và cưối cùng, chúng liên kết lại để có được kết quả cuối cùng như ta muốn.
Và bởi vì mỗi hàm chịu trách nhiệm cho một việc, nó làm cho code của chúng ta dễ phát hiện bug và test được dễ dàng hơn