https://www.educative.io/courses/functional-programming-patterns-with-ramdajs/m7wP8OjrvxA

  1. const bobo = {
  2. firstName: 'Bobo',
  3. lastName: 'Flakes'
  4. };
  5. const result = upperAndReverseFirstName(bobo);
  6. console.log({ result });
  7. //{ result: 'OBOB' }
  1. const getFirstName = (user) => user.firstName;
  2. const uppercaseString = (string) => string.toUpperCase();
  3. const reverseString = (string) => string
  4. .split('')
  5. .reverse()
  6. .join('');
  7. const upperAndReverseFirstName = (user) => {
  8. const name = getFirstName(user);
  9. const uppercasedName = uppercaseString(name);
  10. return reverseString(uppercasedName);
  11. };
  1. const users = [{
  2. firstName: 'Bobo',
  3. lastName: 'Flakes'
  4. }, {
  5. firstName: 'Lawrence',
  6. lastName: 'Shilling'
  7. }, {
  8. firstName: 'Anon',
  9. lastName: 'User'
  10. }];
  11. // ['OBOB', 'ECNERWAL', 'NONA']
  1. const getFirstName = (user) => user.firstName;
  2. const uppercaseString = (string) => string.toUpperCase();
  3. const reverseString = (string) => string
  4. .split('')
  5. .reverse()
  6. .join('');
  7. const upperAndReverseFirstName = (user) => {
  8. const name = getFirstName(user);
  9. const uppercasedName = uppercaseString(name);
  10. return reverseString(uppercasedName);
  11. };
  12. const upperAndReverseFirstNames = (users) => {
  13. return users.map(upperAndReverseFirstName);
  14. }

链式调用

Since all three steps deal with a string, we can use method chaining:

  1. const upperAndReverseFirstName = (user) => {
  2. return user.firstName
  3. .toUpperCase()
  4. .split('')
  5. .reverse()
  6. .join('');
  7. };
  8. const result = upperAndReverseFirstName({
  9. firstName: 'Bobo'
  10. });
  11. console.log({ result });

This solution’s a good example of composition and works fine.
It’s a bit limited, however.
We’d likely find uppercasing and reversing strings useful somewhere else in our app! How can we better share that functionality?

分解组合

Breaking It Up #

Our steps can lead to three functions instead:

  1. getFirstName
  2. uppercaseString
  3. reverseString ```javascript const getFirstName = (user) => user.firstName; const uppercaseString = (string) => string.toUpperCase(); const reverseString = (string) => string .split(‘’) .reverse() .join(‘’);

const upperAndReverseFirstName = (user) => { const name = getFirstName(user); const uppercasedName = uppercaseString(name);

return reverseString(uppercasedName); };

const result = upperAndReverseFirstName({ firstName: ‘Bobo’ });

console.log({ result });

  1. Now we have upperAndReverseFirstName and all the pieces its composed of. Any other function can import the piece it needs, without hauling in everything else.<br />And if the requirements of a step change, we can just change the function responsible for that step without breaking the chain.
  2. ```javascript
  3. const upperAndReverseFirstNames = (users) => {
  4. return users.map(upperAndReverseFirstName);
  5. };

使用Ramda

  1. //users.json
  2. [
  3. {
  4. "firstName": "Bobo",
  5. "lastName": "Flakes"
  6. },
  7. {
  8. "firstName": "Lawrence",
  9. "lastName": "Shilling"
  10. },
  11. {
  12. "firstName": "Anon",
  13. "lastName": "User"
  14. }
  15. ]
  1. const upperAndReverseFirstNames = (users) => {
  2. return users.map(upperAndReverseFirstName);
  3. };
  4. import { map } from 'ramda';
  5. import users from './users.json';
  6. const result = map(upperAndReverseFirstName, users);
  7. console.log({ result });

Not much. In fact, it’s more complicated because we’re importing map instead of just using the built-in array method.
But here’s something Array.map can’t do…

万物柯里化 预加载函数

Curried functions can take some parameters now, and others later by returning a function.

  1. import { map } from 'ramda';
  2. import users from './users.json';
  3. const upperAndReverseFirstNames = map(upperAndReverseFirstName);
  4. const result = upperAndReverseFirstNames(users);
  5. console.log({ result });

无值函数 更短(声明式+高阶函数+柯里化+不需要规定参数值+过程和值无关) Point-Free

Also, notice that the mention of a user parameter has been eliminated. Those two functions don’t explicitly say the data they’re operating on. We’ve given them pretty good variable names so we know exactly what’s happening, but do you see any parameters being specified?
This is a style enabled by HOFs and currying called point-free and it can be beautiful.

Point-free functions don’t show their arguments, making them even briefer than their pointed counterparts. This is nice and short

因为无需参数 所以更简短 更好

  1. const upperAndReverseFirstNames = (users) => {
  2. return users.map(upperAndReverseFirstName);
  3. };
  1. const upperAndReverseFirstNames = map(upperAndReverseFirstName);

数据最后 Data Last (声明式+无值)

Ramda’s functions take their data last, making point-free as easy as possible.

The last gem to gaze at is the ordering of map’s arguments. See how the users are supplied after the mapping function?

  1. // users come first
  2. users.map(upperAndReverseFirstName);
  3. // users come last
  4. map(upperAndReverseFirstName, users)

By design Ramda’s functions are curried and take the data last, allowing for the best point-free, declarative JavaScript possible.
You can combine functions until you’re ready for liftoff. Then when the data finally arrives, watch your pipeline soar like a rocket.