JS - 函数柯里化
一、概念
柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数。
简单来说,柯里化是一种函数的转换,它是指将一个函数从可调用的 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 - 函数柯里化相关推荐
- 函数柯里化的意义_详解JS函数柯里化
第一次看到柯里化这个词的时候,还是在看一篇算法相关的博客提到把函数柯里化,那时一看这个词就感觉很高端,实际上当你了解了后才发现其实就是高阶函数的一个特殊用法. 果然是不管作用怎么样都要有个高端的名字才 ...
- 带你看懂javascript函数柯里化(currying)
1.什么是柯里化 这里参照百度百科: 在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技 ...
- 了解js基础知识中的作用域和闭包以及闭包的一些应用场景,浅析函数柯里化
js基础知识中的作用域和闭包 一.作用域 1.作用域.自由变量简介 (1)作用域定义 (2)作用域实例演示 (3)自由变量定义 (4)自由变量实例演示 2.作用域链简介 (1)作用域链定义 (2)作用 ...
- 【转载】JS中bind方法与函数柯里化
原生bind方法 不同于jQuery中的bind方法只是简单的绑定事件函数,原生js中bind()方法略复杂,该方法上在ES5中被引入,大概就是IE9+等现代浏览器都支持了(有关ES5各项特性的支持情 ...
- 高阶函数、js函数内返回一个内部函数详解---->函数柯里化
高阶函数 如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数. 若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数. 若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函 ...
- 【JS函数】JS函数之高阶函数、组合函数、函数柯里化
自我介绍:大家好,我是吉帅振的网络日志:微信公众号:吉帅振的网络日志:前端开发工程师,工作4年,去过上海.北京,经历创业公司,进过大厂,现在郑州敲代码. JS函数专栏 1[JS函数]JS函数之普通.构 ...
- js面试高频题:函数柯里化的实现(彻底弄懂)
函数柯里化的适用场景有: 1. 参数复用 2. 延时执行 3. 提前确认 函数柯里化的核心在于:函数里面返回函数,从而做到参数复用的目的. 我们以一个js经典面试题为例开始讲解: 实现一个函数,使得满 ...
- reactjs高阶函数和函数柯里化
高阶函数.函数柯里化 <!DOCTYPE html> <html lang="en"> <head><meta charset=" ...
- 高级函数技巧-函数柯里化
我们经常说在Javascript语言中,函数是"一等公民",它们本质上是十分简单和过程化的.可以利用函数,进行一些简单的数据处理,return 结果,或者有一些额外的功能,需要通过 ...
最新文章
- ESXi6.7安装流程和bug处理
- 建立循环双链表(尾插法)
- 日本CG大神又整活了!3D建模软件拿来搞面部实时捕捉,网友:效果好得有点吓人...
- javaScript解决Form的嵌套
- 关于js 中call()和 apply()方法的解释
- linux配置文件引用时间,linux时间设置、screen使用、命令分类、hash作用、命令引用及history命令...
- 项目建立数据库初始环境脚本文件的示例
- 火狐浏览器添加MetaMask钱包和本地开启私有链开发
- 由Docker的MySQL官方镜像配置的容器无法启动问题解决办法(修改配置后无法启动)
- 浙江省二级计算机vfp,浙江省计算机2级vfp程序调试真题集.doc
- python算法应用(五)——搜索与排名1(连接数据库及简单排名)
- 编写函数main求3!+6!+9!python_Python day 6(3) Python 函数式编程1
- 详解Python中函数和模块的特殊属性__annotations__
- Atitit.二维码功能的设计实践 attilax 总结
- SoapUI中文乱码
- 【滑动窗口协议模拟】
- 云服务器申请退款,腾讯云服务器申请自助退款的操作流程及图文教程
- WIN10华硕解决无法调节电脑亮度
- 字节跳动否认完成支付牌照收购,但金融野心一直有
- 北航计算机网络安全,李舟军