浅析JavaScript 函数柯里化


Posted in Javascript onSeptember 08, 2020

柯里化 (Currying)是把接收多个参数的原函数变换成接受一个单一参数(原来函数的第一个参数的函数)并返回一个新的函数,新的函数能够接受余下的参数,并返回和原函数相同的结果。

ES6的方式实现柯里化的通用

function currying(fn,...rest1){
	return function(...rest2){
		//这里用apply 是为把数组形式的参数直接传入原函数 null是因为不需要改变this
		return fn.apply(null,rest1.concat(rest2));
	}
}

将一个sayHello函数柯里化

function sayHello(name,age,fruit){
	console.log(`我叫${name},我${age}岁了,我喜欢吃${fruit}`);
}

//传入第一个参数
let curryingShowMsg = currying(sayHello,'小明');
//执行传入剩余参数
curryingShowMsg(22,'芒果');

反柯里化 和柯里化刚好相反。为了让方法使用场景更广,使用反柯里化,可以把原生方法借出来,让任何对象拥有原生对象的方法。

二者的区别

//柯里化
//function(arg1,arg2) => function(arg1)(arg2);
//function(arg1,arg2,...,argn) => function(arg1)(arg2)(...)(argn)
//反柯里化
//obj.func(arg1,arg2) => func(obj,arg1,arg2)

ES6实现一个反柯里化

function unCurrying(fn){
	//tar 是我们借给的对象 以前需要xxx.fn(xx) 现在就可以fn(xxx,xx)
	return function(tar,...argu){
		return fn.apply(tar,argu);
	}
}
//比如我们想把Array.prototype.push方法从原生借出来
let push = unCurrying(Array.prototype.push);
//arrguments是我们借给的对象
push(arguments,4);

函数柯里化的高阶实现 ,上面的函数只实现一层简单的柯里化 如果实现完全的柯里化func(xx)(xx)(xx)(xx)的话,我们要反复嵌套我们的柯里化函数,这里我们实现一个更高阶的柯里化通用方法。

function curryingHelper(fn,len){
	//这里先说个基本知识点 fn.length 返回的是这个方法需要传入的参数个数
	//这里第一次运行时通过fn.length 后面递归都是用的传入的len len为剩余的参数个数
	const length = len || fn.length;
	return function(...rest){
		//判断这次传入的参数是否大于等于剩下的参数 如果不是递归返回下一个方法继续传参
		return rest.length >= length 
		? fn.apply(this,rest)
		: curryingHelper(currying.apply(this,[fn].concat(rest)),length-rest.length)
	}
}
//还是刚才的sayHello 函数
let betterShowMsg = curryingHelper(sayHello);
//自动控制传参层数
betterShowMsg('zyx')(22)('葡萄');
betterShowMsg('zyx',22)('葡萄');

柯里化的三种用法

1 参数的复用

function Say(name,some){
	console.log(name + '说' + some);
}
//如果我们只想让zyx说一些东西
let zyxSay = currying(Say,'zyx');
zyxSay('1111');//zyx说1111

2 提高适用性

//通用函数解决了兼容性的问题,但是同时在不同场景下,我们可能同一种规则需要反复使用
//这就可能会造成代码的重复性 比如

function square(i){ return i*i }//平方
function dubble(i){ return i*2 }//双倍
function map(handler,list){
	//handle 是操作的规则 list是操作的arrguments
	return list.map(handler)
}

map(square,[1,2,3]);//数组每一项平方
map(dubble,[1,2,3]);//数组每一项加倍
//这就是通用性 我可以用同一个函数做很多不同的操作
//但是如果我们需要大量做平方操作 每次我们都需要传入方法再传入数组就造成的代码浪费
//这时我们通过柯里化提高实用性

let mapSQ = currying(map,square);//直接定义出来的新的平凡操作函数
mapSQ([1,2,3]);//以后就不用传入操作方法了

3 延迟执行

let add = function(...rest){
	//定义一个闭包保存_args
	const _args = [];
	return function cb(...rest){
		if(rest.length == 0){
			//如果不穿参数了 也就是add() 说明我们需要最后执行函数了
			let res = 0;
			//累加
			console.log(_args);
			for(let data of _args){
				res += data;
			}
			return res;
		}else{
			_args.push(...rest);
			//为了锁住args 闭包
			return _args;
		}
	}
}()

add(1);
add(2);
let a = add();
console.log(a);//3

以上就是浅析JavaScript 函数柯里化的详细内容,更多关于JavaScript 函数柯里化的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
jquery监控数据是否变化(修正版)
Apr 12 Javascript
jQuery中判断一个元素是否为另一个元素的子元素(或者其本身)
Mar 21 Javascript
js 跳出页面的frameset框架示例介绍
Dec 23 Javascript
flash遮住div问题的正确解决方法
Feb 27 Javascript
jquery的clone方法应用于textarea和select的bug修复
Jun 26 Javascript
jquery实现标签上移、下移、置顶
Apr 26 Javascript
JS中使用apply、bind实现为函数或者类传入动态个数的参数
Apr 26 Javascript
第一次接触神奇的Bootstrap
Oct 14 Javascript
js 判断一个数字是不是2的n次方幂的实例
Nov 26 Javascript
vue中axios的封装问题(简易版拦截,get,post)
Jun 15 Javascript
简述vue状态管理模式之vuex
Aug 29 Javascript
js jquery 获取某一元素到浏览器顶端的距离实现方法
Sep 05 jQuery
Vue.js使用axios动态获取response里的data数据操作
Sep 08 #Javascript
JavaScript 事件代理需要注意的地方
Sep 08 #Javascript
Vue axios 跨域请求无法带上cookie的解决
Sep 08 #Javascript
详解JavaScript的this指向和绑定
Sep 08 #Javascript
vue点击按钮实现简单页面的切换
Sep 08 #Javascript
Vue filter 过滤器、以及在table中的使用介绍
Sep 07 #Javascript
VUE中setTimeout和setInterval自动销毁案例
Sep 07 #Javascript
You might like
php学习笔记之 函数声明
2011/06/09 PHP
PHP5中Cookie与 Session使用详解
2013/04/30 PHP
ThinkPHP入库出现两次反斜线转义及数据库类转义的解决方法
2014/11/04 PHP
JavaScript 对象模型 执行模型
2010/10/15 Javascript
深入理解Javascript闭包 新手版
2010/12/28 Javascript
电子商务网站上的常用的js放大镜效果
2011/12/08 Javascript
如何获取JQUERY AJAX返回的JSON结果集实现代码
2012/12/10 Javascript
javascript回车完美实现tab切换功能
2014/03/13 Javascript
基于Bootstrap的Metronic框架实现页面链接收藏夹功能
2016/08/29 Javascript
JS实现隐藏同级元素后只显示JS文件内容的方法
2016/09/04 Javascript
基于Vuejs框架实现翻页组件
2020/06/29 Javascript
浅析script标签中的defer与async属性
2016/11/30 Javascript
JavaScript数据结构之二叉树的查找算法示例
2017/04/13 Javascript
react-router实现按需加载
2017/05/09 Javascript
taro开发微信小程序的实践
2019/05/21 Javascript
js中关于Blob对象的介绍与使用
2019/11/29 Javascript
小程序瀑布流组件实现翻页与图片懒加载
2020/05/19 Javascript
朴素贝叶斯算法的python实现方法
2014/11/18 Python
用Python实现斐波那契(Fibonacci)函数
2016/03/25 Python
python遍历文件夹下所有excel文件
2018/01/03 Python
基于Python log 的正确打开方式
2018/04/28 Python
python多进程读图提取特征存npy
2019/05/21 Python
Python3enumrate和range对比及示例详解
2019/07/13 Python
django+tornado实现实时查看远程日志的方法
2019/08/12 Python
tensorflow 限制显存大小的实现
2020/02/03 Python
浅谈three.js中的needsUpdate的应用
2012/11/12 HTML / CSS
HTML5 绘制图像(上)之:关于canvas元素引领下一代web页面的问题
2013/04/24 HTML / CSS
室内设计专业个人的自我评价
2013/10/19 职场文书
师范毕业生求职信
2014/07/11 职场文书
幼儿园园长工作总结2015
2015/05/25 职场文书
初中数学教学随笔
2015/08/15 职场文书
2016十一国庆节慰问信
2015/12/01 职场文书
家庭教育培训学习心得体会
2016/01/14 职场文书
Python中的min及返回最小值索引的操作
2021/05/10 Python
Redis Cluster 集群搭建你会吗
2021/08/04 Redis
Python数组变形的几种实现方法
2022/05/30 Python