🌞

Tìm hiểu Currying function trong Javascript

Sửa bài viết này

Currying function là một function có thể xử lý việc chúng ta truyền lắc nhắc từng tham số, thay vì truyền tất cả tham số cùng một lúc. Mỗi lần gọi function chúng ta lại truyền tiếp một tham số

Truyền cùng lúc

normal(a, b, c)

Truyền lắc nhắc

carrying(a)(b)(c)

Một function thông thường

function multiply(a, b, c) {
    return a * b * c;
}
multiply(1,2,3); // 6

Đây là phiên bản cà-ry của function multiply ở trên

function multiply(a) {
    return (b) => {
        return (c) => {
            return a * b * c
        }
    }
}

multiply(1)(2)(3) // 6

Bạn có thể chửi viết chi mà phức con mẹ nó tạp vậy, callback hell. Nhưng lợi ích của nó là giúp chúng ta gọi được hàm multiply theo kiểu multiply(1)(2)(3) thay vì multiply(1,2,3). Vẫn chưa thấy lợi ích? Viết tách ra cho dễ nhìn nè

const mul1 = multiply(1);
const mul2 = mul1(2);
const result = mul2(3);
// result : 6

Vẫn chưa thấy lợi ích luôn? Xem tiếp ví dụ để tính giảm giá theo hóa đơn

Currying function để làm gì?

Thí dụ bạn có một hàm để tính giá trị discount, giảm ngay 10% cho khách hàng thân thiết.

function discount(price, discount) {
    return price * discount
}
// Giảm ngay giảm 10% trên hóa đơn
const price = discount(500,0.10); // $50 
// $500  - $50 = $450

Khách hàng tiêu tiền điên cuồng, chúng ta gọi hàm này say mê

const price = discount(1500,0.10); // $150
// $1,500 - $150 = $1,350
const price = discount(2000,0.10); // $200
// $2,000 - $200 = $1,800
const price = discount(50,0.10); // $5
// $50 - $5 = $45
const price = discount(5000,0.10); // $500
// $5,000 - $500 = $4,500
const price = discount(300,0.10); // $30
// $300 - $30 = $270

Curry function sẽ giúp được gì trong tình huống này đây? Chúng ta vẫn cho phép truyền % discount và cho phép việc giá trị truyền này một lần thôi

function discount(discount) {
    return (price) => {
        return price * discount;
    }
}
const tenPercentDiscount = discount(0.1);
tenPercentDiscount(500); // $50
const twentyPercentDiscount = discount(0.2);
twentyPercentDiscount(500); // 100
// $500 - $100 = $400
twentyPercentDiscount(5000); // 1000
// $5,000 - $1,000 = $4,000
twentyPercentDiscount(1000000); // 200000
// $1,000,000 - $200,000 = $600,000

Khi cần truyền vào 1 argument ít thay đổi, cố định trong đa số các trường hợp, nghĩ đến carrying.

Chuyển bất cứ hàm nào thành hàm Currying

Chúng ta sẽ viết một cái hàm, nhiệm vụ của nó là biến một hàm bất kỳ và trả về một phiên bản currying của function đó.

function curry(fn, ...args) {
    return (..._arg) => {
        return fn(...args, ..._arg);
    }
}

Giải thích hàm này nha, hàm curry này nhận vào argument đầu tiên là một function, các argument tiếp theo sẽ là giá trị số. Sử dụng với hàm multiply ban đầu

function multiply(a, b, c) {
    return a * b * c;
}
// phiên bản currying
const multiplyCurrying = curry(multiply,2);
multiplyCurrying(4);
multiplyCurrying(6);

Hoặc dùng lodash.curry, lodash.curryRight nếu bàn thích sự hoàn hảo :D