一、概念

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

简单来说,柯里化是一种函数的转换,它是指将一个函数从可调用的 f(a, b, c)转换为可调用的 f(a)(b)(c)

柯里化的3个常见作用:

  • 参数复用
  • 提前返回
  • 延迟计算/运行

二、参数复用

参数复用可以用在各种需要正则检验的需求,比如校验电话号码、校验邮箱、校验身份证号、校验密码等。

这时我们会封装一个通用函数 checkByRegExp ,接收两个参数,校验的正则对象和待校验的字符串。

普通方法,如果需要多次校验那么就调用多次方法

function checkByRegExp(regExp,string) {return regExp.test(string);
}checkByRegExp(/^1\d{10}$/, '12345678900'); // 校验电话号码
checkByRegExp(/^1\d{10}$/, '12345678900');
checkByRegExp(/^1\d{10}$/, '12345678900');

柯里化写法

//进行柯里化
let _check = curry(checkByRegExp);
//生成工具函数,验证电话号码
let checkCellPhone = _check(/^1\d{10}$/);checkCellPhone('12345678900'); // 校验电话号码
checkCellPhone('12345678900'); // 校验电话号码
checkCellPhone('12345678900'); // 校验电话号码

可以借助柯里化对 checkByRegExp 函数进行封装,以简化代码书写,提高代码可读性。

三、提前返回

关于提前返回,这里引用一个网上流传的例子:

兼容现代浏览器以及IE浏览器的事件添加方法。以下是正常写法。

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);});}
};

这样会导致每次使用触发事件的时候,都会触发 if…else if …,如果使用柯里化,那么就只会在第一次的时候走 if…else if … ,即使之后再触发事件,也不会走条件判断。

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);});};}
})();

四、延迟计算

关于延迟计算,一般情况下,函数在传入参数之后,就会立即执行,柯里化的延迟计算,就是能让函数即使传入参数,也不会立即实行,而是将参数先存储在一个数组中,等到某个时机再调用数组,将之前的参数一起计算。

var curryWeight = function(fn) {var _selfWeight = [];return function() {if (arguments.length === 0) {return fn.apply(null, _selfWeight);} else {_selfWeight = _selfWeight.concat([].slice.call(arguments));}}
};
var selfWeight = 0;
var addWeight = curryWeight(function() {var i=0; len = arguments.length;for (i; i<len; i+=1) {selfWeight += arguments[i];}
});addWeight(2.3);
addWeight(6.5);
addWeight(1.2);
addWeight(2.5);
addWeight();    //  这里才计算console.log(selfWeight);    // 12.5

五、实现柯里化函数

实现柯里化函数可以通过函数的 length 属性,获取函数的形参个数,形参的个数就是所需的参数个数。

function curry(func) {return function curried(...args) {if (args.length >= func.length) {return func.apply(this, args);} else {return function(...args2) {return curried.apply(this, args.concat(args2));}}};}function sum(a, b, c) {return a + b + c;
}let curriedSum = curry(sum);alert( curriedSum(1, 2, 3) ); // 6,仍然可以被正常调用
alert( curriedSum(1)(2,3) ); // 6,对第一个参数的柯里化
alert( curriedSum(1)(2)(3) ); // 6,全柯里化

六、柯里化面试题

这里再讲以下,网上的那一道和柯里化相关的面试题,以及一个关于函数内置的toString函数的知识点。

写一个函数实现
add(1)(2)(3)  // 6// 实现方法var add = function(a) {return function(b) {return funciton(c) {return a+b+c;}}}add(1)(2)(3);

上面这种写法是最简单的实现方法,但是缺点显而易见,只能实现单一一种情况,如果传入的参数不定,那么就无法使用这种方法,这里附上一种写法,可以适应多个参数的情况。

var add = function(a) {var sum = a;var addMore = function(b) {sum += b;return addMore;};addMore.toString = function() {return sum;};return addMore;
};
var a = add(1)(2)(3)(4).toString();  //10

这里需要提一下,如果是单纯的,
var a = add(1)(2)(3)(4);
这样输出的是一个函数式

{ [Function: addMore] toString: [Function] }

必须得转化以下,才能够输出数字。另外,还有一种情况:

var add = function(a) {var sum = a;var addMore = function(b) {sum += b;return addMore;};addMore.toString = function() {return sum;};return addMore;
};
var a = add(1)(2)(3)(4)+10;  //20

这是由于函数的隐式转换。当我们直接将函数参与其他的计算时,函数会默认调用toString方法,直接将函数体转换为字符串参与计算。
但是,使用函数内置的 toString()函数 输出的是一个函数体字符串。例子如下,

function b() {return 10;
}
var c = b+10;
console.log(c);
console.log(typeof(c));
// 输出
function b() {return 10;
}10
string

所以,必须使用自定义的 toString 是函数返回我们想要的值。
也就是说,当没有定义toString时,函数的隐式转换会调用默认的toString方法,它会将函数的定义内容作为字符串返回。

而当我们自定义了toString方法时,那么隐式转换的返回结果则由我们自己控制了。

另外,vauleOf 的方法的作用和 toString 方法一样,但是valueOf会比toString后执行。

还有一个注意的点,

add (2,3) arguments.length == 2
add (2)(3) arguments.length == 1

柯里化面试题还有另一种形式

var a = add(1)(2)(3)(4);   //10
var b = add(1, 2, 3, 4);   //10
var c = add(1, 2)(3, 4);   //10
var d = add(1, 2, 3)(4);   //10// 实现方法
function add() {var _args = [].slice.call(arguments);var adder = function () {var _adder = function() {_args.push(...arguments);return _adder;};_adder.toString = function () {return _args.reduce(function (a, b) {return a + b;});}return _adder;}return adder(..._args);
}var a = add(1)(2)(3)(4,5).toString();
console.log(a); // 10

参考链接:
前端基础进阶(十):深入详解函数的柯里化
「前端进阶」彻底弄懂函数柯里化
柯里化(Currying)

JS - 函数柯里化相关推荐

  1. 函数柯里化的意义_详解JS函数柯里化

    第一次看到柯里化这个词的时候,还是在看一篇算法相关的博客提到把函数柯里化,那时一看这个词就感觉很高端,实际上当你了解了后才发现其实就是高阶函数的一个特殊用法. 果然是不管作用怎么样都要有个高端的名字才 ...

  2. 带你看懂javascript函数柯里化(currying)

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

  3. 了解js基础知识中的作用域和闭包以及闭包的一些应用场景,浅析函数柯里化

    js基础知识中的作用域和闭包 一.作用域 1.作用域.自由变量简介 (1)作用域定义 (2)作用域实例演示 (3)自由变量定义 (4)自由变量实例演示 2.作用域链简介 (1)作用域链定义 (2)作用 ...

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

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

  5. 高阶函数、js函数内返回一个内部函数详解---->函数柯里化

    高阶函数 如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数. 若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数. 若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函 ...

  6. 【JS函数】JS函数之高阶函数、组合函数、函数柯里化

    自我介绍:大家好,我是吉帅振的网络日志:微信公众号:吉帅振的网络日志:前端开发工程师,工作4年,去过上海.北京,经历创业公司,进过大厂,现在郑州敲代码. JS函数专栏 1[JS函数]JS函数之普通.构 ...

  7. js面试高频题:函数柯里化的实现(彻底弄懂)

    函数柯里化的适用场景有: 1. 参数复用 2. 延时执行 3. 提前确认 函数柯里化的核心在于:函数里面返回函数,从而做到参数复用的目的. 我们以一个js经典面试题为例开始讲解: 实现一个函数,使得满 ...

  8. reactjs高阶函数和函数柯里化

    高阶函数.函数柯里化 <!DOCTYPE html> <html lang="en"> <head><meta charset=" ...

  9. 高级函数技巧-函数柯里化

    我们经常说在Javascript语言中,函数是"一等公民",它们本质上是十分简单和过程化的.可以利用函数,进行一些简单的数据处理,return 结果,或者有一些额外的功能,需要通过 ...

最新文章

  1. ESXi6.7安装流程和bug处理
  2. 建立循环双链表(尾插法)
  3. 日本CG大神又整活了!3D建模软件拿来搞面部实时捕捉,网友:效果好得有点吓人...
  4. javaScript解决Form的嵌套
  5. 关于js 中call()和 apply()方法的解释
  6. linux配置文件引用时间,linux时间设置、screen使用、命令分类、hash作用、命令引用及history命令...
  7. 项目建立数据库初始环境脚本文件的示例
  8. 火狐浏览器添加MetaMask钱包和本地开启私有链开发
  9. 由Docker的MySQL官方镜像配置的容器无法启动问题解决办法(修改配置后无法启动)
  10. 浙江省二级计算机vfp,浙江省计算机2级vfp程序调试真题集.doc
  11. python算法应用(五)——搜索与排名1(连接数据库及简单排名)
  12. 编写函数main求3!+6!+9!python_Python day 6(3) Python 函数式编程1
  13. 详解Python中函数和模块的特殊属性__annotations__
  14. Atitit.二维码功能的设计实践 attilax 总结
  15. SoapUI中文乱码
  16. 【滑动窗口协议模拟】
  17. 云服务器申请退款,腾讯云服务器申请自助退款的操作流程及图文教程
  18. WIN10华硕解决无法调节电脑亮度
  19. 字节跳动否认完成支付牌照收购,但金融野心一直有
  20. 北航计算机网络安全,李舟军

热门文章

  1. 集合框架|Java集合框架基本使用
  2. 中国互联网的沧海桑田
  3. 可达编程 单源最短路
  4. Python ffmpeg视频压缩
  5. java json 解析_Java解析JSON的四种方式
  6. 魔推mpush:实现精准智能消息推送的五个关键
  7. 概率分布,独立同分布在图像分类与检测中到底代表什么?
  8. 2020最新pycharm汉化安装(亲测有效)
  9. c语言程序设计工资纳税系统,C语言程序设计纳税工资系统
  10. addClass与className的区别