| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- ## 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
- <script src='path/to/lodash.js'></script>
- <script src='path/to/lodash.fp.js'></script>
- <script>
- // Loading `lodash.fp.js` converts `_` to its fp variant.
- _.defaults({ 'a': 2, 'b': 2 })({ 'a': 1 });
- // ➜ { 'a': 1, 'b': 2 }
- // Use `noConflict` to restore the pre-fp variant.
- var fp = _.noConflict();
- _.defaults({ 'a': 1 }, { 'a': 2, 'b': 2 });
- // ➜ { 'a': 1, 'b': 2 }
- fp.defaults({ 'a': 2, 'b': 2 })({ 'a': 1 });
- // ➜ { 'a': 1, 'b': 2 }
- </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);
- // ➜ [6, NaN, 2]
- // The `lodash/fp/map` iteratee is capped at one argument:
- // (value)
- fp.map(parseInt)(['6', '8', '10']);
- // ➜ [6, 8, 10]
- ```
- 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)))) %>
- The iteratee of `mapKeys` is invoked with one argument: (key)
- #### Fixed Arity
- Methods have fixed arities to support auto-currying.
- ```js
- // `lodash/padStart` accepts an optional `chars` param.
- _.padStart('a', 3, '-')
- // ➜ '--a'
- // `lodash/fp/padStart` does not.
- fp.padStart(3)('a');
- // ➜ ' a'
- fp.padCharsStart('-')(3)('a');
- // ➜ '--a'
- ```
- 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']);
- // ➜ ['a', 'c']
- // `lodash/fp/filter` is iteratee-first data-last:
- // (iteratee, collection)
- var compact = fp.filter(Boolean);
- compact(['a', null, 'c']);
- // ➜ ['a', 'c']
- ```
- ##### 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
- Methods that accept an array of arguments:<br>
- <%= toFuncList(_.keys(mapping.methodSpread)) %>
- Methods with unchanged argument orders:<br>
- <%= toFuncList(_.keys(mapping.skipRearg)) %>
- Methods with custom argument orders:<br>
- <%= _.map(_.keys(mapping.methodRearg), function(methodName) {
- var orders = mapping.methodRearg[methodName];
- return ' * `_.' + methodName + '` has an order of ' + toArgOrder(orders);
- }).join('\n') %>
- #### 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>
- <%= _.map(_.keys(mapping.aliasToReal).sort(), function(alias) {
- var realName = mapping.aliasToReal[alias];
- 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);
- // ➜ false
- // The equivalent of `_.gt(5, 2)` or `5 > 2`.
- _.gt(_, 2)(5);
- // ➜ true
- ```
- ## 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.
|