Trong lập trình hàm, mẫu currying là một cách để viết các hàm sao cho các đối số của chúng có thể được áp dụng một phần. Điều này có nghĩa là bạn có thể tạo một hàm mới bằng cách cung cấp một số, nhưng không phải tất cả, các đối số mà hàm ban đầu mong đợi. Điều này giúp tạo ra các chức năng cụ thể hơn có thể được sử dụng lại trong các phần khác nhau của mã của bạn.
Cà ri là gì?
Currying là quá trình chuyển đổi một hàm mong đợi nhiều đối số thành một chuỗi các hàm, mỗi hàm chỉ mong đợi một đối số. Chẳng hạn, xét hàm Hàm này cộng hai số với nhau.
1 2 3 4 | <span class="token keyword">function</span> <span class="token function">add</span> <span class="token punctuation">(</span> <span class="token parameter">x <span class="token punctuation">,</span> y</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> x <span class="token operator">+</span> y <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Để xử lý hàm này, hãy viết một hàm mới nhận đối số đầu tiên x
và yêu cầu nó trả về một hàm mới mong đợi đối số thứ hai y
. Bạn có thể làm điều đó như thế này.
1 2 3 4 5 6 | <span class="token keyword">function</span> <span class="token function">add</span> <span class="token punctuation">(</span> <span class="token parameter">x</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">y</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> x <span class="token operator">+</span> y <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Bây giờ, thay vì gọi add(x, y)
, chúng ta có thể gọi add(x)(y)
. Điều này có vẻ giống như một thay đổi nhỏ, nhưng nó cho phép bạn thực hiện một số điều thú vị.
Lợi ích của cà ri
Sử dụng mô hình cà ri có một số lợi thế.
1. Chức năng tái sử dụng
Một trong những lợi ích chính của currying là nó cho phép bạn tạo các chức năng cụ thể hơn có thể được sử dụng lại trong các phần khác nhau của mã của bạn. Chẳng hạn, xét hàm Hàm này nhân một số với 10.
1 2 3 4 | <span class="token keyword">function</span> <span class="token function">multiplyBy10</span> <span class="token punctuation">(</span> <span class="token parameter">x</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> x <span class="token operator">*</span> <span class="token number">10</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Hàm này chuyên dùng để nhân với 10 và không thể nhân với các số khác. Tuy nhiên, bằng cách tính hàm này, chúng ta có thể tạo một hàm tổng quát hơn có thể nhân bất kỳ số nào.
1 2 3 4 5 6 7 8 9 | <span class="token keyword">function</span> <span class="token function">multiply</span> <span class="token punctuation">(</span> <span class="token parameter">x</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">y</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> x <span class="token operator">*</span> y <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> multiplyBy10 <span class="token operator">=</span> <span class="token function">multiply</span> <span class="token punctuation">(</span> <span class="token number">10</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> multiplyBy5 <span class="token operator">=</span> <span class="token function">multiply</span> <span class="token punctuation">(</span> <span class="token number">5</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Ở trạng thái này, chúng ta có hai hàm cụ thể, multiplyBy10
multiplyBy5
, mà chúng ta có thể sử dụng lại trong toàn bộ mã của mình.
2. Khả năng kết hợp
Một lợi ích khác của currying là bạn có thể dễ dàng kết hợp các chức năng mới từ các chức năng hiện có. Ví dụ, xét một hàm cộng và nhân các số như sau:
1 2 3 4 5 6 7 8 | <span class="token keyword">function</span> <span class="token function">add</span> <span class="token punctuation">(</span> <span class="token parameter">x <span class="token punctuation">,</span> y</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> x <span class="token operator">+</span> y <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">multiply</span> <span class="token punctuation">(</span> <span class="token parameter">x <span class="token punctuation">,</span> y</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> x <span class="token operator">*</span> y <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Currying có thể được sử dụng để tạo một hàm mới nhân hai số và thêm số thứ ba vào kết quả.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">function</span> <span class="token function">add</span> <span class="token punctuation">(</span> <span class="token parameter">x</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">y</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> x <span class="token operator">+</span> y <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">multiply</span> <span class="token punctuation">(</span> <span class="token parameter">x</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">y</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> x <span class="token operator">*</span> y <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> <span class="token function-variable function">multiplyAndAdd</span> <span class="token operator">=</span> <span class="token parameter">x</span> <span class="token operator">=></span> <span class="token parameter">y</span> <span class="token operator">=></span> <span class="token parameter">z</span> <span class="token operator">=></span> <span class="token function">add</span> <span class="token punctuation">(</span> <span class="token function">multiply</span> <span class="token punctuation">(</span> x <span class="token punctuation">)</span> <span class="token punctuation">(</span> y <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">(</span> z <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Bây giờ để thực hiện phép tính (2 * 3) + 4
, bạn có thể gọi multiplyAndAdd(2)(3)(4)
.
Ví dụ thực tế về cà ri trong JavaScript
Bây giờ chúng ta đã học được những kiến thức cơ bản về currying và lợi ích của nó, hãy xem xét một số ví dụ thực tế về cách sử dụng mẫu này trong mã JavaScript.
1. Ứng dụng một phần chức năng
Một cách sử dụng phổ biến của currying là tạo một hàm mới với một số đối số được điền sẵn. Điều này được gọi là ứng dụng chức năng một phần.
Chẳng hạn, xét hàm Hàm này tính toán tổng số tiền bao gồm thuế.
1 2 3 4 | <span class="token keyword">function</span> <span class="token function">calculateTotal</span> <span class="token punctuation">(</span> <span class="token parameter">price <span class="token punctuation">,</span> taxRate</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> price <span class="token operator">+</span> <span class="token punctuation">(</span> price <span class="token operator">*</span> taxRate <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Nếu bạn muốn tạo một hàm mới để tính toán tổng chi phí của một đơn đặt hàng ở một mức thuế nhất định, bạn có thể thực hiện việc này bằng cách sử dụng currying.
1 2 3 4 5 6 7 8 | <span class="token keyword">function</span> <span class="token function">calculateTotal</span> <span class="token punctuation">(</span> <span class="token parameter">price</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">taxRate</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> price <span class="token operator">+</span> <span class="token punctuation">(</span> price <span class="token operator">*</span> taxRate <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> calculateTotalWithTax <span class="token operator">=</span> <span class="token function">calculateTotal</span> <span class="token punctuation">(</span> <span class="token number">0.08</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Hiện tại, để biết tổng chi phí của một đơn đặt hàng có giá $100
và thuế suất là 8%
, bạn có thể gọi hàm calculateTotalWithTax(100)
.
2. Tạo hàm bậc cao
Một cách sử dụng phổ biến của currying là tạo các hàm bậc cao hơn, là các hàm lấy các hàm khác làm đối số hoặc trả về chúng dưới dạng đầu ra.
Chẳng hạn, xét hàm Hàm này nhận một mảng số và một hàm gọi lại, đồng thời trả về một mảng mới với hàm gọi lại được áp dụng cho từng phần tử.
1 2 3 4 5 6 7 8 | <span class="token keyword">function</span> <span class="token function">map</span> <span class="token punctuation">(</span> <span class="token parameter">array <span class="token punctuation">,</span> callback</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> newArray <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span> <span class="token keyword">const</span> element <span class="token keyword">of</span> array <span class="token punctuation">)</span> <span class="token punctuation">{</span> newArray <span class="token punctuation">.</span> <span class="token function">push</span> <span class="token punctuation">(</span> <span class="token function">callback</span> <span class="token punctuation">(</span> element <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> newArray <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Currying có thể được sử dụng để tạo các hàm mới với các đối số gọi lại được điền sẵn.
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">function</span> <span class="token function">map</span> <span class="token punctuation">(</span> <span class="token parameter">callback</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">array</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> newArray <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span> <span class="token keyword">const</span> element <span class="token keyword">of</span> array <span class="token punctuation">)</span> <span class="token punctuation">{</span> newArray <span class="token punctuation">.</span> <span class="token function">push</span> <span class="token punctuation">(</span> <span class="token function">callback</span> <span class="token punctuation">(</span> element <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> newArray <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> mapWithMultiplyBy2 <span class="token operator">=</span> <span class="token function">map</span> <span class="token punctuation">(</span> <span class="token parameter">x</span> <span class="token operator">=></span> x <span class="token operator">*</span> <span class="token number">2</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Bây giờ bạn có thể lấy mảng [2, 4, 6]
bằng cách gọi mapWithMultiplyBy2([1, 2, 3])
.
3. Tạo trình xử lý sự kiện
Currying cũng có thể hữu ích để tạo trình xử lý sự kiện trong React và các thư viện JavaScript khác.
Chẳng hạn, xét hàm Hàm này xử lý sự kiện nhấp chuột của nút.
1 2 3 4 5 | <span class="token keyword">function</span> <span class="token function">handleClick</span> <span class="token punctuation">(</span> <span class="token parameter">event <span class="token punctuation">,</span> id <span class="token punctuation">,</span> name</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token template-string"><span class="token template-punctuation string">`</span> <span class="token string">Button </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> id <span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> with name </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> name <span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> was clicked!</span> <span class="token template-punctuation string">`</span></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// Do something with `event`</span> <span class="token punctuation">}</span> |
Currying có thể được sử dụng để tạo một hàm mới với các đối số id
và name
được điền sẵn.
1 2 3 4 5 6 7 8 9 | <span class="token keyword">function</span> <span class="token function">handleClick</span> <span class="token punctuation">(</span> <span class="token parameter">id <span class="token punctuation">,</span> name</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">event</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token template-string"><span class="token template-punctuation string">`</span> <span class="token string">Button </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> id <span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> with name </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> name <span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> was clicked!</span> <span class="token template-punctuation string">`</span></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// Do something with `event`</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> handleClickWithIdAndName <span class="token operator">=</span> <span class="token function">handleClick</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">,</span> <span class="token string">'Submit Button'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
handleClickWithIdAndName
cho thuộc tính onClick
hiện đảm bảo rằng thông báo thích hợp được ghi lại khi nhấp vào nút.
4. Tạo trình vòng lặp tùy chỉnh
Currying cũng có thể hữu ích trong việc tạo các trình vòng lặp tùy chỉnh trong JavaScript.
Chẳng hạn, xét hàm Hàm này lặp qua một mảng số và trả về tổng.
1 2 3 4 5 6 7 8 | <span class="token keyword">function</span> <span class="token function">sum</span> <span class="token punctuation">(</span> <span class="token parameter">array</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> total <span class="token operator">=</span> <span class="token number">0</span> <span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span> <span class="token keyword">const</span> element <span class="token keyword">of</span> array <span class="token punctuation">)</span> <span class="token punctuation">{</span> total <span class="token operator">+=</span> element <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> total <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Currying có thể được sử dụng để tạo một hàm mới lặp lại trên một mảng và áp dụng hàm gọi lại cho từng phần tử.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">function</span> <span class="token function">iterate</span> <span class="token punctuation">(</span> <span class="token parameter">callback</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">array</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> total <span class="token operator">=</span> <span class="token number">0</span> <span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span> <span class="token keyword">const</span> element <span class="token keyword">of</span> array <span class="token punctuation">)</span> <span class="token punctuation">{</span> total <span class="token operator">+=</span> <span class="token function">callback</span> <span class="token punctuation">(</span> element <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> total <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> sum <span class="token operator">=</span> <span class="token function">iterate</span> <span class="token punctuation">(</span> <span class="token parameter">x</span> <span class="token operator">=></span> x <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">'sum([1,2,3])'</span> <span class="token punctuation">,</span> <span class="token function">sum</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token number">1</span> <span class="token punctuation">,</span> <span class="token number">2</span> <span class="token punctuation">,</span> <span class="token number">3</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token comment">// 9</span> |
Hiện tại bạn có thể lấy tổng của mảng [2, 3, 4]
bằng cách gọi sum([1, 2, 3])
.
Phần kết luận
Trong bài viết này, chúng ta đã tìm hiểu cách sử dụng mẫu currying trong JavaScript để tạo các hàm cụ thể hơn và có thể tái sử dụng, đồng thời cải thiện tính giao hoán và khả năng đọc của mã. Chúng ta cũng đã thấy một số ví dụ thực tế về cách áp dụng mô hình này trong các tình huống thực tế. Currying có thể mất một chút thời gian để tìm hiểu, nhưng nó có thể là một công cụ mạnh mẽ trong quy trình lập trình chức năng của bạn.
Như mọi khi, tôi hy vọng bạn thích bài viết này và học được điều gì đó mới.
Cảm ơn rất nhiều. Hẹn gặp lại các bạn trong bài viết tiếp theo!
Nếu các bạn thích bài viết này, hãy ủng hộ chúng tôi bằng cách like và subscribe. Cảm ơn.