背景

柯里化(Currying)是一种关于函数的高阶技术。它不仅被用于 JavaScript,还被用于其他编程语言。函数柯里化又叫部分求值,维基百科中对柯里化 (Currying) 的定义为:

在数学和计算机科学中,柯里化是一种将使用多个参数的函数转换成一系列使用一个参数的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

用大白话来说就是只传递给函数一部分参数来调用它,让它返回一个新函数去处理剩下的参数。使用一个简单的例子来介绍下,最常用的就是 add 函数了。

// add method
const add = (...args) => args.reduce((a, b) => a + b);

// 传入多个参数,执行 add 函数
add(1, 2) // 返回 3

// 假设我们实现了一个 currying 函数,支持一次传入一个参数
let sum = currying(add);
let addCurryOne = sum(1);
addCurryOne(2) // 返回 3
addCurryOne(3) // 返回 4

使用场景

柯里化是一种函数的转换,它是指将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)(c)。柯里化不会调用函数。它只是对函数进行转换。 在平常工作中主要使用场景如下:

  • 1、延迟计算(部分求和、bind 函数)

  • 2、动态创建函数(添加监听 addEvent、惰性函数)

  • 3、参数复用(Function.prototype.call.bind(Object.prototype.toString))

JS中的函数科里化

可以对比下haskell这种天然的函数式语言,js里的珂里化实在是残缺不全...但是利用珂里化这种参数对应函数的思想,结合js的闭包特性,来实现良好的封装。 举个例子:js中最常见的dom的插入和删除。 普通写法:变量都在外部,不能确保每个remove操作都“正确”的

var append = function (parent, child) {
    parent.appendChild(child);
}
var remove = function (dom) {
    dom.remove();
}
//插入 remove(child); //删除
append(parent, child); 

文艺写法:确保了每个删除操作都会删除插入的节点。

var append = function (parent, child) {
    parent.appendChild(child);
    return function () {
        child.remove();
    }
}

//或者是这种,point free风格 
var append2 = function (parent, child) {
    parent.appendChild(child);
    return child.remove.bind(child);
}
//插入一个节点,同时返回所插入的节点的删除操作。 remove(); //删除。
var remove = append(parent, child);

总结一下就是说,这种以函作为主体,确保了函数之间不会相互干扰,尤其是在复杂的前端工程下,每一处的代码越“安全”,越独立,越能更好的拓展功能和排查问题。

经典面试题:add(1)(2)(3)

function add(seed) {
    function retVal(later) {
        return add(seed + later);
    }
    retVal.toString = function () {
        return seed;
    };
    return retVal;
}
console.log(add(1)(2)(3).toString()); // 6

add函数返回闭包retVal,在retVal中又继续调用add,最终我们可以写成add(1)(2)(3)(...)这样柯里化的形式。 每调用一次add函数,都会返回retValue函数;调用retValue函数会调用add函数,然后还是返回retValue函数,所以调用add的结果一定是返回一个retValue函数。add函数的存在意义只是为了提供闭包,这个类似的递归调用每次调用add都会生成一个新的闭包。

总结

优点:

  • 参数复用
  • 提前返回
  • 延迟计算/运行

缺点:

  • 函数柯里化可以用来构建复杂的算法 和 功能, 但是滥用也会带来额外的开销。从上面实现部分的代码中,可以看到,使用柯里化函数,离不开闭包, arguments, 递归。
  • 闭包,函数中的变量都保存在内存中,内存消耗大,有可能导致内存泄漏。
  • 递归,效率非常
  • arguments, 变量存取慢,访问性很差

我个人觉得柯里化并非是必须的,而且不熟悉的同学阅读起来可能会遇到麻烦,但是它能帮助我们理解JS中的函数式编程,更重要的是,我们以后在阅读类似的代码时,不会感到陌生。

并非“柯里化”对函数式编程有意义。而是,函数式编程在把函数当作一等公民的同时,就不可避免的会产生“柯里化”这种用法。所以它并不是因为“有什么意义”才出现的。

到此这篇关于JS中函数科里化的背景与应用的文章就介绍到这了,更多相关JS函数科里化应用内容请搜索阿兔在线工具以前的文章或继续浏览下面的相关文章希望大家以后多多支持阿兔在线工具!

点赞(0)

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部