Function Composition in JavaScript with Array.prototype.reduceRight
In recent years, functional programming in JavaScript has become increasingly popular. While some of its often-published principles (such as invariance) require runtime workarounds, the language's first-class processing of functions proves its support for composable code driven by this basic primitive. Before introducing how to dynamically combine functions from other functions, let's briefly review it.
Key Points
- Function combinations in JavaScript can create complex functions by combining simpler functions, thereby improving the reusability and modularity of the code. This approach simplifies code understanding, debugging, and testing, and encourages the principle of "don't repeat yourself" (DRY) and reduces redundancy.
- Advanced-order functions (can take one or more functions as parameters, or return one function as a result) are key parts of function combinations in JavaScript. They are used to create new functions by combining existing functions.
- JavaScript handles functions as values, allowing easy combination of larger, context-specific jobs. Using higher-order functions results in separation of their definitions and calls. This can free developers from the strict hierarchical constraints imposed by object-oriented programming.
- Function combinations can be used with JavaScript frameworks such as React or Vue. In React, combining components to build complex user interfaces is a common pattern. Similarly, Vue's mixin system can be regarded as a form of function combinations.
What is a function?
In fact, a function is a procedure which allows execution of a set of imperative steps to perform side effects or return values. For example:
1 2 3 |
|
When this function is called with an object with the firstName and lastName properties, getFullName returns a string containing the two corresponding values:
1 2 3 4 5 6 7 8 |
|
It is worth noting that since ES2015, JavaScript now supports arrow function syntax:
1 2 3 |
|
Given that our getFullName function has a 1 (i.e. a single parameter) and only has one return statement, we can simplify this expression:
1 |
|
Although the methods of these three expressions are different, they all achieve the same purpose in the end:
- Create a function called getFullName that can be accessed through the name property.
- Accepts a parameter person.
- Returns a calculated string containing person.firstName and person.lastName, separated by spaces.
Combining function through return value
In addition to assigning function return values to declarations (e.g. const person = getPerson();), we can also use them to fill the parameters of other functions, or generally provide values where JavaScript allows them. Suppose we have functions that perform logging and sessionStorage side effects:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
We can do these operations on the return value of getPerson using nested calls:
1 2 3 |
|
Given that the required parameters need to be provided to the function according to the way it is called, the innermost function will be called first. So, in the above example, the return value of getPerson will be passed to the log, and the return value of log will be forwarded to the store. By combining function calls to build statements, we can eventually build complex algorithms from atomic building blocks, but nesting these calls can become difficult to handle; what would it look like if we wanted to combine 10 functions?
1 2 3 4 5 6 7 8 |
|
Luckily, we can use an elegant general implementation: simplify the array of functions into higher order functions.
Cumulative array using Array.prototype.reduce
The reduce method of theArray prototype takes an array instance and accumulates it as a single value. If we want to sum a number array, we can use the following method:
1 2 3 |
|
- Our callback function will run 5 times
- Since we provide an initial value, total will be 0 on the first call
- The first call will return 0 2, causing total to resolve to 2 on the second call
- The result returned by this subsequent call 2 3 will be provided to the total parameter in the third call, etc.
- Accumulator – The value returned by the last iteration callback function. In the first iteration, this resolves to the initial value, and if no initial value is specified, it resolves to the first item in the array.
- currentValue – The array value of the current iteration; since it is linear, it will progress from array[0] to array[array.length - 1]
- during the call to Array.prototype.reduce
Combining function using Array.prototype.reduce
Now that we understand how to simplify arrays into single values, we can use this method to combine existing functions into new functions:
1 |
|
lazy evaluation.
So how do we combine other functions into a single higher order function?
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
- person declaration will resolve to { firstName: 'Homer', incident: 'Simpson' }
- The above representation of person will be output to the browser's console
- person will be serialized to JSON and then write sessionStorage under the person key
The importance of call order
Ability to combine any number of functions using composing utilities to make our code more concise and abstract. However, we can highlight one point by revisiting the inline call:
1 2 3 |
|
People may find it natural to copy this with our compose function:
1 2 3 4 5 6 7 8 |
|
In this case, why does fNested(4) === fComposed(4) resolve to false? You may remember that I emphasized how to interpret the internal call in the first place, so compose(g, h, i) is actually equivalent to x => i(h(g(x))), so fNested returns 10 and fComposed returns 9. We can simply reverse the call order of nested or combined variants of f, but given the specificity of compose to mirror nested calls, we need a way to reduce the function in right-to-left order; JavaScript is lucky to use Array.prototype.reduceRight provides this:
1 2 3 |
|
With this implementation, both fNested(4) and fComposed(4) resolve to 10. However, our getPersonWithSideEffects function is now incorrectly defined; although we can reverse the order of the internal functions, in some cases, reading from left to right can facilitate the psychological analysis of program steps. It turns out that our previous methods have been quite common, but are often called pipe:
1 |
|
By using our pipe function, we will keep the left-to-right order required by getPersonWithSideEffects. Pipelines have become a major component of RxJS for reasons outlined above; in this order, it may be more intuitive to think about data streams in combination streams operated by operators.
Function combinations as alternatives to inheritance
We have seen in the previous example how to combine infinite multiple functions into larger, reusable, target-oriented units. Another benefit of function combination is to free yourself from the rigidity of inheritance graphs. Suppose we want to reuse logging and storage behavior based on the class hierarchy; it can be expressed like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Apart from the length, the direct problem with this code is that we abuse inheritance to implement reuse; if another class extends Loggable, it is also inherently a subclass of the Storage, even if we don't need this logic. A potentially more serious problem is naming conflicts:
1 2 3 |
|
If we want to instantiate MyState and call its store method, we will not call the Storeable store method unless we add a call to super.store() in MyState.prototype.store, but this will be in State Creates a tight, fragile coupling between Storable. This can be mitigated using entity systems or policy patterns, as I have introduced elsewhere, but despite the advantages of inheriting the broader taxonomy of expression systems, function combinations provide a flat, concise way to share without dependency on Code for method name.
Summary
JavaScript handles functions as values and generates their expressions, making it easy to combine larger, context-specific jobs. Thinking of this task as a cumulative of function arrays eliminates the need for imperative nested calls, and using higher-order functions results in separation of their definitions and calls. Furthermore, we can get rid of the strict hierarchical constraints imposed by object-oriented programming.
FAQs about function combinations in JavaScript
What is the meaning of function combination in JavaScript?
Function combination is a basic concept in JavaScript and large functional programming. It allows developers to create complex functions by combining simpler functions, thereby improving the reusability and modularity of their code. This approach makes the code easier to understand, debug and test. It also encourages the principle of "don't repeat yourself" (DRY) to reduce redundancy in the code base.
How does function combinations relate to the concept of higher-order functions?
High-order functions are a key part of function combinations in JavaScript. A higher-order function is a function that can take one or more functions as parameters, return a function as a result, or perform both operations at the same time. In function combinations, we often use higher-order functions to create new functions by combining existing functions.
Can you provide a practical example of function combinations in JavaScript?
Of course, let's consider a simple example. Suppose we have two functions, double and increment. double takes a number and multiplies it by 2, and increment adds 1 to its input. We can combine these two functions to create a new function that doubles a number and increments the result.
1 2 3 4 5 6 7 8 |
|
What is the difference between function combination and function chain in JavaScript?
Function combination and function chain are two different ways to combine functions in JavaScript. Function combinations involve passing the output of one function as input to another. On the other hand, a function chain involves calling multiple functions in order, where each function calls the result of the previous function. Although both techniques can achieve similar results, function combinations are more in line with the principles of functional programming.
How does function combination help with code testing and debugging?
Function combinations facilitate the creation of small pure functions that do only one thing and do well. These functions are easier to test and debug than large monolithic functions. Since each function is independent, you can test it individually without worrying about the rest of the code. This makes it easier to find and fix bugs in the code.
Is function combinations possible with asynchronous functions in JavaScript?
Yes, function combinations can be used with asynchronous functions in JavaScript. However, this requires more attention, as you need to make sure that the output of an asynchronous function is correctly passed to the next function as input. This usually involves using promise or async/await syntax.
What are the potential drawbacks or challenges of using function combinations in JavaScript?
Although there are many benefits to function combinations, it may also introduce complexity if used improperly. For example, deeply nested function calls can be difficult to read and understand. Furthermore, if the combined functions are not pure functions (i.e. they have side effects), it may lead to unexpected results. Therefore, it is important to use function combinations with caution and combine them with good coding practices.
How does function combinations relate to the concept of currying in JavaScript?
Curriization is a technique in JavaScript where a function with multiple parameters is converted into a series of functions, each function has only one parameter. Currying can be used with functions combinations to create more flexible and reusable functions. In fact, some utility libraries such as lodash and Ramda provide both currying and combinatorial functions.
Is function combinations useful with JavaScript frameworks such as React or Vue?
Yes, function combinations can be used with JavaScript frameworks such as React or Vue. In fact, in React, combining components to build complex user interfaces is a common pattern. Similarly, Vue's mixin system can be regarded as a form of function combinations.
What libraries or tools are there to assist in function combinations in JavaScript?
Yes, there are several libraries that provide utilities for function combinations in JavaScript. Some popular libraries include lodash, Ramda, and Redux (for state management). These libraries provide functions such as compose or pipe, making combining functions easier and more efficient.
The above is the detailed content of Function Composition in JavaScript with Array.prototype.reduceRight. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics











Frequently Asked Questions and Solutions for Front-end Thermal Paper Ticket Printing In Front-end Development, Ticket Printing is a common requirement. However, many developers are implementing...

JavaScript is the cornerstone of modern web development, and its main functions include event-driven programming, dynamic content generation and asynchronous programming. 1) Event-driven programming allows web pages to change dynamically according to user operations. 2) Dynamic content generation allows page content to be adjusted according to conditions. 3) Asynchronous programming ensures that the user interface is not blocked. JavaScript is widely used in web interaction, single-page application and server-side development, greatly improving the flexibility of user experience and cross-platform development.

There is no absolute salary for Python and JavaScript developers, depending on skills and industry needs. 1. Python may be paid more in data science and machine learning. 2. JavaScript has great demand in front-end and full-stack development, and its salary is also considerable. 3. Influencing factors include experience, geographical location, company size and specific skills.

Discussion on the realization of parallax scrolling and element animation effects in this article will explore how to achieve similar to Shiseido official website (https://www.shiseido.co.jp/sb/wonderland/)...

The latest trends in JavaScript include the rise of TypeScript, the popularity of modern frameworks and libraries, and the application of WebAssembly. Future prospects cover more powerful type systems, the development of server-side JavaScript, the expansion of artificial intelligence and machine learning, and the potential of IoT and edge computing.

How to merge array elements with the same ID into one object in JavaScript? When processing data, we often encounter the need to have the same ID...

Explore the implementation of panel drag and drop adjustment function similar to VSCode in the front-end. In front-end development, how to implement VSCode similar to VSCode...

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.
