函数柯里化的意义_javaScript 中的函数柯里化(Currying)简述

什么是柯里化

柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

简单来说,柯里化即是将多参函数转换成一系列的单参函数,其最大特点即只有一个参数,不达到最终目的时返回值都是函数。下面我们举一个简单的加法实现的例子来说明柯里化的特点。

javaScript 实现柯里化函数

对于实现一个加法函数,多参数方式的实现示例:

function add(a, b, c) {

return a + b + c;

}

// 执行

add(1, 2, 3); // 6

柯里化要求只能有一个参数,其实现出来的执行效果应该是这样的:

// 简单实现加法柯里化方法

function add (a) {

var total = a;

return function (b) {

total += b;

return function (c) {

return total += c;

}

}

}

add(1)(2)(3); // 6

这个实现比较简单直接,这就是柯里化函数要求的效果。

ES6 箭头函数实现柯里化

ES6 的箭头函数有一个特点是,单行执行的结果即作为返回值,那么使用箭头函数实现柯里化就变得简洁多了:

const add = a => b => c => a + b + c;

add(1)(2)(3); // 6

参数任意的柯里化函数实现

对于前文加法函数,如果要求参数可以任意多,那么在 JavaScript 中该如何实现呢?

对于这个需求,从执行效果来看,当后续还有参数时,函数返回值应当是一个函数;当后续没有了参数时,函数返回值应当是一个值。那么如果能够让函数返回值既可以作为函数继续传参执行,又可以在取值时输出为值,这个问题就解决了。

回想一下,在 JavaScript 中对象到原始值的转换规则:

当一个对象转换成原始值时,先查看对象是否有 valueOf 方法,如果有并且返回值是一个原始值,那么直接返回这个值,否则没有 valueOf 或返回的不是原始值,那么调用 toString 方法,返回字符串表示。

简单来说,如果对一个对象类型取值,会调用它的 valueOf 或 toString 方法,返回其执行结果。每一个对象都默认有这两个方法的实现。示例:

// 定义函数 fn

function fn() {}

fn.toString(); // 输出:"function fn() {}"

fn.valueOf(); // 输出 function fn() {}

那么,只需要重写这两个方法中的一个,即可实现取值时得到的是我们期望的结果值。我们尝试一下:

function add(a) {

var total = a;

var _fn = function (b) {

total += b;

return _fn;

};

_fn.toString = _fn.valueOf = function () {

return total;

};

return _fn;

}

add(1)(2); // 3

add(1)(2)(3); // 6

add(1)(2)(3)(4); // 10

通用的柯里化实现

function currying(fn) {

// 缓存队列

var _args = [];

return function cb() {

// 不传参数时返回方法的执行

if (arguments.length === 0) {

return fn.apply(this, _args);

}

Array.prototype.push.apply(_args, arguments);

return cb;

}

}

另一种通用实现:

function currying(fn) {

var outerArgs = Array.prototype.slice.call(arguments, 1);

return function() {

var innerArgs = Array.prototype.slice.call(arguments),

finalArgs = outerArgs.concat(innerArgs);

return fn.apply(null, finalArgs);

};

}

使用示例:

var gd = currying(loc,'广东');

var zh = currying(zj,'珠海');

zh('香洲区'); // 广东-珠海-香洲区

zh('高新区'); // 广东-珠海-高新区

gd('广州','越秀区'); // 广东-越秀-越秀区

柯里化函数的作用

柯里化函数在使用上更为简洁,可以帮助你更好的处理和抽象代码的逻辑。参考加法函数 add 的特点,如果每次一传参都是一个流程的执行,那么实现一个柯里化方法,在调用时就很清晰的显示的流程执行的顺序。

根据柯里化的特点,被总结出了如下几个主要作用/优点:

参数复用。

延迟计算/运行。

参数复用

利用柯里化,我们可以固定住其中的部分参数,在调用时这个参数就不需要再次传递,这也就是我们这里说的参数复用。示例:

const local = country => province => city => `${country}-${province}-${city}!`;

const cn = say('China');

const cnHn = say('河南');

const cnGd = sayToMr('广东');

cnHn('信阳'); // China-河南-信阳

greetMiss('珠海'); // China-广东-珠海

利用复用的参数,可以让柯里化的方法具有更高的适用性。

延迟计算

使用通用的实现 currying 方法来实现加法函数,即可看到延迟计算的效果:

// 原始方法

function add() {

var sum = 0, i, len;

for (i = 0, len = arguments.length; i < len; i++) {

sum += arguments[i];

}

return sum;

}

// 将 add 柯里化

var addCurrying = currying(add);

var add123 = addCurrying(1)(2)(3); // 此时只生成了三个方法存于队列中,并未执行

add123(); // 此时才真正的执行计算

柯里化函数的副作用

柯里化会创建大量的嵌套和闭包,在未执行前都得不到释放,这会导致内存占用变大。但这一般情况下都不会有什么问题,大多数时候 DOM 操作是影响性能的主要因素。关于 js 柯里化函数的性能:

存取 arguments 对象通常要比存取命名参数要慢

使用 fn.apply() 和 fn.call() 要比直接调用 fn() 要慢

创建大量嵌套作用域和闭包会带来内存和速度上的开销

大多数时候 DOM 操作是影响性能的主要因素

相关参考

http://zh.wikipedia.org/wiki/Currying

https://segmentfault.com/a/1190000004589338

http://www.zhangxinxu.com/wordpress/2013/02/js-currying/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值