2016-05-16 13:33:49 +02:00
|
|
|
|
## lodash/fp
|
|
|
|
|
|
|
|
|
|
The `lodash/fp` module promotes a more
|
|
|
|
|
[functional programming](https://en.wikipedia.org/wiki/Functional_programming)
|
|
|
|
|
(FP) friendly style by exporting an instance of `lodash` with its methods wrapped
|
|
|
|
|
to produce immutable auto-curried iteratee-first data-last methods.
|
|
|
|
|
|
|
|
|
|
## Installation
|
|
|
|
|
|
|
|
|
|
In a browser:
|
|
|
|
|
```html
|
2017-05-13 13:25:33 +02:00
|
|
|
|
<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>
|
2016-05-16 13:33:49 +02:00
|
|
|
|
<script>
|
|
|
|
|
// Loading `lodash.fp.js` converts `_` to its fp variant.
|
|
|
|
|
_.defaults({ 'a': 2, 'b': 2 })({ 'a': 1 });
|
2017-05-13 13:25:33 +02:00
|
|
|
|
// ➜ { 'a': 1, 'b': 2 }
|
2016-05-16 13:33:49 +02:00
|
|
|
|
|
|
|
|
|
// Use `noConflict` to restore the pre-fp variant.
|
|
|
|
|
var fp = _.noConflict();
|
|
|
|
|
|
|
|
|
|
_.defaults({ 'a': 1 }, { 'a': 2, 'b': 2 });
|
2017-05-13 13:25:33 +02:00
|
|
|
|
// ➜ { 'a': 1, 'b': 2 }
|
2016-05-16 13:33:49 +02:00
|
|
|
|
fp.defaults({ 'a': 2, 'b': 2 })({ 'a': 1 });
|
2017-05-13 13:25:33 +02:00
|
|
|
|
// ➜ { 'a': 1, 'b': 2 }
|
2016-05-16 13:33:49 +02:00
|
|
|
|
</script>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
In Node.js:
|
|
|
|
|
```js
|
|
|
|
|
// Load the fp build.
|
|
|
|
|
var fp = require('lodash/fp');
|
|
|
|
|
|
|
|
|
|
// Load a method category.
|
|
|
|
|
var object = require('lodash/fp/object');
|
|
|
|
|
|
|
|
|
|
// Load a single method for smaller builds with browserify/rollup/webpack.
|
|
|
|
|
var extend = require('lodash/fp/extend');
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Mapping
|
|
|
|
|
|
|
|
|
|
Immutable auto-curried iteratee-first data-last methods sound great, but what
|
|
|
|
|
does that really mean for each method? Below is a breakdown of the mapping used
|
|
|
|
|
to convert each method.
|
|
|
|
|
|
|
|
|
|
#### Capped Iteratee Arguments
|
|
|
|
|
|
|
|
|
|
Iteratee arguments are capped to avoid gotchas with variadic iteratees.
|
|
|
|
|
```js
|
|
|
|
|
// The `lodash/map` iteratee receives three arguments:
|
|
|
|
|
// (value, index|key, collection)
|
|
|
|
|
_.map(['6', '8', '10'], parseInt);
|
2017-05-13 13:25:33 +02:00
|
|
|
|
// ➜ [6, NaN, 2]
|
2016-05-16 13:33:49 +02:00
|
|
|
|
|
|
|
|
|
// The `lodash/fp/map` iteratee is capped at one argument:
|
|
|
|
|
// (value)
|
|
|
|
|
fp.map(parseInt)(['6', '8', '10']);
|
2017-05-13 13:25:33 +02:00
|
|
|
|
// ➜ [6, 8, 10]
|
2016-05-16 13:33:49 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Methods that cap iteratees to one argument:<br>
|
|
|
|
|
<%= toFuncList(_.keys(_.pickBy(mapping.iterateeAry, _.partial(_.eq, _, 1)))) %>
|
|
|
|
|
|
|
|
|
|
Methods that cap iteratees to two arguments:<br>
|
|
|
|
|
<%= toFuncList(_.keys(_.pickBy(mapping.iterateeAry, _.partial(_.eq, _, 2)))) %>
|
|
|
|
|
|
2017-05-13 13:25:33 +02:00
|
|
|
|
The iteratee of `mapKeys` is capped to one argument: `(key)`
|
2016-05-16 13:33:49 +02:00
|
|
|
|
|
|
|
|
|
#### Fixed Arity
|
|
|
|
|
|
|
|
|
|
Methods have fixed arities to support auto-currying.
|
|
|
|
|
```js
|
|
|
|
|
// `lodash/padStart` accepts an optional `chars` param.
|
|
|
|
|
_.padStart('a', 3, '-')
|
2017-05-13 13:25:33 +02:00
|
|
|
|
// ➜ '--a'
|
2016-05-16 13:33:49 +02:00
|
|
|
|
|
|
|
|
|
// `lodash/fp/padStart` does not.
|
|
|
|
|
fp.padStart(3)('a');
|
2017-05-13 13:25:33 +02:00
|
|
|
|
// ➜ ' a'
|
2016-05-16 13:33:49 +02:00
|
|
|
|
fp.padCharsStart('-')(3)('a');
|
2017-05-13 13:25:33 +02:00
|
|
|
|
// ➜ '--a'
|
2016-05-16 13:33:49 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Methods with a fixed arity of one:<br>
|
|
|
|
|
<%= toFuncList(_.difference(mapping.aryMethod[1], _.keys(mapping.skipFixed))) %>
|
|
|
|
|
|
|
|
|
|
Methods with a fixed arity of two:<br>
|
|
|
|
|
<%= toFuncList(_.difference(mapping.aryMethod[2], _.keys(mapping.skipFixed))) %>
|
|
|
|
|
|
|
|
|
|
Methods with a fixed arity of three:<br>
|
|
|
|
|
<%= toFuncList(_.difference(mapping.aryMethod[3], _.keys(mapping.skipFixed))) %>
|
|
|
|
|
|
|
|
|
|
Methods with a fixed arity of four:<br>
|
|
|
|
|
<%= toFuncList(_.difference(mapping.aryMethod[4], _.keys(mapping.skipFixed))) %>
|
|
|
|
|
|
|
|
|
|
#### Rearranged Arguments
|
|
|
|
|
|
|
|
|
|
Method arguments are rearranged to make composition easier.
|
|
|
|
|
```js
|
|
|
|
|
// `lodash/filter` is data-first iteratee-last:
|
|
|
|
|
// (collection, iteratee)
|
|
|
|
|
var compact = _.partial(_.filter, _, Boolean);
|
|
|
|
|
compact(['a', null, 'c']);
|
2017-05-13 13:25:33 +02:00
|
|
|
|
// ➜ ['a', 'c']
|
2016-05-16 13:33:49 +02:00
|
|
|
|
|
|
|
|
|
// `lodash/fp/filter` is iteratee-first data-last:
|
|
|
|
|
// (iteratee, collection)
|
|
|
|
|
var compact = fp.filter(Boolean);
|
|
|
|
|
compact(['a', null, 'c']);
|
2017-05-13 13:25:33 +02:00
|
|
|
|
// ➜ ['a', 'c']
|
2016-05-16 13:33:49 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
##### Most methods follow these rules
|
|
|
|
|
|
|
|
|
|
A fixed arity of two has an argument order of:<br>
|
|
|
|
|
<%= toArgOrder(mapping.aryRearg[2]) %>
|
|
|
|
|
|
|
|
|
|
A fixed arity of three has an argument order of:<br>
|
|
|
|
|
<%= toArgOrder(mapping.aryRearg[3]) %>
|
|
|
|
|
|
|
|
|
|
A fixed arity of four has an argument order of:<br>
|
|
|
|
|
<%= toArgOrder(mapping.aryRearg[4]) %>
|
|
|
|
|
|
|
|
|
|
##### Exceptions to the rules
|
|
|
|
|
|
2019-03-29 22:00:08 +01:00
|
|
|
|
Methods that accept an array as their last, second to last, or only argument:<br>
|
2016-05-16 13:33:49 +02:00
|
|
|
|
<%= toFuncList(_.keys(mapping.methodSpread)) %>
|
|
|
|
|
|
|
|
|
|
Methods with unchanged argument orders:<br>
|
|
|
|
|
<%= toFuncList(_.keys(mapping.skipRearg)) %>
|
|
|
|
|
|
|
|
|
|
Methods with custom argument orders:<br>
|
2017-05-13 13:25:33 +02:00
|
|
|
|
<%= _.map(_.keys(mapping.methodRearg), methodName => {
|
|
|
|
|
const orders = mapping.methodRearg[methodName];
|
2016-05-16 13:33:49 +02:00
|
|
|
|
return ' * `_.' + methodName + '` has an order of ' + toArgOrder(orders);
|
|
|
|
|
}).join('\n') %>
|
|
|
|
|
|
2017-05-13 13:25:33 +02:00
|
|
|
|
The iteratee of `reduceRight` has an argument order of: `(b, a)`
|
|
|
|
|
|
2016-05-16 13:33:49 +02:00
|
|
|
|
#### New Methods
|
|
|
|
|
|
|
|
|
|
Not all variadic methods have corresponding new method variants. Feel free to
|
|
|
|
|
[request](https://github.com/lodash/lodash/blob/master/.github/CONTRIBUTING.md#feature-requests)
|
|
|
|
|
any additions.
|
|
|
|
|
|
|
|
|
|
Methods created to accommodate Lodash’s variadic methods:<br>
|
|
|
|
|
<%= toFuncList(_.keys(mapping.remap)) %>
|
|
|
|
|
|
|
|
|
|
#### Aliases
|
|
|
|
|
|
|
|
|
|
There are <%= _.size(mapping.aliasToReal) %> method aliases:<br>
|
2017-05-13 13:25:33 +02:00
|
|
|
|
<%= _.map(_.keys(mapping.aliasToReal).sort(), alias => {
|
|
|
|
|
const realName = mapping.aliasToReal[alias];
|
2016-05-16 13:33:49 +02:00
|
|
|
|
return ' * `_.' + alias + '` is an alias of `_.' + realName + '`';
|
|
|
|
|
}).join('\n') %>
|
|
|
|
|
|
|
|
|
|
## Placeholders
|
|
|
|
|
|
|
|
|
|
The placeholder argument, which defaults to `_`, may be used to fill in method
|
|
|
|
|
arguments in a different order. Placeholders are filled by the first available
|
|
|
|
|
arguments of the curried returned function.
|
|
|
|
|
```js
|
|
|
|
|
// The equivalent of `2 > 5`.
|
|
|
|
|
_.gt(2)(5);
|
2017-05-13 13:25:33 +02:00
|
|
|
|
// ➜ false
|
2016-05-16 13:33:49 +02:00
|
|
|
|
|
|
|
|
|
// The equivalent of `_.gt(5, 2)` or `5 > 2`.
|
|
|
|
|
_.gt(_, 2)(5);
|
2017-05-13 13:25:33 +02:00
|
|
|
|
// ➜ true
|
2016-05-16 13:33:49 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Chaining
|
|
|
|
|
|
|
|
|
|
The `lodash/fp` module **does not** convert chain sequence methods. See
|
|
|
|
|
[Izaak Schroeder’s article](https://medium.com/making-internets/why-using-chain-is-a-mistake-9bc1f80d51ba)
|
|
|
|
|
on using functional composition as an alternative to method chaining.
|
|
|
|
|
|
|
|
|
|
## Convert
|
|
|
|
|
|
|
|
|
|
Although `lodash/fp` & its method modules come pre-converted, there are times
|
|
|
|
|
when you may want to customize the conversion. That’s when the `convert` method
|
|
|
|
|
comes in handy.
|
|
|
|
|
```js
|
|
|
|
|
// Every option is `true` by default.
|
|
|
|
|
var _fp = fp.convert({
|
|
|
|
|
// Specify capping iteratee arguments.
|
|
|
|
|
'cap': true,
|
|
|
|
|
// Specify currying.
|
|
|
|
|
'curry': true,
|
|
|
|
|
// Specify fixed arity.
|
|
|
|
|
'fixed': true,
|
|
|
|
|
// Specify immutable operations.
|
|
|
|
|
'immutable': true,
|
|
|
|
|
// Specify rearranging arguments.
|
|
|
|
|
'rearg': true
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// The `convert` method is available on each method too.
|
|
|
|
|
var mapValuesWithKey = fp.mapValues.convert({ 'cap': false });
|
|
|
|
|
|
|
|
|
|
// Here’s an example of disabling iteratee argument caps to access the `key` param.
|
|
|
|
|
mapValuesWithKey(function(value, key) {
|
|
|
|
|
return key == 'a' ? -1 : value;
|
|
|
|
|
})({ 'a': 1, 'b': 1 });
|
|
|
|
|
// => { 'a': -1, 'b': 1 }
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Manual conversions are also possible with the `convert` module.
|
|
|
|
|
```js
|
|
|
|
|
var convert = require('lodash/fp/convert');
|
|
|
|
|
|
|
|
|
|
// Convert by name.
|
|
|
|
|
var assign = convert('assign', require('lodash.assign'));
|
|
|
|
|
|
|
|
|
|
// Convert by object.
|
|
|
|
|
var fp = convert({
|
|
|
|
|
'assign': require('lodash.assign'),
|
|
|
|
|
'chunk': require('lodash.chunk')
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Convert by `lodash` instance.
|
|
|
|
|
var fp = convert(lodash.runInContext());
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Tooling
|
|
|
|
|
|
|
|
|
|
Use [eslint-plugin-lodash-fp](https://www.npmjs.com/package/eslint-plugin-lodash-fp)
|
|
|
|
|
to help use `lodash/fp` more efficiently.
|