The previous article introduced the implementation of curry
(currying) in javascript
functional programming. Of course, that currying has limited parameters. Currying, the kind of currying that allows you to add infinite parameters when you have the opportunity. This time I am mainly talking about javascript
another very important function in functional programmingcompose
, compose
The function of the function is to combine functions, execute functions in series, and combine multiple functions. The output result of one function is the input parameter of another function. Once the first function starts to execute, It will be deduced and executed like dominoes.
For example, if you have such a requirement, you need to enter a name. This name is composed of firstName
, lastName
, and then put this Change all names to uppercase and output them. For example, if you enter jack
, smith
, we will print it out, 'HELLO, JACK SMITH'
.
We consider using function combination to solve this problem, which requires two functions greeting
, toUpper
var greeting = (firstName, lastName) => 'hello, ' + firstName + ' ' + lastName var toUpper = str => str.toUpperCase() var fn = compose(toUpper, greeting) console.log(fn('jack', 'smith')) // ‘HELLO,JACK SMITH’
This is the rough use of compose , to summarize, the following points should be noted:
The parameters of compose
are functions, and what is returned is also a function
Because except for the parameters accepted by the first function, the parameters accepted by other functions are the return values of the previous function, so the parameters of the initial function are multiple
, while the accepted values of other functions are The
compsoe function of one yuan
can accept any parameters. All parameters are functions, and the execution direction is from right to left
, the initial function must be placed on the rightmost side of the parameter
After knowing these three points, it is easy to analyze the execution process of the previous example. , when executing fn('jack', 'smith')
, the initial function is greeting
, the execution result is passed as a parameter to toUpper
, and then executed toUpper
, to get the final result, let me briefly mention the benefits of compose. If you want to add a processing function, you don’t need to modify fn
, you only need to execute a compose
, for example, if we want to add another trim
, we only need to do
var trim = str => str.trim() var newFn = compose(trim, fn) console.log(newFn('jack', 'smith'))
. It can be seen that it is very convenient for maintenance and expansion.
After analyzing the examples, in line with the fundamental principle, we still need to explore how compose
is implemented. First, I will explain how I Implemented, and then explore how the two major libraries of javascript
functional programming, lodash.js
and ramda.js
are implemented, among whichramda.js
The implementation process is very functional.
My idea is that since the function executes like a domino, I first thought of recursion. Let’s implement this step by stepcompose
, First, compose
returns a function. In order to record the execution of the recursion, the length of the parameters len
must also be recorded, and a name must be added to the returned function f1
.
var compose = function(...args) { var len = args.length return function f1() { } }
What needs to be done in the function body is to continuously execute the functions in args
, and use the execution result of the previous function as the input parameter of the next execution function, which requires a cursorcount
to record the execution of the args
function list.
var compose = function(...args) { var len = args.length var count = len - 1 var result return function f1(...args1) { result = args[count].apply(this, args1) count-- return f1.call(null, result) } }
This is the idea. Of course, this is not possible. There is no exit condition. The recursive exit condition is when the last function is executed, that is, count
is 0
, at this time, one thing to note is that when the recursion exits, the count
cursor must return to the initial state, and finally add the code
var compose = function(...args) { var len = args.length var count = len - 1 var result return function f1(...args1) { result = args[count].apply(this, args1) if (count <= 0) { count = len - 1 return result } else { count-- return f1.call(null, result) } } }
This will achieve this compose
function. Later, I discovered that recursion can be achieved using iteration. It seems easier to understand using the while
function. In fact, lodash.js
is implemented in this way.
lodash
The idea of implementing lodash
is the same as above, but it is implemented iteratively. I will post its source code to take a look
var flow = function(funcs) { var length = funcs.length var index = length while (index--) { if (typeof funcs[index] !== 'function') { throw new TypeError('Expected a function'); } } return function(...args) { var index = 0 var result = length ? funcs[index].apply(this, args) : args[0] while (++index < length) { result = funcs[index].call(this, result) } return result } } var flowRight = function(funcs) { return flow(funcs.reverse()) }
It can be seen that the original implementation of lodash
is from left to right
, but it also provides from right to left
flowRight
, there is an additional layer of function verification, and what is received is an array
, not a parameter sequence
, and from this linevar result = length? funcs[index].apply(this, args): args[0]
It can be seen that the array is allowed to be empty, and it can be seen that it is still very strict. What I wrote lacked this rigorous exception handling.
This time I mainly introduce the principle and implementation method of the compose
function in functional programming. Due to space reasons, I will analyze the ramda The .js
source code implementation will be introduced in the next article. It can be said that the compose
implemented by ramda.js
is more functional and needs to be analyzed separately.
The above is the content implemented by compose in JavaScript functional programming. For more related content, please pay attention to the PHP Chinese website (www.php.cn)!