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.  在很多情况下,我们可以更方便的生成 偏函数 变体,可以更灵活的被我们使用。

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

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


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

查看所有标签

猜你喜欢:

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

Introduction to Computation and Programming Using Python

Introduction to Computation and Programming Using Python

John V. Guttag / The MIT Press / 2013-7 / USD 25.00

This book introduces students with little or no prior programming experience to the art of computational problem solving using Python and various Python libraries, including PyLab. It provides student......一起来看看 《Introduction to Computation and Programming Using Python》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换