JS专题之函数柯里化
栏目: JavaScript · 发布时间: 5年前
内容简介:#### 前言在计算机科学中,柯里化(英语: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); } } }
三、应用场景
函数柯里化的好处有几个:
- 参数复用;
- 提前返回;
- 延迟计算/运行。
函数柯里化允许和鼓励你分隔复杂功能变成更小更容易分析的部分。这些小的逻辑单元显然是更容易理解和测试的,然后你的应用就会变成干净而整洁的组合,由一些小单元组成的组合。
文章开篇的 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专题之函数柯里化》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。