JavaScript函数柯里化

函数式

JavaScript是以函数为一等公民的函数式语言。函数在JavaScript中也是一个对象(继承制Function),函数也可以作为参数传递成函数变量。最近几年函数式也因为其无副作用的特性、透明性、惰性计算等在高并发,大数据领域火起来了。

JavaScript中也有如Underscore、lodash之类的函数式库,如lodash的使用方式:

var names = _.chain(users)
  .map(function(user){
    return user.user;
  })
  .join(" , ")
  .value();
console.log(names);

关于lodash更多内容请参考JavaScript工具库之Lodash.

柯里化

今天文章将以高阶函数中的柯里化方式来,看看JavaScript的函数式能力。

在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。这个技术由 Christopher Strachey 以逻辑学家 Haskell Curry 命名的,尽管它是 Moses Schnfinkel 和 Gottlob Frege 发明的。

在理论计算机科学中,柯里化提供了在简单的理论模型中比如只接受一个单一参数的lambda 演算中研究带有多个参数的函数的方式。

JavaScript的柯里化实现

下边的例子,我们将把柯里化方式泛化为接受任意个参数,直到声明的方法参数个数饱和才执行,所以根据参数个数可以有多种柯里化函数产生。

代码如下:

(function(global) {
    var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m,
        FN_ARG_SPLIT = /,/,
        FN_ARG = /^\s*(_?)(\S+?)\1\s*$/,
        STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
    var getArgLength = function(func) {
        var fnText = func.toString().replace(STRIP_COMMENTS, ‘‘);
        var argDecl = fnText.match(FN_ARGS);
        var params = [];
        argDecl[1].split(FN_ARG_SPLIT).forEach(function(arg) {
            arg.replace(FN_ARG, function(all, underscore, name) {
                params.push(name);
            });
        });
        return params.length;
    };
    var curryFunc = function(func, len) {
        len = len || getArgLength(func);
        var args = [];
        if (len === 0) {
            return func.apply(null);
        }
        return function() {
            [].push.apply(args, [].slice.apply(arguments));
            if (args.length >= len) {
                return func.apply(null, args);
            }
            return arguments.callee;
        };
    };
    global.curryFunc = curryFunc;
})(this);
function add(x, y, z) {
    return x + y + z;
}
console.log("result 1:", curryFunc(add)(1, 2)(3));
console.log("result 2:", curryFunc(add)(1)(2, 3));
console.log("result 3:", curryFunc(add)(1)(3)(2));
function add(x, y, z) {
    return x * y * z;
}
console.log("result 1:", curryFunc(add)(2, 4)(6));
console.log("result 2:", curryFunc(add)(2)(4, 6));
console.log("result 3:", curryFunc(add)(2)(6)(4));
function sayHello() {
    return "hello";
}
console.log(curryFunc(sayHello));

首先上面会利用正则来获取传入函数的参数个数。再返回一个函数的代理,每次的调用都会将传入参数缓存在args临时变量中,直到参数个数饱和才会立即执行。代码比较冗长,慢慢品味,当然有不足支持,也希望大家指出来。

时间: 2024-10-25 05:17:33

JavaScript函数柯里化的相关文章

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函数进阶系列第二篇——函数柯里化

前面的话 函数柯里化currying的概念最早由俄国数学家Moses Schönfinkel发明,而后由著名的数理逻辑学家Haskell Curry将其丰富和发展,currying由此得名.本文将详细介绍函数柯里化(curring) 定义 currying又称部分求值.一个currying的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来.待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值 从

一道javascript面试题(闭包与函数柯里化)

要求写一个函数add(),分别实现能如下效果: (1)console.log(add(1)(2)(3)(4)());//10 (2)console.log(add(1,2)(3,4)());//10 (3)console.log(add(1,2)(3,4));//10 针对(1)和(2),有两种思路实现:纯闭包思路和函数柯里化思路.一.闭包思路 (1)的解决方案(闭包实现) function add(arg) { // body... let sum = 0; sum+=arg; return

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

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

建议75:函数柯里化

柯里化是把接受多个参数的函数变换成接受一个单一参数的函数,并且返回一个新函数,这个新函数能够接受原函数的参数.下面可以通过例子来帮助理解.function adder(num) {    return function(x) {        return num + x;    }}var add5 = adder(5);var add6 = adder(6);print(add5(1));  // 6print(add6(1));  //7 函数adder接受一个参数,并返回一个函数,这个返

microtasks、macrotasks与函数柯里化

1.microtasks.macrotasks JavaScript是单线程执行的,而现在推行的多线程执行,都可以理解为伪多线程,因为所有的执行都会回归的主线程执行, 而主线程外会有如多个消息队列,等待主线程的空闲后进入执行. 而microtasks与macrotasks就是很好理解事件环的概念,然后它在不同的浏览器的执行顺序可能不一致,但不妨去理解它. V8实现中,两个队列各包含不同的任务: macrotasks: script(整体代码),setTimeout, setInterval, s

【前端学习笔记】函数柯里化(自网易云课堂)

1. 函数柯里化通常是指把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的并且返回一个接受余下的参数而且返回结果的新函数的技术. // 1. 最简单的柯里化 // sum函数接受三个参数,并返回求和结果 var sum = function(a,b,c) { return a+b+c; } // 最简单柯里化的sum函数 var sum_curry = function(a){ return function(b,c){ return a+b+c; } } 2. 更泛化的定义是

【读书笔记】 函数柯里化

这是书上函数柯里化的例子 1 function curry(fn){ 2 var args = Array.prototype.slice.call(arguments, 1);//取出调用curry时除了第一个函数参数的后面所有参数; 3 return function(){ 4 var innerArgs = Array.prototype.slice.call(arguments);//取出第二次调用时的所有参数; 5 var finalArgs = args.concat(innerAr

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

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