Skip to content

函数柯里化 #159

@S-T-D

Description

@S-T-D

是什么

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

比如:

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

const curried = curry(add);

curried(1)(2)(3);   // output: 6

add 函数是一个多参数函数,经过柯里化后得到 curried 函数。

curried 函数可以接收一个或多个参数,只有当参数个数达到预定的个数的时候才会执行,否则就将参数保存起来,返回一个函数继续接收后续参数。

 

用途

curry 的用途可以理解为:参数复用。本质上是降低通用性,提高适用性。

重点在于降低通用性,提高适用性。

这似乎与平时的编码规范相违背,一般我们都会尽量提高代码的通用性和复用性,而柯里化却要降低通用性。

 

先看两个例子,例子都来自于参考资料。

// 示意而已
function ajax(type, url, data) {
    var xhr = new XMLHttpRequest();
    xhr.open(type, url, true);
    xhr.send(data);
}

// 虽然 ajax 这个函数非常通用,但在重复调用的时候参数冗余
ajax('POST', 'www.test.com', "name=kevin")
ajax('POST', 'www.test2.com', "name=kevin")
ajax('POST', 'www.test3.com', "name=kevin")

// 利用 curry
var ajaxCurry = curry(ajax);

// 以 POST 类型请求数据
var post = ajaxCurry('POST');
post('www.test.com', "name=kevin");

// 以 POST 类型请求来自于 www.test.com 的数据
var postFromTest = post('www.test.com');
postFromTest("name=kevin");

可以看到复用性和柯里化并不冲突,我们仍然需要一个通用的 ajax 函数,但是在具体特定场景大量试用 ajax 的时候,我们可以通过柯里化来简化代码,简化 ajax 的试用,让其更适合在这里试用。

 

var prop = curry(function (key, obj) {
    return obj[key]
});

var name = person.map(prop('name'));

map 是平时开发高频使用的 API,上述代码对 person 数组进行遍历,取出 name 数组。

在这里,柯里化使我们只需要关注 key 属性,除了取 name,还可以取 person 的任意属性,提高了复用性,并且语义清晰。

 

实现

const curry = (fn) => {
    const curried = (...args) => 
        args.length === fn.length ? 
            fn(...args) : (...args2) => curried(...args, ...args2);
    return curried;
}

实现原理就是:参数个数满足就执行,不满足就先保存,继续返回函数以接收新的参数。

 

参考资料

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions