2020-08-14 理解 javascript 函数中的 curry 

理解 javascript 函数中的 curry 

          函数柯里化: 所谓函数柯里化就是把一个函数的多个传参变成多个函数的单个传参。 函数的柯里化,是 Javascript 中函数式编程的一个重要概念。它返回的,是一个函数的函数。其实现方式,需要依赖参数以及递归,通过拆分参数的方式,来调用一个多参数的函数方法,以达到减少代码冗余,增加可读性的目的。fn(a,b,c)  变成  curry(a)(b)(c)

         本质: 实现多个参数合并为一个参数数组,apply  调用 函数。

f1 传参a 中 return 一个匿名函数 传参b , 匿名函数在在return 一个 函数执行。这样的好处是可实现参数的复用。

function sum(a, b, c) {
    console.log(a + b + c);
}

const fn = curry(sum);

fn(1, 2, 3); // 6   ==>sum args: [3,2,1]
fn(1, 2)(3); // 6   ==>sum args: [3,1,2]
fn(1)(2, 3); // 6   ==>sum args: [2,3,1]
fn(1)(2)(3); // 6   ==>sum args: [3,2,1]
function curry (fn, currArgs) {
  return function() {
      let args = [].slice.call(arguments);
      console.log('ARGS: ',args);
      // 首次调用时,若未提供最后一个参数currArgs,则不用进行args的拼接
      if (currArgs !== undefined) {
          args = args.concat(currArgs);
      }

      // 递归调用 fn,length  代表函数传参个数。
      if (args.length < fn.length) {
        
          return curry(fn, args);
      }

      // 递归出口
      return fn.apply(null, args);
  }
}

curry 第一个传参为函数sum ,第二个传参为fn (fn 代表被curry 函数包裹传参fn 后返回的函数)函数的参数currArgs.

后可以通过 fn(1)(2)(3)  传参,curry 函数通过递归实现了后面参数与currArgs拼接,拼接后的 参数个数与fn 函数传参相同,顺序由不同的传参方式不同而不同。

 

loadash.js 中正是运用柯里化函数。用于快速返回数组中某一个属性的值。

const persons = [
    { name: 'kevin', age: 4 },
    { name: 'bob', age: 5 }
];

// 这里的 curry 函数,之前已实现
const getProp = curry(function (obj, index) {
    const args = [].slice.call(arguments);
    return obj[args[args.length - 1]];
});

const ages = persons.map(getProp('age')); // [4, 5]
const names = persons.map(getProp('name')); // ['kevin', 'bob']

由于map 函数的 回调中自动传递相关参数,相当于 getProp('age')(currentValue,index,arr)  ==> 参数 【curentValue,index,arr,age】因此,fn 的传参个数必须大于等于2,才能 return obj[attr]

ARGS:  [ 'age' ]  no currentArgs

ARGS:  [ { name: 'kevin', age: 4 },0, [ { name: 'kevin', age: 4 }, { name: 'bob', age: 5 } ] ]

concat args:  [ { name: 'kevin', age: 4 },0, [ { name: 'kevin', age: 4 }, { name: 'bob', age: 5 } ], 'age' ]

ARGS:  [ { name: 'bob', age: 5 },1, [ { name: 'kevin', age: 4 }, { name: 'bob', age: 5 } ] ]

concat args:  [ { name: 'bob', age: 5 },1,[ { name: 'kevin', age: 4 }, { name: 'bob', age: 5 } ], 'age' ]

var new_array = arr.map(function callback(currentValue[, index[, array]]) {
    // Return element for new_array
}[, thisArg]);

对于优化比较耗时的计算,可以利用缓存,利用闭包,将结果缓存到内存中。

嵌套在函数作用域中的函数,称为闭包函数。该作用域称为闭包环境;通过闭包函数可以访问闭包环境所在的作用域变量与形参,此利用了javascript 的变量回收机制,一个函数调用时开辟空间,函数结束调用,释放空间,垃圾回收机制释放调用结束的函数时 ,发现函数的变量正在其他地方调用,这些变量不会释放,永久保存在内存。只有退出程序,才会释放。

function memoizeFunction(func) {
    const cache = {};
    return function() {
        let key = arguments[0];
        if (cache[key]) {
            return cache[key];
        } else {
            const val = func.apply(null, arguments);
            cache[key] = val;
            return val;
        }
    };
}

const fibonacci = memoizeFunction(function(n) {
    return (n === 0 || n === 1) ? n : fibonacci(n - 1) + fibonacci(n - 2);
});

console.log(fibonacci(100)); // 输出354224848179262000000

JavaScript 经典面试题 

// 实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;

function add() {
    // 第一次执行时,定义一个数组专门用来存储所有的参数
    var _args = Array.prototype.slice.call(arguments);

    // 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
    var _adder = function() {
        _args.push(...arguments);
        return _adder;
    };

    // 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
    _adder.toString = function () {
        return _args.reduce(function (a, b) {
            return a + b;
        });
    }
    return _adder;
}

add(1)(2)(3)                // 6
add(1, 2, 3)(4)             // 10
add(1)(2)(3)(4)(5)          // 15
add(2, 6)(1)                // 9

 偏函数: 固定一个函数的一个或多个参数,也就是将一个n元函数转换成一个n-x元函数。

使用场景

  • 动态生成函数
  • 减少参数
  • 延迟计算
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值