[转]js函数式变成之函数柯里化

本文转自: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 操作

总结

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

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

时间: 2024-10-13 22:56:49

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

js之函数柯里化

函数柯里化是js函数式编程的一项重要应用,柯里化是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术.假设我们要计算一个表达式如下 function add(a,b,c){ return a+b+c; } add(1,2,3);//直接调用输出 add(1)(2)(3);//参数分开调用输出 第一种是我们常见的,第二种参数分开调用不常见,但我们也能实现他 如下 function add(a){ return function(b){ return function(c){ retu

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

原生bind方法 不同于jQuery中的bind方法只是简单的绑定事件函数,原生js中bind()方法略复杂,该方法上在ES5中被引入,大概就是IE9+等现代浏览器都支持了(有关ES5各项特性的支持情况戳这里ECMAScript 5 compatibility table),权威指南上提到在ES3中利用apply模拟该方法的实现(JS权威指南中函数那章), 但无法真实还原该方法, 这也是真bind方法中的有趣特性. (原文这边理解有问题, 这段话的意思如果结合犀牛书上下文的意思, 再结合犀牛书中

【转】详解JS函数柯里化

第一次看到柯里化这个词的时候,还是在看一篇算法相关的博客提到把函数柯里化,那时一看这个词就感觉很高端,实际上当你了解了后才发现其实就是高阶函数的一个特殊用法.果然是不管作用怎么样都要有个高端的名字才有用. 首先看看柯里化到底是什么? 维基百科上说道:柯里化,英语:Currying(果然是满满的英译中的既视感),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术. 看这个解释有一点抽象,我们就拿被做了无数次示例的add函数,

JS函数柯里化

第一次看到柯里化这个词的时候,还是在看一篇算法相关的博客提到把函数柯里化,那时一看这个词就感觉很高端,实际上当你了解了后才发现其实就是高阶函数的一个特殊用法. 果然是不管作用怎么样都要有个高端的名字才有用. 首先看看柯里化到底是什么? 维基百科上说道:柯里化,英语:Currying(果然是满满的英译中的既视感),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术. 看这个解释有一点抽象,我们就拿被做了无数次示例的add函数

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

在Lambda演算(一套数理逻辑的形式系统,具体我也没深入研究过)中有个小技巧:假如一个函数只能收一个参数,那么这个函数怎么实现加法呢,因为高阶函数是可以当参数传递和返回值的,所以问题就简化为:写一个只有一个参数的函数,而这个函数返回一个带参数的函数,这样就实现了能写两个参数的函数了(具体参见下边代码)--这就是所谓的柯里化(Currying,以逻辑学家Hsakell Curry命名),也可以理解为一种在处理函数过程中的逻辑思维方式. 1 function add(a, b) { 2 retur

JavaScript函数柯里化的一些思考

1. 高阶函数的坑 在学习柯里化之前,我们首先来看下面一段代码: var f1 = function(x){ return f(x); }; f1(x); 很多同学都能看出来,这些写是非常傻的,因为函数f1和f是等效的,我们直接令var f1 = f;就行了,完全没有必要包裹那么一层. 但是,下面一段代码就未必能够看得出问题来了: var getServerStuff = function(callback){ return ajaxCall(function(json){ return cal

精读JavaScript模式(六),Memoization模式与函数柯里化的应用

假期就这么结束了!十天假就有三天在路上,真的难受!想想假期除了看了两场电影貌似也没做什么深刻印象的事情.流浪地球,特效还是很赞,不过对于感情的描写还是逃不掉拖沓和尴尬的通病,对于国产科幻还是抱有支持的态度.疯狂的外星人相比读大学期间看的疯狂的赛车,荒诞感还是差了点,也许是我笑点太高...不过整体还是感觉比流浪地球值票价,个人观点吧. 开年来同事说自己小舅子年终奖税后18W,他这两天深受打击,我听完也深受打击,哎. 假期结束也该好好安排下今年的时间了,年底辞职的规划不变,加上未来几年要结婚,想想还

函数柯里化(Currying)示例

”函数柯里化”是指将多变量函数拆解为单变量的多个函数的调用, 可以从高元函数动态地生成大量低元的函数.可以看成一个强大的函数工厂,结合函数式编程,可以叠加出很BT的能力.下面给出了一个示例,说明如何使用 Currying 用一行代码计算任意指数的多项式的和: 以及使用 Currying 实现一个简单的文件处理框架. 注意到, Currying 的过程中,参数的顺序是有讲究的.一般, 函数参数建议放在前面,按照想要调用的顺序: 数据参数放在后面. package scalastudy.basic

python笔记--3--函数、生成器、装饰器、函数嵌套定义、函数柯里化

函数 函数定义语法: def 函数名([参数列表]): '''注释''' 函数体 函数形参不需要声明其类型,也不需要指定函数返回值类型 即使该函数不需要接收任何参数,也必须保留一对空的圆括号 括号后面的冒号必不可少 函数体相对于def关键字必须保持一定的空格缩进 Python允许嵌套定义函数 在定义函数时,开头部分的注释并不是必需的,但是如果为函数的定义加上这段注释的话,可以为用户提供友好的提示和使用帮助. Python是一种高级动态编程语言,变量类型是随时可以改变的.Python中的函数和自定