JS专题之函数柯里化

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

内容简介:#### 前言在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。#### 一、为什么会有函数柯里化?

#### 前言

在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

#### 一、为什么会有函数柯里化?

Currying 的重要意义在于可以把函数完全变成「接受一个参数;返回一个值」的固定形式,这样对于讨论和优化会更加方便。

将关注的重点聚焦到函数本身,而不因冗余的数据参数分散注意力。

有这样的说法,并非柯里化有什么意义,而是,当函数可以作为函数的参数和返回值,成为函数式编程语言后,就会不可避免地产生函数柯里化。

#### 二、具体实现

先来一个简单的 add 函数

function add(x, y) {
    return x + y;
}

add(2, 3);  // 5

重要的概念多说一遍:函数柯里化就是接收多个参数的函数变换为接收一个函数,并返回接收余下参数,最终能返回结果的技术

那么,继续:

function add(x) {
    return function(y) {
        return x + y;
    }
}

add(2)(3);  // 5

所以,曾经的一个函数,因为闭包操作(返回函数并访问了自由变量的行为),变成了多个接收一个参数的函数。

所以简单来讲:函数柯里化就是意图将函数的参数变成一个。让函数可以输入一个值,就返回一个相对应的值,从而实现纯函数化。

为什么函数式编程要求函数必须是纯的,不能有副作用?因为它是一种数学运算,原始目的就是求值,不做其他事情,否则就无法满足函数运算法则了。在函数式编程中,函数就是一个管道(pipe)。这头进去一个值,那头就会出来一个新的值,没有其他作用。

所以良好的编程规范是尽可能让函数块做一个事情,实现可复用性,可维护性。

上面的例子中,如果有很多个参数怎么办,难道一层层嵌套?

我们继续:

function plus(value) {
    "use strict";
    var add = function () {
        var args = [];
        var adder = function adder() {
            Array.prototype.push.apply(args,Array.prototype.slice.apply(arguments))
            return adder;
        }
        adder.toString = function () {
            return args.reduce(function(a, b) {
                return a + b;
            })
        }
        return adder;
    }
    return add()(value);
}

plus(2)(3)(5).toString();  // 10;

上面的代码看起来不那么优雅,如果是减法,我们就得又重新为减法写这么多的代码。像 lodash, underscore 这些 工具 库,都提供了柯里化的工具函数。

我们一起来试着实现:

function curry(fn, args) {
    var length = fn.length;  // 函数参数的长度

    // 闭包保存参数列表
    args = args || [];

    return function() {
        // 获取参数列表。
        var _args = args.slice(0);
        
            Array.prototype.push.apply(_args, Array.prototype.slice.call(arguments))

        if (_args.length < length) {
        // 如果传入的参数列表长度还没有超过函数定义时的参数长度,就 push 新的参数到参数列表中保存起来。
        
            // 自己调用自己,将保存的参数传递到下一个柯里化函数。
            return curry.call(this, fn, _args);
        }
        else {
        // 如果传入的参数列表长度已经超过函数定义时的参数长度,就执行。
            return fn.apply(this, _args);
        }
    }
}

三、应用场景

函数柯里化的好处有几个:

  1. 参数复用;
  2. 提前返回;
  3. 延迟计算/运行。

函数柯里化允许和鼓励你分隔复杂功能变成更小更容易分析的部分。这些小的逻辑单元显然是更容易理解和测试的,然后你的应用就会变成干净而整洁的组合,由一些小单元组成的组合。

文章开篇的 add 函数,假如,每次调用加法有一个初始值会怎样?

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

var addTen = add(10);

var addSix = add(6);

addTen(2)(3);  // 15;

addSix(7)(8);  // 21;

以上代码就实现了参数复用,保存固定参数的函数。

看一个经典的例子:

元素绑定事件监听器:

var addEvent = function(el, type, fn, capture) {
    if (window.addEventListener) {
        el.addEventListener(type, function(e) {
            fn.call(el, e);
        }, capture);
    } else if (window.attachEvent) {
        el.attachEvent("on" + type, function(e) {
            fn.call(el, e);
        });
    } 
};

以上代码是为了兼容 IE 浏览器对 DOM 事件绑定做的函数封装。

问题在于,每次对 DOM 元素进行事件绑定时,函数内部都会走一遍 if else。那么用函数柯里化就能实现 提前返回

var addEvent = (function(){
    if (window.addEventListener) {
        return function(el, sType, fn, capture) {
            el.addEventListener(sType, function(e) {
                fn.call(el, e);
            }, (capture));
        };
    } else if (window.attachEvent) {
        return function(el, sType, fn, capture) {
            el.attachEvent("on" + sType, function(e) {
                fn.call(el, e);
            });
        };
    }
})();

总结

函数柯里化是“函数是一等公民”的编程语言环境形成的编程风格,利用了函数能作为参数一级返回值以及利用了闭包保存变量的特点,是将多个参数的函数转换为接收一个参数,最后返回结果的技术。

欢迎关注我的个人公众号“谢南波”,专注分享原创文章。

JS专题之函数柯里化


以上所述就是小编给大家介绍的《JS专题之函数柯里化》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Web Caching

Web Caching

Duane Wessels / O'Reilly Media, Inc. / 2001-6 / 39.95美元

On the World Wide Web, speed and efficiency are vital. Users have little patience for slow web pages, while network administrators want to make the most of their available bandwidth. A properly design......一起来看看 《Web Caching》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具