JS中的 偏函数 和 柯里化

栏目: JavaScript · 发布时间: 5年前

内容简介:在计算机科学中,偏函数应用 是指将一些参数固定到一个函数,产生另一个较小的函数的过程。举个例子:基于这个函数,我们利用

什么是偏函数

在计算机科学中,偏函数应用 是指将一些参数固定到一个函数,产生另一个较小的函数的过程。

举个例子:

// 我们创建了一个做 乘法运算 的函数
function mult(a, b) {
    return a * b;
};复制代码

基于这个函数,我们利用 bind 创造一个新的函数 double

let double = mult.bind(null, 2);

console.log( double(3) );  // mult(2, 3) = 6;
console.log( double(4) );  // mult(2, 4) = 8;
console.log( double(5) );  // mult(2, 5) = 10; 复制代码

mult.bind(null, 2) 创造了一个新函数 double ,传递调用到 mult 函数,以 nullcontext2 为第一个参数。其他参数等待传入。

这就是 偏函数应用 —— 我们创造了一个新函数,同时将部分参数替换成特定值。

什么时候使用偏函数

刚刚我们基于 mult 创建了一个新的函数 double ,这里我们再创建一个新的函数 triple

let triple = mult.bind(null, 3);

console.log( triple(3) );  // mult(3, 3) = 9;
console.log( triple(4) );  // mult(3, 4) = 12;
console.log( triple(5) );  // mult(3, 5) = 15;复制代码

使用 偏函数 ,我们能够从中受益的是:我们创建了一个独立的非匿名函数( doubletriple )。我们可以使用它,而不需要每次都传入第一个参数,因为 bind 帮我们搞定了。

在其他的场景中,当我们有一个非常通用的函数,并且想要方便地获取它的特定变体,偏函数也是非常有用。

举个例子,我们拥有函数 post(signature, api, data) 。在调用请求方法的时候有着相同的用户签名,这里我们想要使用它的偏函数变体: post(api, data) ,表明该请求发送自同一用户签名。

什么是柯里化

有时候人们会把 偏函数应用 和另外一个名为 柯里化 的东西混淆,但那的确是另外一个和函数有关的有趣技术。

函数式编程语言 和 其他许多语言 中,柯里化(currying)提供了一种自动管理参数如何传递给函数和异常的方法。

简单来说, currying   是一项将一个调用形式为 f(a, b, c) 的函数转化为调用形式 f(a)(b)(c) 的技术。

举个例子:

function currying(fn) {
    return function(a) {
        return function(b) {
            return fn(a, b);
        };
    };
}

// 用法
function sum(a + b) {
    return a + b;
}

let carriedSum = currying(sum);

console.log( carriedSum(1)(2) );  // 3复制代码

从上面的例子可以看到, carrying 的实现就是一系列的封装。

  1.   currying(fn) 的结果就是一层封装 function(a)
  2. 当它被调用,就像 carriedSum(1) 这样,它的参数被保存到 词法环境 中,然后返回一层新的封装 function(b)
  3. 然后 carriedSum(1)(2) 调用 function(b) ,传入参数 2 ,它将调用传递给初始的多参数函数 sum

结合之前的 偏函数  知识,我们可以看到, sum 函数在 柯里化 之后,逐个传递参数的时候返回的那一层封装:其实就是 sum 函数 的 偏函数变体

这可能也是大家容易将这个两个概念搞混的原因之一吧。

高级柯里化

高级的柯里化同时允许 函数正常调用获取偏函数

我们可以实现一下 高级的柯里化:

function currying(fn) {
    return function curried(...args) {
        if(args.length>=fn.length) {
            // 传入的实参长度 >= 初始函数形参长度 的时候,则直接执行初始函数
            return fn.apply(this, args);
        } else {
            // 否则 得到一个 偏函数,递归carried方法,直到获得所有参数后,直接执行
            return function(...args2) {
                return curried.apply(this, args.concat(args2));
            }
        }
    }
}

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

let curriedSum = currying(sum);

// 常规调用
console.log( curriedSum(1, 2, 3) );  // 6

// 得到 curriedSum(1)的偏函数,然后用另外两个参数调用它
console.log( curriedSum(1)(2, 3) );  // 6

// 完全柯里化调用
console.log( curriedSum(1)(2)(3) );  // 6复制代码

柯里化的目的是什么?

从上面的 高级柯里化 实现的例子中可以发现:

  1.   sum 函数 在 柯里化 之后对于使用并没有任何影响,仍然可以被正常调用。
  2.  在很多情况下,我们可以更方便的生成 偏函数 变体,可以更灵活的被我们使用。

总得来说, 柯里化的目的 就是在不影响 初始函数 的调用形式的情况下,更方便的让我们获得初始函数的 偏函数 变体。

最后,欢迎各位小伙伴留言,相互讨论。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Hadoop in Action

Hadoop in Action

Chuck Lam / Manning Publications / 2010-12-22 / USD 44.99

HIGHLIGHT Hadoop in Action is an example-rich tutorial that shows developers how to implement data-intensive distributed computing using Hadoop and the Map- Reduce framework. DESCRIPTION Hadoop i......一起来看看 《Hadoop in Action》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

随机密码生成器
随机密码生成器

多种字符组合密码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具