手写柯里化,实现柯里化

Posted m2maomao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手写柯里化,实现柯里化相关的知识,希望对你有一定的参考价值。

柯里化,就是将接受多个参数的函数变换成接受一个单一参数的函数。

闭包的应用场景就是函数科里化。(延长变量的生命周期)

参数复用,利用闭包将函数的参数储存起来,等参数达到一定数量时执行函数

 

fn(x, y) -> fn(x)(y)

上面的代码就是把fn函数做成嵌套函数,外层函数的返回值是内层函数。外层函数调用完之后,能接着调用。

涉及到的概念,高阶函数,闭包,call/apply,argument。

科里化执行函数的核心是:有参数传入时,收集参数,返回函数;收集参数完毕,执行,返回值。

 

第一种方法:比较容易理解

fn指的是源处理函数,如sum,currArgs 是调用curry时传入的参数列表,比如(1,2)(3)

function curry(fn, currArgs)return function()
        let args =  Array.from(arguments);
        // 首次调用的时候,若未提供最后一个参数currArgs,则不用进行args拼接
        if(currArgs !== undefined)
            args = args.concat(currArgs)
        
        // 递归调用,判断args的个数,是否与fn的参数相对能,相等了就可以把参数都传给fn,进而输出;否则继续递归调用,一直到两者相等。
        if(args.length < fn.length)  // fn.length 是fn函数参数的个数
            return curry(fn, args);
        
        return fn.apply(null, args);
    

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


const fn = curry(sum);

fn(1, 2, 3); // 6
fn(1, 2)(3); // 6

 

  第二种方法,

const curry = (fn) => 
    if (typeof fn !== \'function\') 
        console.log(\'function\')
      throw Error(\'No function provided\')
    

    return function curriedFn (...args) 
        // 括号里扩展运算符的作用,是把传过来的参数变成数组。
        // 等同于 args = Array.from(arguments);

      if (fn.length > args.length)   // 未达到触发条件,继续收集参数
        return function () 
            /**
             * [].slice.call(arguments) 将类数组转化为数组,
             * 上一行代码的原理是call会将slice方法内部的this就会被替换成arguments,
             * 并循环遍历arguments,复制到新数组返回,这样就得到了一个复制arguments类数组的数组对象。
             * 等同 Array.from(arguments)
             * 也等同于 Array.prototype.slice.call(arguments)
             */
          return curriedFn.apply(null, args.concat(Array.from(arguments)))
        
      
    //   apply:方法能劫持另外一个对象的方法,继承另外一个对象的属性.
    // Function.apply(obj,args)方法能接收两个参数
    // obj:这个对象将代替Function类里this对象
    // args:这个是数组,它将作为参数传给Function(args-->arguments)       
      return fn.apply(null, args)
    //   args作为参数,被fn调用。
    
  

  const multiply = (x, y, z) => x*y*z;
  const curryMul = curry(multiply);
  const result = curryMul(1)(2)(3); // 1*2*3 = 6
  console.log(\'result\',result)

JS柯里化

前两天参加一个面试被问了这么一个题目,如何实现add(1)(2);  //3

当时没答出来,那边告诉我这是JS柯里化,回来查了一下。资料如下:

闭包和柯里化都是 JavaScript 经常用到而且比较高级的技巧,所有的函数式编程语言都支持这两个概念,因此,我们想要充分发挥出 JavaScript 中的函数式编程特征,就需要深入的了解这两个概念,闭包事实上更是柯里化所不可缺少的基础。

柯里化的概念

闭包的我们之前已经接触到,先说说柯里化。柯里化就是预先将函数的某些参数传入,得到一个简单的函数,但是预先传入的参数被保存在闭包中,因此会有一些奇特的特性。比如:
var adder = function(num){
    return function(y){
        return num + y;
    }
}
var inc = adder(1);
var dec = adder(-1);

这里的 inc/dec 两个变量事实上是两个新的函数,可以通过括号来调用,比如下例中的用法:
//inc, dec现在是两个新的函数,作用是将传入的参数值(+/-)1
print(inc(99));//100
print(dec(101));//100
print(adder(100)(2));//102
print(adder(2)(100));//102

柯里化的应用

根据柯里化的特性,我们可以写出更有意思的代码,比如在前端开发中经常会遇到这样的情况,当请求从服务端返回后,我们需要更新一些特定的页面元素,也就是局部刷新的概念。使用局部刷新非常简单,但是代码很容易写成一团乱麻。而如果使用柯里化,则可以很大程度上美化我们的代码,使之更容易维护。我们来看一个例子:
//update会返回一个函数,这个函数可以设置id属性为item的web元素的内容
function update(item){
    return function(text){
        $("div#"+item).html(text);
    }
}
//Ajax请求,当成功是调用参数callback
function refresh(url, callback){
    var params = {
        type : "echo",
        data : ""
    };
    $.ajax({
        type:"post",
        url:url,
        cache:false,
        async:true,
        dataType:"json",
        data:params,
        //当异步请求成功时调用
        success: function(data, status){
            callback(data);
        },
        //当请求出现错误时调用
        error: function(err){
            alert("error : "+err);
        }
    });
}
refresh("action.do?target=news", update("newsPanel"));
refresh("action.do?target=articles", update("articlePanel"));
refresh("action.do?target=pictures", update("picturePanel"));

其中,update 函数即为柯里化的一个实例,它会返回一个函数,即:
    update("newsPanel") = function(text){
        $("div#newsPanel").html(text);
    }

由于 update(“newsPanel”)的返回值为一个函数,需要的参数为一个字符串,因此在refresh 的 Ajax 调用中,当 success 时,会给 callback 传入服务器端返回的数据信息,从而实现 newsPanel 面板的刷新,其他的文章面板 articlePanel,图片面板 picturePanel的刷新均采取这种方式,这样,代码的可读性,可维护性均得到了提高。

以上是关于手写柯里化,实现柯里化的主要内容,如果未能解决你的问题,请参考以下文章

JS高级——纯函数柯里化(手写自动柯里化函数)组合函数(手写自动组合函数)

6.手写函数柯里化工具函数并理解其应用场景和优势

JS中的柯里化及精巧的自动柯里化实现

面试官:什么是函数柯里化?能手写实现吗?

柯里化函数

函数柯里化