一个关于柯里化函数的实现解析

本篇内容主要参考了如下文章:
从 sum(2)(3) == sum(2, 3) 到实现柯里化函数
JavaScript专题之函数柯里化

柯里化定义

在数学和计算机科学中,柯里化是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术。

一个柯里化函数的实现

在上面两篇文章中,两位做者都比较详细的分析了柯里化函数的实现方式,特别是冴羽的文章中给出了详细的从零开始实现柯里化函数的方法,在这里我就再也不赘述了。segmentfault

在这里我主要针对上面第一个文章中的实现方法,进行一下执行过程的分析。主要是针对其中的具体的一些执行过程单独看代码仍是不甚明了,特此详细执行分析一下以做理解,加深记忆。app

实现方式

这个方式是我感受最容易接受的函数

function curry(fn, argLen, currArgs) {
    return function() {
        console.log("arguments:", arguments, arguments.length)
        var args = [].slice.call(arguments);
        console.log("args:", args)
        // 首次调用时未提供最后一个参数
        if (currArgs !== undefined) {
            args = args.concat(currArgs);
        }
        // 递归出口
        if (args.length == argLen) {
            return fn.apply(this, args);
        } else {
            return curry(fn, argLen, args);
        }
    }
}

function sumOf(a, b, c, d) {
    return a + b + c + d;
}

// 改造普通函数,返回柯里函数
var sum = curry(sumOf, 4);

下面咱们分别来看一下几种不一样的传参方式的执行过程是怎么样的优化

sum(1,2,3,4)

>sum(1,2,3,4)
arguments: Arguments(4) [1, 2, 3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ] 4
args: (4) [1, 2, 3, 4]

sum(1,2,3)(4)

>sum(1,2,3)(4)
arguments: Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ] 3
args: (3) [1, 2, 3]
arguments: Arguments [4, callee: ƒ, Symbol(Symbol.iterator): ƒ] 1
args: [4]

sum(1,2)(3,4)

>sum(1,2)(3,4)
arguments: Arguments(2) [1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ] 2
args: (2) [1, 2]
arguments: Arguments(2) [3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ] 2
args: (2) [3, 4]

经过上面针对几种传参方式的执行过程的分析,咱们能够清楚地看出其中一些关键变量的内容,这样就让咱们可以清楚地理解了柯里化函数的执行过程this

我的优化

针对上面的执行方式,咱们能够看出除了须要被柯里化的函数外,还须要根据这个函数的参数数量传入对应的数量值,这个并非那么的方便。不妨改进一下code

function curry(fn, currArgs) {
    return function() {
        console.log("arguments:", arguments, arguments.length)
        var args = [].slice.call(arguments);
        console.log("args:", args)
        // 首次调用时未提供最后一个参数
        if (currArgs !== undefined) {
            args = args.concat(currArgs);
        }
        // 递归出口
        if (args.length == fn.length) {
            return fn.apply(this, args);
        } else {
            return curry(fn, args);
        }
    }
}

这里咱们经过利用length 属性指明函数的形参个数,来获取被柯里化函数的参数数量,这样就不须要咱们在额外传入了。可是此时须要注意的是,被柯里化的函数的参数不能有默认值,否则的话,length属性就没有意义了。因此这个方式也不是完美的。递归

小结

简单来讲,实现柯里化函数的方式基本都会须要根据参数以及递归方式来实现,这样才能让咱们经过拆分参数的方式来调用一个多参数的函数方法。这样的好处是减小重复传递不变的部分参数,将柯里化后的callback参数传递给map, filter等函数ip

var persons = [{name: 'kevin', age: 11}, {name: 'daisy', age: 24}]

let getProp = _.curry(function (key, obj) {
    return obj[key]
});
let names2 = persons.map(getProp('name'))
console.log(names2); //['kevin', 'daisy']

let ages2 = persons.map(getProp('age'))
console.log(ages2); //[11,24]

可是也不得不认可,这是个很是高阶的用法,普通的开发场景中不多会被使用,毕竟理解并非那么的简单。开发

相关文章
相关标签/搜索