Khám phá currying trong JavaScript: từ lý thuyết đến ứng dụng thực tế
Bạn đã bao giờ bắt gặp thuật ngữ "Currying" trong JavaScript và tự hỏi ý nghĩa của nó? Bài viết này sẽ giải thích khái niệm Currying bằng các ví dụ đơn giản, dễ hiểu và minh họa ứng dụng thực tế của nó trong việc tối ưu code.
Currying là gì?
Currying là một phương pháp lập trình hàm, trong đó một hàm sử dụng từng đối số của nó một cách riêng biệt, thay vì cùng một lúc. Một hàm Curried sẽ trả về một hàm khác, hàm này chấp nhận tham số tiếp theo cho đến khi tất cả các đối số đã được cung cấp. Nói một cách đơn giản, Currying chuyển đổi một hàm có nhiều đối số thành một chuỗi các hàm, mỗi hàm nhận một đối số.
Chúng ta hãy cùng tìm hiểu Currying thông qua một ví dụ thực tế và code minh họa.
Ví dụ về làm một chiếc bánh mì kẹp thịt
Hãy nghĩ đến việc gọi một chiếc bánh mì kẹp thịt tại một quán ăn nhanh. Một đầu bếp sẽ chuẩn bị bánh mì kẹp thịt của bạn theo từng lớp:
- Lớp 1: Bánh mì (đối số đầu tiên).
- Lớp 2: Miếng thịt (đối số thứ hai).
- Lớp 3: Lớp phủ (đối số thứ ba).
Chúng ta hãy viết code cho kịch bản trên bằng cách sử dụng Hàm thông thường và Hàm Curried.
1. Sử dụng Hàm thông thường:
Trong một hàm thông thường, tất cả các thành phần được truyền cùng một lúc dưới dạng đối số.
function makeBurger(bun, patty, topping) {
return `Your burger has: ${bun} bun, ${patty} patty, and ${topping} topping.`;
}
const myBurger = makeBurger("Sesame", "Mix Veg", "Cheese");
console.log(myBurger); // Output: Your burger has: Sesame bun, Mix Veg patty, and Cheese topping.
2. Sử dụng Hàm Curried:
Trong một hàm Curried, bạn truyền từng thành phần một.
function makeBurgerCurried(bun) {
return function (patty) {
return function (topping) {
return `Your burger has: ${bun} bun, ${patty} patty, and ${topping} topping.`;
};
};
}
// Example usage
const chooseBun = makeBurgerCurried("Sesame");
const choosePatty = chooseBun("Mix Veg");
const myCurriedBurger = choosePatty("Cheese");
console.log(myCurriedBurger); // Output: Your burger has: Sesame bun, Mix Veg patty, and Cheese topping.
3. Giải thích:
Lần gọi thứ nhất: makeBurgerCurried("Sesame")
nhận "Sesame"
và trả về một hàm mới, hàm này chờ nhận patty.
const chooseBun = makeBurgerCurried("Sesame");
console.log(chooseBun);
/* Output:
ƒ (patty) {
return function (topping) {
return `Your burger has: ${bun} bun, ${patty} patty, and ${topping} topping.`;
};
} */
Lần gọi thứ hai: chooseBun("Mix Veg")
nhận "Mix Veg"
và trả về một hàm khác, hàm này chờ nhận topping.
const choosePatty = chooseBun("Mix Veg");
console.log(choosePatty);
/* Output:
ƒ (topping) {
return `Your burger has: ${bun} bun, ${patty} patty, and ${topping} topping.`;
} */
Lần gọi thứ ba: choosePatty("Cheese")
nhận "Cheese"
và hoàn thành chuỗi hàm, trả về mô tả burger cuối cùng.
const myCurriedBurger = choosePatty("Cheese");
console.log(myCurriedBurger);
// Output: Your burger has: Sesame bun, Mix Veg patty, and Cheese topping.
Hàm mũi tên rút gọn cho Currying
Bạn có thể rút gọn hàm Curried bằng cách sử dụng hàm mũi tên:
const curriedArrowFunction = (bun) => (patty) => (topping) =>
`Your burger has: ${bun} bun, ${patty} patty, and ${topping} topping`
const myArrowFunction = curriedArrowFunction("Sesame")("Mix Veg")("Cheese")
console.log(myArrowFunction); // Your burger has: Sesame bun, Mix Veg patty, and Cheese topping
Tại sao nên sử dụng Currying?
Currying đặc biệt hữu ích khi bạn cần tái sử dụng một hàm với các đối số cụ thể. Nó thúc đẩy việc tái sử dụng code, khả năng đọc và tính module.
Ứng dụng Thực tế: Máy tính Giảm giá
Hãy tưởng tượng bạn đang phát triển một nền tảng thương mại điện tử. Việc giảm giá được tính theo loại khách hàng:
- Khách hàng thông thường được giảm 10%.
- Khách hàng Premium được giảm 20%.
Đầu tiên, hãy xây dựng ứng dụng này bằng hàm thông thường:
1. Sử dụng Hàm thông thường:
Sử dụng hàm thông thường cho máy tính giảm giá có thể dẫn đến code kém linh hoạt và khó tái sử dụng. Bạn sẽ phải viết các hàm riêng biệt cho từng loại khách hàng hoặc truyền tất cả các tham số mỗi khi tính toán giảm giá.
function calculateDiscount(customerType, price) {
if (customerType === "Regular") {
return price * 0.9; // 10% discount
} else if (customerType === "Premium") {
return price * 0.8; // 20% discount
}
}
console.log(calculateDiscount("Regular", 100)); // Output: 90
console.log(calculateDiscount("Premium", 100)); // Output: 80
Hạn chế của Hàm thông thường:
- Logic lặp lại: Bạn phải truyền customerType mỗi lần, ngay cả khi nó không thay đổi trong nhiều phép tính.
- Không tái sử dụng được: Nếu bạn muốn áp dụng giảm giá cho một loại khách hàng trên nhiều giao dịch, bạn phải chỉ định loại mỗi lần.
- Vấn đề khả năng mở rộng: Việc thêm các loại khách hàng hoặc quy tắc giảm giá bổ sung sẽ làm phức tạp hàm và khiến việc bảo trì trở nên khó khăn hơn.
Bây giờ, hãy xây dựng ứng dụng này bằng hàm Curried:
2. Sử dụng Hàm Curried:
Currying cho phép bạn tạo các hàm có thể tái sử dụng cho các loại khách hàng khác nhau. Thay vì liên tục cung cấp các tham số giống nhau, bạn có thể định cấu hình logic giảm giá cho từng loại khách hàng.
function createDiscountCalculator(discountRate) {
return function (price) {
return price * (1 - discountRate);
};
}
// Create specific calculators for different customer types
const regularDiscount = createDiscountCalculator(0.1); // 10% discount
const premiumDiscount = createDiscountCalculator(0.2); // 20% discount
// Use them for calculations
console.log(regularDiscount(100)); // Output: 90
console.log(premiumDiscount(100)); // Output: 80
console.log(regularDiscount(200)); // Output: 180
Ưu điểm của Hàm Curried:
- Tái sử dụng: Khi regularDiscount hoặc premiumDiscount đã được chỉ định, bạn sẽ không cần chỉ định tỷ lệ chiết khấu một lần nữa cho các giao dịch tiếp theo.
- Code sạch hơn: Logic được tách biệt và tập trung. Mỗi hàm có một trách nhiệm duy nhất: xác định và áp dụng tỷ lệ chiết khấu.
- Khả năng mở Rộng: Việc tạo các loại khách hàng mới rất đơn giản. Ví dụ:
const studentDiscount = createDiscountCalculator(0.15); // 15% discount
console.log(studentDiscount(100)); // 85
- Khả năng đọc được cải thiện: Code thể hiện rõ ràng mục đích của nó. Hàm regularDiscount chỉ định logic giảm giá cho khách hàng thông thường.
Kết luận
Currying thoạt nhìn có vẻ phức tạp nhưng như chúng ta đã thấy, nó là một khái niệm mạnh mẽ để đơn giản hóa việc tạo hàm và làm cho code của bạn rõ ràng hơn và có thể tái sử dụng hơn. Bây giờ bạn đã hiểu rõ về nó, hãy thử áp dụng Currying trong dự án tiếp theo của bạn và xem điều kỳ diệu xảy ra!
All Rights Reserved