wiki.jst 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. ## lodash/fp
  2. The `lodash/fp` module promotes a more
  3. [functional programming](https://en.wikipedia.org/wiki/Functional_programming)
  4. (FP) friendly style by exporting an instance of `lodash` with its methods wrapped
  5. to produce immutable auto-curried iteratee-first data-last methods.
  6. ## Installation
  7. In a browser:
  8. ```html
  9. <script src='path/to/lodash.js'></script>
  10. <script src='path/to/lodash.fp.js'></script>
  11. <script>
  12. // Loading `lodash.fp.js` converts `_` to its fp variant.
  13. _.defaults({ 'a': 2, 'b': 2 })({ 'a': 1 });
  14. // ➜ { 'a': 1, 'b': 2 }
  15. // Use `noConflict` to restore the pre-fp variant.
  16. var fp = _.noConflict();
  17. _.defaults({ 'a': 1 }, { 'a': 2, 'b': 2 });
  18. // ➜ { 'a': 1, 'b': 2 }
  19. fp.defaults({ 'a': 2, 'b': 2 })({ 'a': 1 });
  20. // ➜ { 'a': 1, 'b': 2 }
  21. </script>
  22. ```
  23. In Node.js:
  24. ```js
  25. // Load the fp build.
  26. var fp = require('lodash/fp');
  27. // Load a method category.
  28. var object = require('lodash/fp/object');
  29. // Load a single method for smaller builds with browserify/rollup/webpack.
  30. var extend = require('lodash/fp/extend');
  31. ```
  32. ## Mapping
  33. Immutable auto-curried iteratee-first data-last methods sound great, but what
  34. does that really mean for each method? Below is a breakdown of the mapping used
  35. to convert each method.
  36. #### Capped Iteratee Arguments
  37. Iteratee arguments are capped to avoid gotchas with variadic iteratees.
  38. ```js
  39. // The `lodash/map` iteratee receives three arguments:
  40. // (value, index|key, collection)
  41. _.map(['6', '8', '10'], parseInt);
  42. // ➜ [6, NaN, 2]
  43. // The `lodash/fp/map` iteratee is capped at one argument:
  44. // (value)
  45. fp.map(parseInt)(['6', '8', '10']);
  46. // ➜ [6, 8, 10]
  47. ```
  48. Methods that cap iteratees to one argument:<br>
  49. <%= toFuncList(_.keys(_.pickBy(mapping.iterateeAry, _.partial(_.eq, _, 1)))) %>
  50. Methods that cap iteratees to two arguments:<br>
  51. <%= toFuncList(_.keys(_.pickBy(mapping.iterateeAry, _.partial(_.eq, _, 2)))) %>
  52. The iteratee of `mapKeys` is invoked with one argument: (key)
  53. #### Fixed Arity
  54. Methods have fixed arities to support auto-currying.
  55. ```js
  56. // `lodash/padStart` accepts an optional `chars` param.
  57. _.padStart('a', 3, '-')
  58. // ➜ '--a'
  59. // `lodash/fp/padStart` does not.
  60. fp.padStart(3)('a');
  61. // ➜ ' a'
  62. fp.padCharsStart('-')(3)('a');
  63. // ➜ '--a'
  64. ```
  65. Methods with a fixed arity of one:<br>
  66. <%= toFuncList(_.difference(mapping.aryMethod[1], _.keys(mapping.skipFixed))) %>
  67. Methods with a fixed arity of two:<br>
  68. <%= toFuncList(_.difference(mapping.aryMethod[2], _.keys(mapping.skipFixed))) %>
  69. Methods with a fixed arity of three:<br>
  70. <%= toFuncList(_.difference(mapping.aryMethod[3], _.keys(mapping.skipFixed))) %>
  71. Methods with a fixed arity of four:<br>
  72. <%= toFuncList(_.difference(mapping.aryMethod[4], _.keys(mapping.skipFixed))) %>
  73. #### Rearranged Arguments
  74. Method arguments are rearranged to make composition easier.
  75. ```js
  76. // `lodash/filter` is data-first iteratee-last:
  77. // (collection, iteratee)
  78. var compact = _.partial(_.filter, _, Boolean);
  79. compact(['a', null, 'c']);
  80. // ➜ ['a', 'c']
  81. // `lodash/fp/filter` is iteratee-first data-last:
  82. // (iteratee, collection)
  83. var compact = fp.filter(Boolean);
  84. compact(['a', null, 'c']);
  85. // ➜ ['a', 'c']
  86. ```
  87. ##### Most methods follow these rules
  88. A fixed arity of two has an argument order of:<br>
  89. <%= toArgOrder(mapping.aryRearg[2]) %>
  90. A fixed arity of three has an argument order of:<br>
  91. <%= toArgOrder(mapping.aryRearg[3]) %>
  92. A fixed arity of four has an argument order of:<br>
  93. <%= toArgOrder(mapping.aryRearg[4]) %>
  94. ##### Exceptions to the rules
  95. Methods that accept an array of arguments:<br>
  96. <%= toFuncList(_.keys(mapping.methodSpread)) %>
  97. Methods with unchanged argument orders:<br>
  98. <%= toFuncList(_.keys(mapping.skipRearg)) %>
  99. Methods with custom argument orders:<br>
  100. <%= _.map(_.keys(mapping.methodRearg), function(methodName) {
  101. var orders = mapping.methodRearg[methodName];
  102. return ' * `_.' + methodName + '` has an order of ' + toArgOrder(orders);
  103. }).join('\n') %>
  104. #### New Methods
  105. Not all variadic methods have corresponding new method variants. Feel free to
  106. [request](https://github.com/lodash/lodash/blob/master/.github/CONTRIBUTING.md#feature-requests)
  107. any additions.
  108. Methods created to accommodate Lodash’s variadic methods:<br>
  109. <%= toFuncList(_.keys(mapping.remap)) %>
  110. #### Aliases
  111. There are <%= _.size(mapping.aliasToReal) %> method aliases:<br>
  112. <%= _.map(_.keys(mapping.aliasToReal).sort(), function(alias) {
  113. var realName = mapping.aliasToReal[alias];
  114. return ' * `_.' + alias + '` is an alias of `_.' + realName + '`';
  115. }).join('\n') %>
  116. ## Placeholders
  117. The placeholder argument, which defaults to `_`, may be used to fill in method
  118. arguments in a different order. Placeholders are filled by the first available
  119. arguments of the curried returned function.
  120. ```js
  121. // The equivalent of `2 > 5`.
  122. _.gt(2)(5);
  123. // ➜ false
  124. // The equivalent of `_.gt(5, 2)` or `5 > 2`.
  125. _.gt(_, 2)(5);
  126. // ➜ true
  127. ```
  128. ## Chaining
  129. The `lodash/fp` module **does not** convert chain sequence methods. See
  130. [Izaak Schroeder’s article](https://medium.com/making-internets/why-using-chain-is-a-mistake-9bc1f80d51ba)
  131. on using functional composition as an alternative to method chaining.
  132. ## Convert
  133. Although `lodash/fp` & its method modules come pre-converted, there are times
  134. when you may want to customize the conversion. That’s when the `convert` method
  135. comes in handy.
  136. ```js
  137. // Every option is `true` by default.
  138. var _fp = fp.convert({
  139. // Specify capping iteratee arguments.
  140. 'cap': true,
  141. // Specify currying.
  142. 'curry': true,
  143. // Specify fixed arity.
  144. 'fixed': true,
  145. // Specify immutable operations.
  146. 'immutable': true,
  147. // Specify rearranging arguments.
  148. 'rearg': true
  149. });
  150. // The `convert` method is available on each method too.
  151. var mapValuesWithKey = fp.mapValues.convert({ 'cap': false });
  152. // Here’s an example of disabling iteratee argument caps to access the `key` param.
  153. mapValuesWithKey(function(value, key) {
  154. return key == 'a' ? -1 : value;
  155. })({ 'a': 1, 'b': 1 });
  156. // => { 'a': -1, 'b': 1 }
  157. ```
  158. Manual conversions are also possible with the `convert` module.
  159. ```js
  160. var convert = require('lodash/fp/convert');
  161. // Convert by name.
  162. var assign = convert('assign', require('lodash.assign'));
  163. // Convert by object.
  164. var fp = convert({
  165. 'assign': require('lodash.assign'),
  166. 'chunk': require('lodash.chunk')
  167. });
  168. // Convert by `lodash` instance.
  169. var fp = convert(lodash.runInContext());
  170. ```
  171. ## Tooling
  172. Use [eslint-plugin-lodash-fp](https://www.npmjs.com/package/eslint-plugin-lodash-fp)
  173. to help use `lodash/fp` more efficiently.