Function-Type JS interface
Previously, I saw a technical video on YouTube that said "why the Underscore.js interface is not good" and what kind of interface is better. The speaker is the author of Lodash.js, who proposes a "comprehensive functional" JS interface design pattern. Probably something like this:
Traditional interface _.map ([1, 2, 3], function (EL) {return el * 2}); return [2, 4, 6]//function-interface var fn = _.map ([1, 2, 3]); Return a FUNCTIONFN (function (EL) {return el * 2}); return [2, 4, 6];//or _.map ([1, 2, 3]) (function (EL) {return el * 2}); return [2, 4, 6];
Did you find a little feeling? In fact, it is the ubiquitous function of "the localization" in the functional programming language. When the argument fills the formal parameter list, the settlement returns the result, otherwise a temporary function is returned and the argument continues to be accepted.
Seeing this writing, I felt the potential for a large-scale simplification of code. At that time, actually tried to send a lot of places to use, because the previously written code is affected by JQuery, there are many such interfaces:
Foobar.attribute (name); Read attribute Foobar.attribute (name, newvalue); Write properties
Such an interface is curry by the above method will make the read attribute impossible, the root cause is that the number of parameters is not the same as the semantics of the attribute function at all. Using jQuery feels like this is a great way to write, and then it follows, but at the moment there seems to be a problem with this interface design.
So, today, talk about how this interface is implemented, and the FP module in Lodash.
Implementation principle
In the final analysis is a currying problem, currying in many languages is built-in features, but JS does not, so we want to implement a currying tool function. First, the simplest implementation of the currying, its function is very simple, input a function fn1 and partial arguments, return a save part of the argument, continue to receive the arguments of the function fn2, call fn2, it will merge the real parameter group, and call FN1.
/** * Function Curry * @param fn input function * @return the function */var curry = functions (fn) { if (!isfunction (FN)) { return; } var args = slice (arguments, 1); return function () { return fn.apply (this, args.concat (slice (arguments, 0)));} }
Isfunction and slice Everybody knows I'm not going to stick it out. Take a look at how to invoke:
function Add (A, b) { return a + b;} AddOne = Curry (add, 1); AddOne (2); Return 3
Sometimes we need to enter part of the argument as an array list, so let's wrap up the curry function just now:
/** * Function Curry * @param fn input function * @param arr parameter list * @return the function */var curryapply = functions (FN, arr) { if (!isfuncti On (FN)) { return; } var args = arr.slice (0); Args.unshift (FN); Return curry.apply (this, args);}
The problem with the curry function above is that we need to encapsulate a version that supports successive invocations by supplementing the arguments several times in a row:
/** * Auto-Curry * @param fn input function * @param n Input function parameter number * @return the function after curry */var Autocurry = functions (FN, n) { if (!isfunctio N (FN)) { return; } function Retfn () { var len = arguments.length; var args = slice (arguments, 0); var nextn = N-len; if (Nextn > 0) { return Autocurry (curryapply (RETFN, args), nextn); } Return fn.apply (this, args); } return RETFN;}
The recursive method used by Autocurry, the output function can continuously complement the arguments in a simple call, and the input function is executed when the arguments and the preset number of parameters are equal. Here's how to use it:
function Compute (A, B, c) { return (A + b) * C;} var curryedcompute = Autocurry (compute, 3); Compute (1, 2, 3); return 9curryedCompute (1) (2) (3); Return 9
If you use node. js, you probably know that there is a curry module in NPM, the functionality is the same, but when you do not enter the number of arguments n, the curry module uses the Length property of the function object as the preset n value.
Lodash/fp
The realization of the principle here is clear. In the principle of not making wheels, if you want to try the functional style of the basic JS library, it is recommended to use LODASH/FP this module. We all know that Lodash is underscore better implemention, and LODASH/FP is the lodash of the branch. Unlike simple currying, for ease of use, LODASH/FP's designers swapped out some of the interface's parameter sequences, such as the _.map interface mentioned at the beginning, and if simple currying the first parameter should be an array [1, 2, 3], but most of the time, What we want to hold is an algorithm that uses this algorithm to process different data. So what we want to be staged is actually the second parameter, FN, so the LODASH/FP interface is this:
The ' Lodash/map ' Iteratee receives three arguments://(value, Index|key, collection) _.map ([' 6 ', ' 8 ', ' Ten '], parseint); /→[6, NaN, 2]//the ' Lodash/fp/map ' Iteratee is capped at one argument://(value) Fp.map (parseint) ([' 6 ', ' 8 ', ' 10 ']);//→ [6, 8, 10]
For more detailed instructions on LODASH/FP, see: Https://github.com/lodash/lodash/wiki/FP ...
Function JS Interface implementation principle, and LODASH/FP module