Currying
Currying means evaluating functions with multiple arguments and splitting them into a sequence of functions with a single argument. So instead of taking all arguments at once, the function takes the first argument and returns a new function, which takes the second argument and returns a new function, which takes the third argument … and so on until all arguments are provided and the final function is executed
.
Currying helps you break down functions into smaller reusable functions to handle a single task. This makes your functions purer, less error prone, and easier to test.
Simple Currying Example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <span class="token comment">// Hàm transaction để xử lý giao dịch ngân hàng</span> <span class="token keyword">const</span> <span class="token function-variable function">transaction</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token parameter">fee <span class="token punctuation">,</span> balance <span class="token punctuation">,</span> amount</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> balance <span class="token operator">+</span> amout <span class="token operator">-</span> fee <span class="token punctuation">;</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// Cách thực hiện curry đơn giản</span> <span class="token keyword">const</span> <span class="token function-variable function">curry</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token parameter">fn <span class="token punctuation">,</span> <span class="token operator">...</span> args</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token parameter"><span class="token operator">...</span> _arg</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token function">fn</span> <span class="token punctuation">(</span> <span class="token operator">...</span> args <span class="token punctuation">,</span> <span class="token operator">...</span> _arg <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// Có thể dễ dàng sử dụng lại logic giao dịch cho loại giao dịch "free"</span> <span class="token keyword">const</span> freeTransaction <span class="token operator">=</span> <span class="token function">curry</span> <span class="token punctuation">(</span> transaction <span class="token punctuation">,</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">freeTransaction</span> <span class="token punctuation">(</span> <span class="token number">10</span> <span class="token punctuation">,</span> <span class="token number">90</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// = 100</span> <span class="token function">freeTransaction</span> <span class="token punctuation">(</span> <span class="token number">100</span> <span class="token punctuation">,</span> <span class="token number">90</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// = 190</span> |
In the above example, we have implemented a simple Curry logic to handle a function that takes exactly three parameters. The knowledge and examples I give are only for explaining concepts. In fact if you want to apply it I recommend you to use Ramda or similar libraries that support currying
functions with any number of arguments and also support changing the order of arguments using use placeholders
. However, sometimes the logic is simple, I also implement myself a function like the above, which is convenient and saves a lot of Library.
Composition
Composition is a technique where the result of one function is passed to the next function, the function is passed to the next function, etc., until the last function is executed and the result is calculated. Compositions functions can include any number of functions.
Composition also helps to divide functions into smaller reusable functions that are responsible for handling a single logic. (Dividing and conquering is too reasonable, isn’t it?)
1 2 3 4 5 6 7 8 9 10 | <span class="token comment">// Compose function</span> <span class="token keyword">const</span> <span class="token function-variable function">compose</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token parameter"><span class="token operator">...</span> fns</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token parameter">x</span> <span class="token operator">=></span> fns <span class="token punctuation">.</span> <span class="token function">reduce</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token parameter">y <span class="token punctuation">,</span> f</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">f</span> <span class="token punctuation">(</span> y <span class="token punctuation">)</span> <span class="token punctuation">,</span> x <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// Functions</span> <span class="token keyword">const</span> <span class="token function-variable function">addFee</span> <span class="token operator">=</span> <span class="token parameter">amount</span> <span class="token operator">=></span> amount <span class="token operator">+</span> <span class="token number">2</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">addDiscount</span> <span class="token operator">=</span> <span class="token parameter">amount</span> <span class="token operator">=></span> amount <span class="token operator">-</span> <span class="token number">5</span> <span class="token punctuation">;</span> <span class="token comment">// Function composition</span> <span class="token keyword">const</span> composition <span class="token operator">=</span> <span class="token function">compose</span> <span class="token punctuation">(</span> addFee <span class="token punctuation">,</span> addDiscount <span class="token punctuation">)</span> <span class="token punctuation">(</span> <span class="token number">100</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Ramda also has APIs for Composition function
with Pipe and Compose .
Closures
Closures are a function that maintains access to the outer function’s variables and arguments (scope), even after the outer function has finished executing. Closures are useful for hiding implement
details in JavaScript. In other words, it can be useful to create private variables or functions like this: (It’s almost as close to OOP closure)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <span class="token keyword">function</span> <span class="token function">counter</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> count <span class="token operator">=</span> <span class="token number">0</span> <span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">increment</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> count <span class="token operator">+=</span> <span class="token number">1</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> increment <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> generateId <span class="token operator">=</span> <span class="token function">counter</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">generateId</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// 1</span> <span class="token function">generateId</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// 2</span> <span class="token function">generateId</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// 3</span> |
Nullish operator ??
The nullish
operator is a way to quickly apply a default value if the left operand is null
or undefined. This is especially useful in case you want to accept all falsy values
other than null
and undefined
. Or in case you want to apply falsy values
as default.
1 2 3 4 5 6 7 8 9 | <span class="token comment">// Falsy values</span> <span class="token keyword">const</span> value <span class="token operator">=</span> <span class="token number">0</span> <span class="token operator">??</span> <span class="token number">100</span> <span class="token punctuation">;</span> <span class="token comment">// = 0</span> <span class="token keyword">const</span> value <span class="token operator">=</span> <span class="token boolean">false</span> <span class="token operator">??</span> <span class="token boolean">true</span> <span class="token punctuation">;</span> <span class="token comment">// = false</span> <span class="token comment">// Default values</span> <span class="token keyword">const</span> value <span class="token operator">=</span> <span class="token keyword">null</span> <span class="token operator">??</span> <span class="token number">100</span> <span class="token punctuation">;</span> <span class="token comment">// = 100</span> <span class="token keyword">const</span> value <span class="token operator">=</span> <span class="token keyword">undefined</span> <span class="token operator">??</span> <span class="token number">100</span> <span class="token comment">// = 100;</span> |
Reflect API
Reflect programmatically means that a program can test itself by interpolating and manipulating its own structures. The Reflect API provides a set of functions useful for both interpolation and manipulation through the Reflect API ‘s static functions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <span class="token keyword">const</span> person <span class="token operator">=</span> <span class="token punctuation">{</span> name <span class="token operator">:</span> <span class="token string">'Bob'</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token function">Symbol</span> <span class="token punctuation">(</span> <span class="token string">'email'</span> <span class="token punctuation">)</span> <span class="token punctuation">]</span> <span class="token operator">:</span> <span class="token string">'bob@evil.com'</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> Reflect <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> person <span class="token punctuation">,</span> <span class="token string">'name'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// = Bob</span> Reflect <span class="token punctuation">.</span> <span class="token function">has</span> <span class="token punctuation">(</span> person <span class="token punctuation">,</span> <span class="token string">'email'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// = true</span> Reflect <span class="token punctuation">.</span> <span class="token function">has</span> <span class="token punctuation">(</span> person <span class="token punctuation">,</span> <span class="token string">'phone'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// = false</span> Reflect <span class="token punctuation">.</span> <span class="token function">getPrototypeOf</span> <span class="token punctuation">(</span> person <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// = { constructor ... }</span> Reflect <span class="token punctuation">.</span> <span class="token function">getOwnPropertyDescriptor</span> <span class="token punctuation">(</span> person <span class="token punctuation">,</span> <span class="token string">'name'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// = { value: 'Bob', writable: true, enumerable: true, configurable: true }</span> Reflect <span class="token punctuation">.</span> <span class="token function">ownKeys</span> <span class="token punctuation">(</span> person <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// name, Symbol(email)</span> Reflect <span class="token punctuation">.</span> <span class="token function">defineProperty</span> <span class="token punctuation">(</span> person <span class="token punctuation">,</span> <span class="token string">'phone'</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> writable <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> Reflect <span class="token punctuation">.</span> <span class="token function">has</span> <span class="token punctuation">(</span> person <span class="token punctuation">,</span> <span class="token string">'phone'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// = true</span> Reflect <span class="token punctuation">.</span> <span class="token function">set</span> <span class="token punctuation">(</span> person <span class="token punctuation">,</span> <span class="token string">'phone'</span> <span class="token punctuation">,</span> <span class="token string">'123456789'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> Reflect <span class="token punctuation">.</span> <span class="token function">deleteProperty</span> <span class="token punctuation">(</span> person <span class="token punctuation">,</span> <span class="token string">'phone'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> Reflect <span class="token punctuation">.</span> <span class="token function">has</span> <span class="token punctuation">(</span> person <span class="token punctuation">,</span> <span class="token string">'phone'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// = false</span> |
There are many more that you can read in detail here .
Roundup
As always, I hope you enjoyed this article and learned something new.
Thank you and see you in the next posts!
If you find this blog interesting, please give me a like and subscribe to support me. Thank you.