1,实现柯里 curry

1)柯里化使用

  1. const R = require('ramda');
  2. const func = R.curry((a, b) => [ a, b ]);
  3. console.log(func(1, 2)); // 直接使用函数,传两个参数,可以转为顺序的数组
  4. console.log(func(1)(2)); // 柯里化函数,传一部分参数,还会返回函数,再继续传参数
  5. console.log(func(R.__, 2)(1)); // ramda有一个__ 占位符,表示这个参数可以等下再传

2)实现柯里函数

  1. // 自己修改书上的错误实现
  2. function _curryN(fn, args) {
  3. const length = fn.length;
  4. return (...arg) => {
  5. console.log('arg', arg);
  6. args = args.concat(arg);
  7. if (args.length === length) {
  8. return fn(...args);
  9. }
  10. return _curryN(fn, args);
  11. };
  12. }
  13. function curry(fn) {
  14. return _curryN(fn, []);
  15. }
  16. const func2 = curry((a, b, c) => [ a, b, c ]);
  17. // console.log(func2(1, 2, 3));
  18. console.log(func2(1)(2)(3));

注意:

  1. 访问函数的 .length 可以获取函数需要传递的参数个数
  2. 扩展符在做参数的时候,可以把之前的类数组转化成一个数组,但是在函数中的时候,args就表示这个转化以后的数组,如果再用扩展符去获取,就会导致args 变为原来的数值,而不是数组
  3. 所有参数传递完毕才调用fn。 ```javascript // 网上搜索答案 function _curryN(fn, args) { const length = fn.length; return function() { const newArgs = args.concat(Array.prototype.slice.call(arguments)); return newArgs.length < length ? _curryN.call(this, fn, newArgs) : fn.apply(this, newArgs); }; }

function curry(fn) { return _curryN(fn, []); }

const func2 = curry((a, b, c) => [ a, b, c ]);

console.log(func2(1, 2, 3)); console.log(func2(1)(2)(3));

  1. 注意:
  2. 1. 函数的 arguments 属性的数据类型是对象
  3. 1. Array.prototype.slice.call(arguments) 把类数组的参数对象转化为数组
  4. 1. call apply 的使用一样,都是把后边的参数传给前面的函数,但是需要使用 this 的作用域
  5. 1. 如果需要使用到this的指向,就需要使用 function定义函数,而不能使用 箭头函数
  6. 1. 如果递归函数第一层调用不需要参数,但是第二层调需要参数,可以在外面定义一个函数,传一个参数
  7. 1. func2(1)(2)(3) 表示之前的函数返回一个函数,然后再继续调用,调用的循序是从右到左,既<br />3 -> 2 -> 1
  8. <a name="PnuXk"></a>
  9. ## 2,函数式编程 —— compose
  10. 情景:如果函数的嵌套比较多,a( b( c( d( e( f( g(1) ) ) ) ) ) ) 函数调用比较多层的情况,可以使用compose(题外话:其实Lisp语言中就存在函数的多层调用)<br />可以看到 上面函数的调用放向是 g -> f -> e -> d -> c -> b -> a 从右到左,compose的调用放向就是从右到左,同时ramda 还提供了 pipe 函数,可以从左到右调用
  11. 1ramda compose pipe 的使用
  12. ```javascript
  13. const notInGlobal = R.not(check(global)); // R.not() 表示函数的结果取反
  14. const notInGlobal = R.compose(R.not, check(global)) // R.compose 从右到左
  15. const notInGlobal = R.pipe( check(global), R.not) // R.pipe 从左到右

2)实现compose函数

  1. const compose = (...fns) => fns.reverse().reduce((a, b) => (...arg) => b(a(arg)));
  2. function compose(...funs) {
  3. if (funs.length === 0) {
  4. return arg => arg;
  5. }
  6. if (funs.length === 1) {
  7. return funs[0];
  8. }
  9. return funs.reverse().reduce((a, b) => function(...arg) {
  10. console.log('arg', arg); // 看arg 是什么
  11. return b(a(arg));
  12. });
  13. }
  14. function isTrue() {
  15. return false;
  16. }
  17. const fn2 = compose(R.not, isTrue);
  18. console.log('fn2 ---', fn2());
  19. console.log('fn2 ---', fn2(121)); // arg 是 fn2 传入的参数

注意:

  1. compose函数的重点就是传入的函数数组是从右向左执行,所以就是把参数 翻转,在堆叠执行
  2. (…fns) 在参数中使用箭头函数可以把传入的参数组合成一个数组为fns。
  3. Array.prototype.reduce( (a, b) => a + b) reduce传入的需要是一个函数,表示堆叠的加法器,举的例子表示把两个数相加,代码中 reduce( (a, b) => (…arg) => b(a(arg))) 表示把函数一层一层的调用
  4. arg 是最外层函数传入的参数

3,函数式编程基本概念

1,什么是函数式编程
面向对象编程和函数编程对比

  1. // 面向对象编程
  2. var Flock = function(n) {
  3. this.seagulls = n;
  4. };
  5. Flock.prototype.conjoin = function(other) {
  6. this.seagulls += other.seagulls;
  7. return this;
  8. };
  9. Flock.prototype.breed = function(other) {
  10. this.seagulls = this.seagulls * other.seagulls;
  11. return this;
  12. };
  13. var flock_a = new Flock(4);
  14. var flock_b = new Flock(2);
  15. var flock_c = new Flock(0);
  16. var result = flock_a.conjoin(flock_c)
  17. .breed(flock_b)
  18. .conjoin(flo ck_a.breed(flock_b))
  19. .seagulls;
  1. // 函数式编程
  2. var conjoin = function(flock_x, flock_y) {
  3. return flock_x + floc k_y
  4. };
  5. var breed = function(flock_x, flock_y) {
  6. return flock_x * flock_ y
  7. };
  8. var flock_a = 4;
  9. var flock_b = 2;
  10. var flock_c = 0;
  11. var result = conjoin(breed(flock_b,
  12. conjoin(flock_a, flock_c)),
  13. breed(flock_a, flock_b));

自己的理解:
1)函数里面不定义新的变量,所有的变量从参数中获取
2)让函数中的变量看起来更清晰

2,纯函数
纯函数也是需要,函数中所需要的参数从参数中传递过来,即使在一个函数中调用其他的两个函数,这两个函数的参数也是需要从主函数的参数中传递过来

  1. // 不纯的
  2. var signUp = function(attrs) {
  3. var user = saveUser(attrs);
  4. welcomeUser(user);
  5. };
  6. var saveUser = function(attrs) {
  7. var user = Db.save(attrs);
  8. ...
  9. };
  10. var welcomeUser = function(user) {
  11. Email(user, ...);
  12. ...
  13. };
  14. // 纯的
  15. var signUp = function(Db, Email, attrs) {
  16. return function() {
  17. var user = saveUser(Db, attrs);
  18. welcomeUser(Email, user);
  19. };
  20. };
  21. var saveUser = function(Db, attrs) {
  22. ...
  23. };
  24. var welcomeUser = function(Email, user) {
  25. ...
  26. };