本文转自:https://segmentfault.com/a/1190000003733107

函数柯里化是指参数逐渐求值的过程。

我觉得它是:降低通用性,提高专用性。

通常,柯里化是这样的过程,“如果你固定某些参数,你将得到接受余下参数的一个函数”。所以对于有两个变量的函数y^x,如果固定了 y=2,则得到有一个变量的函数 2^x

通用实现

全选复制放进笔记
function currying(fn) {
var slice = Array.prototype.slice;
var args = alice.call(arguments, 1);
return function() {
var innerArgs = slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return fn.apply(null, finalArgs);
}
}

先看一个简单的例子

全选复制放进笔记
function add(num1, num2) {
return num1 + num2;
} function curryAdd(num) {
return num + 5;
} add(2, 4); // 6
curryAdd(1); // 6

curryAdd 显然不是一个柯里化的实现。但是它很好的诠释了柯里化的思想。add 函数有两个参数,curryAdd 固定了其中一个参数


用上面 currying 函数构造 curryAdd 函数。

全选复制放进笔记
var curryAdd5 = currying(add, 5);

var curryAdd4 = currying(add, 4);

curryAdd5(1); // 6

curryAdd4(1); // 5

再看一个经典的 ajax 例子。

全选复制放进笔记
function Ajax() {
this.xhr = new XMLHttpRequest();
} Ajax.prototype.open = function(type, url, data, callback) {
this.onload = function() {
callback(this.xhr.responseText, this.xhr.status, thix.xhr);
} this.xhr.open(type, url, data.async);
this.xhr.send(data.paras);
} ['get', 'post'].forEach(function(type) {
Ajax.prototype[type] = currying(Ajax.prototype.open, type);
}) var xhr = new Ajax(); xhr.get('/articles/list', {}, function(datas) {}); xhr.post('/articles/add', {}, function(datas) {});

get post 两个方法是通过 'open' 方法衍生出来的。

从一个通用的 open 函数(可接受任意type),柯里化成专用的函数 get、post。


固定易变因数

提前把易变因数固定下来,生成一个更明确的应用函数,最典型的代码就是 ES5 定义的 Function.prototype.bing 函数

全选复制放进笔记
Function.prototype.bing = function(context) {
var _this = this,
slice = Array.prototype.slice,
_args = slice.call(arguments, 1); return function() {
return _this.apply(context, _args.concat(slice.call(arguments)))
}
}

延迟执行

不断的柯里化,累积传入的参数,最后执行。

全选复制放进笔记
function add() {
var sum = 0, i, len;
for (i = 0, len = arguments.length; i < len; i++) {
sum += arguments[i];
}
return sum;
} var currying = function(fn) {
var _args = []; return function cb() {
if (arguments.length === 0) {
return fn.apply(this, _args);
} Array.prototype.push.apply(_args, arguments); return cb;
}
} var curryingAdd = currying(add); curryingAdd(1)(2)(3)(4)(); // 10 var add321 = curryingAdd(3)(2, 1); add321(4)(); // 10

性能

柯里化肯定会有一些开销(函数嵌套,比普通函数占更多内存),但性能瓶颈首先来自其它原因(DOM 操作等)。

从另外一个角度分析,不管你用不用柯里化这个思维,你的代码很可能已经步入了更复杂的模式,会有更大的开销。

有关性能的一些事:

  • 存取 arguments 对象通常要比存取命名参数要慢一些。

  • 一些老版本的浏览器在 arguments.length 的实现上相当慢。

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

  • 创建大量嵌套作用域和闭包会带来开销,无论是内容还是速度上。

  • 大多数瓶颈来自 DOM 操作


总结

柯里化是以逻辑学家哈斯凯尔·加里命名的,

正如它的命名一样,函数柯里化给我们带来的是:解决问题的一种逻辑思维方式。

[转]js函数式变成之函数柯里化的更多相关文章

  1. 【转载】JS中bind方法与函数柯里化

    原生bind方法 不同于jQuery中的bind方法只是简单的绑定事件函数,原生js中bind()方法略复杂,该方法上在ES5中被引入,大概就是IE9+等现代浏览器都支持了(有关ES5各项特性的支持情 ...

  2. js高阶函数应用—函数柯里化和反柯里化(二)

    第上一篇文章中我们介绍了函数柯里化,顺带提到了偏函数,接下来我们继续话题,进入今天的主题-函数的反柯里化. 在上一篇文章中柯里化函数你可能需要去敲许多代码,理解很多代码逻辑,不过这一节我们讨论的反科里 ...

  3. 前端面试手写代码——JS函数柯里化

    目录 1 什么是函数柯里化 2 柯里化的作用和特点 2.1 参数复用 2.2 提前返回 2.3 延迟执行 3 封装通用柯里化工具函数 4 总结和补充 1 什么是函数柯里化 在计算机科学中,柯里化(Cu ...

  4. js高阶函数应用—函数柯里化和反柯里化

    在Lambda演算(一套数理逻辑的形式系统,具体我也没深入研究过)中有个小技巧:假如一个函数只能收一个参数,那么这个函数怎么实现加法呢,因为高阶函数是可以当参数传递和返回值的,所以问题就简化为:写一个 ...

  5. JS 浅谈函数柯里化,不明觉厉

    在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术.这个技术由 Christopher ...

  6. JS:函数柯里化

    函数柯里化 柯里化 在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术. 简单来说,就 ...

  7. js bind es5函数柯里化

    绑定函数 bind()最简单的用法是创建一个函数,使这个函数不论怎么调用都有同样的this值.常见的错误就像上面的例子一样,将方法从对象中拿出来,然后调用,并且希望this指向原来的对象. 如果不做特 ...

  8. Scala 基础(十二):Scala 函数式编程(四)高级(二)参数(类型)推断、闭包(closure)、函数柯里化(curry)、控制抽象

    1  参数(类型)推断 参数推断省去类型信息(在某些情况下[需要有应用场景],参数类型是可以推断出来的,如list=(1,2,3) list.map() map中函数参数类型是可以推断的),同时也可以 ...

  9. JavaScript函数柯里化的一些思考

    1. 高阶函数的坑 在学习柯里化之前,我们首先来看下面一段代码: var f1 = function(x){ return f(x); }; f1(x); 很多同学都能看出来,这些写是非常傻的,因为函 ...

随机推荐

  1. js的动态加载、缓存、更新以及复用(二)

    上一篇发出来后得到了很多回复,在此首先感谢大家的热情捧场!有的推荐第三方框架,比如 In.js.requrieJS.sea.js.lab.js等.这个开阔了眼界,以前只知道sea.js,省去了自己搜索 ...

  2. Devrama Slider - 支持任意 HTML 的内容滑块

    Devrama Slider 是一个图片滑块,支持很多特色功能.除了支持图片滑动,其它的 HTML 内容也支持.主要特色:响应式.图片预加载.图片延迟加载.进度条.自定义导航栏和控制按钮等等. 在线演 ...

  3. 24个很赞的 Node.js 免费教程和在线指南

    JavaScript 最初是用来创建动态网站效果的的前端语言.而如今,这门脚本语言也可以用作后端开发,用于搭建 Web 服务器,开发接口,甚至创建博客.在下面这个列表中包括24个 Node.js 教程 ...

  4. EWS API 2.0读取日历信息-读取内容注意事项

    采用模拟账号的方式读取日历信息,注意下日历的内容读取(Body)读取.代码如下:(采用 EWS API 2.0版本) 1.读取内容前必须设置如下属性:否则会提示:You must load or as ...

  5. [ javascript canvas 插件演示 ] canvas 插件演示

    <!DOCTYPE html> <html lang='zh-cn'> <head> <title>Insert you title</title ...

  6. 【转】C++标准库和标准模板库

    C++强大的功能来源于其丰富的类库及库函数资源.C++标准库的内容总共在50个标准头文件中定义.在C++开发中,要尽可能地利用标准库完成.这样做的直接好处包括:(1)成本:已经作为标准提供,何苦再花费 ...

  7. iOS使用Charles(青花瓷)抓包并篡改返回数据图文详解

    写本文的契机主要是前段时间有次用青花瓷抓包有一步忘了,在网上查了半天也没找到写的完整的教程,于是待问题解决后抽时间截了图,自己写一遍封存在博客园中以便以后随时查阅. charles又名青花瓷,在iOS ...

  8. 浅谈FloatingActionButton(悬浮按钮)

    一.介绍 这个类是继承自ImageView的,所以对于这个控件我们可以使用ImageView的所有属性 android.support.design.widget.FloatingActionButt ...

  9. Android 在不同Actitity之间数据传递

    本文实现一个简易的人品计算器来实践在不同Actitity之间数据传递 intent的数据传递 从A界面打开B界面 把A界面的数据传递给B界面 1. intent.setData(uri) -- int ...

  10. android deep link(深度链接)与自定义协议!

    此自定义仅供参考! 首先打开androidManifest.xml 在MainActivity中添加如下内容: <activity android:name=".MainActivit ...