详解用场景去理解函数柯里化(入门篇)


Posted in Javascript onApril 11, 2019

前言

函数柯里化就是将多参简化为单参数的一种技术方式,其最终支持的是方法的连续调用,每次返回新的函数,在最终符合条件或者使用完所有的传参时终止函数调用。

场景实例

与其他文章不同,我在本文会重点分享一些柯里化的经典使用场景,让你在学会这点技巧后能切实的提升代码的可维护性。

编写可重用小模块代码

比如我们有个方法部分逻辑前置是相同的,后面的执行是因为参数不同导致结果不同的,下面是代码部分。
计算商品的折扣,我们需要根据不同的折扣以及商品的入参返回其实际的价格。

// before
function getPrice(price,discount){
	return price * discount;
}

let price = getPrice(500,0.1);


// after 
function getPrice(discount){
	return price =>{
 	return price * discount
 }
}
// 使用,在这种使用效果下,我们可以固定的肢解拿到百分之十折扣的函数,
//也就是针对使用0.1折扣的商品价格都可以简化这个折扣的传递,从而达到简化参数的目的
//那么从函数的运行上来讲,也比之前的效率高了,如果解析折扣的过程比较复杂
let tenDiscount = getPrice(0.1);
let price = tenDiscount(500);

let price = getPrice(0.1)(500)

看上去有点鸡肋,因为我们本来的写法很简单,使用了柯里化反而让简单的事情变得复杂了,这主要是因为没有达到我们要把一个函数变成柯里化的经典场景。假如你下面的代码变成了下面这样,也许你就能觉察出如果有使用柯里化就会非常方便了,因为针对第一个参数做了若干的处理,甚至可以称为一个算法或者完整的逻辑判断流程,那么如果有多个参数调用都涉及这个方法的调用,同一个参数的这部分逻辑是相同可以共用跳过的。codepen连接:链接

// complexed fun 
function getPriceComplex(price,discount){
 let actualDiscount = 1;
 if(discount > 0.8 ) {
 	actualDiscount = 0.8;
 } else if(discount > 0.5){
 	actualDiscount = 0.5;
 } else {
 actualDiscount = 0.1;
 }
 let actualPrice = price - price % 100 ;
	return actualPrice * actualDiscount;
}

// complexed fun better
function getPriceComplexBetter(discount){
 let actualDiscount = 1;
 if(discount > 0.8 ) {
 	actualDiscount = 0.8;
 } else if(discount > 0.5){
 	actualDiscount = 0.5;
 } else {
 actualDiscount = 0.1;
 }
 return price => {
 	 let actualPrice = price - price % 100 ;
			return actualPrice * actualDiscount;
 }
}


console.log(getPriceComplex(500,0.9))
let exp1 = getPriceComplexCp(0.9);
console.log(exp1);
/** price => {
 let actualPrice = price - price % 100;
 return actualPrice * actualDiscount;
}*/
// 相同的输入参数时 可以缓存下之前代码逻辑的执行结果 实现模块的可重用,如果你之前的逻辑是一个纯函数
console.log(exp1(500))// 400
console.log(exp1(400))// 320


// get real discount 
// 当你针对第一个参数的逻辑较为复杂时,出于可维护角度,建议如此 ;
// 当你另外一个逻辑也是基于这个返回结果时,出于重用角度,建议如此
function getActualDiscount(discount){
 let actualDiscount = 1;
 if(discount > 0.8 ) {
 	actualDiscount = 0.8;
 } else if(discount > 0.5){
 	actualDiscount = 0.5;
 } else {
 actualDiscount = 0.1;
 }
 return actualDiscount;
}
// complexed fun best
function getPriceComplexBest(discount){
 let actualDiscount =getActualDiscount(discount);
 return price => {
 	 let actualPrice = price - price % 100 ;
			return actualPrice * actualDiscount;
 }
}

总结,无论如何,我们使用某种技巧或者封装或者其他,都是为了让代码更可用,原先复杂不可测试、不可理解的代码变得更有调理,更节省性能的角度出发的,当你的思维方式中有这种的时候,你就不会觉得是为了形式而使用,而是你的编码习惯或者风格就是如此。

简单改造普通函数为柯里

假如我们需要把一个原来非柯里的函数如何快速改造,在不影响原来主要代码逻辑的情况下,想下我们代码可能如何写?

// 只考虑两个参数
function add(a,b){
 return a + b
}

// 但如果你是用柯里化的方式:两个参数的时候 ,但这样对原代码变动非常大,对于一些复杂的逻辑,这基本不可能
function curryAdd(...args){
 return (...newArgs) => {
 	return anoNumber * number;
 };
}

// 我们写一个通用的柯里化函数的方式,经过这个函数的转换,我们可以将调用方式简化
function curry = (fn,...args){
	return (..._args)=>{
 	return fn(...args, ..._arg);
 }
}

let curryAdd = curry(add,10);
let curryAdd2 = curryAdd(11)

不定参数的累加

一个比较经典的练手题,把下面的代码用柯里化的方式实现,其难点简单分析如下:如果你没有了解过柯里化,可能觉得基本无法完成。

1 动态入参个数,这个也许还可以通过arguments循环完成2 每次都能接受新的参数继续累加,这必须是返回新函数并带有之前的结果,要求是具有柯里化特点3 每次不在追加参数时,需要能得到的值,这个需要你了解toString方法来改变结果值

实现一个add方法,使计算结果能够满足如下预期: add(1)(2)(3) = 6

add(1, 2, 3)(4) = 10

add(1)(2)(3)(4)(5) = 15

function add() {
 // 第一次执行时,定义一个数组专门用来存储所有的参数
 var _args = [].slice.call(arguments);
 // 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值,执行时已经收集所有参数为数组
 var adder = function () {
  var _adder = function() {
   // 执行收集动作,每次传入的参数都累加到原参数
   [].push.apply(_args, [].slice.call(arguments));
   return _adder;
  };
  // 利用隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
  _adder.toString = function () {
   return _args.reduce(function (a, b) {
    return a + b;
   });
  }
  return _adder;
 }
 return adder(_args);
}

备注:codepen中的console.log方法被重写,会有报错的问题,你可以直接通过浏览器的console控制台调试这个方法。

部分参数应用

部分参数应用是指有些场景是希望固定传递多个参数,来得到其固定的函数,然后基于这个函数去执行代码。类似于第一个例子中的一个折扣参数得出折扣算法的使用。我们将第一个例子再复杂化一些。就会变成这样的。

function getActualDiscount(custoemrLevel,discount){
	
}
function getPriceComplex (custoemrLevel,discount){
	let actualDiscount = getActualDiscount(custoemrLevel,discount);
 return price=>{
 	return price * actualDiscount;
 }
}
// 等级一的折扣策略 
let strategyLev1WithOnepoint = getPriceComplex('lev1',0.1) ;
let actualPrice = strategyLev1WithOnepoint(500);

以上所述是小编给大家介绍的用场景去理解函数柯里化(入门篇)详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
JavaScript 语法集锦 脚本之家基础推荐
Nov 15 Javascript
Jquery easyUI 更新行示例
Mar 06 Javascript
JavaScript实现的石头剪刀布游戏源码分享
Aug 22 Javascript
js实现同一页面可多次调用的图片幻灯切换效果
Feb 28 Javascript
使用AngularJS制作一个简单的RSS阅读器的教程
Jun 18 Javascript
AngularJS基础 ng-cut 指令介绍及简单示例
Aug 01 Javascript
js监听input输入框值的实时变化实例
Jan 26 Javascript
bootstrap table 多选框分页保留示例代码
Mar 08 Javascript
基于vue实现swipe轮播组件实例代码
May 24 Javascript
在vue2.0中引用element-ui组件库的方法
Jun 21 Javascript
vue 弹窗时 监听手机返回键关闭弹窗功能(页面不跳转)
May 10 Javascript
微信小程序实现多选框功能的实例代码
Jun 24 Javascript
Vue开发Html5微信公众号的步骤
Apr 11 #Javascript
跟混乱的页面弹窗说再见
Apr 11 #Javascript
vue实现todolist功能、todolist组件拆分及todolist的删除功能
Apr 11 #Javascript
vue实现todolist基本功能以及数据存储功能实例详解
Apr 11 #Javascript
JavaScript高阶教程之“==”隐藏下的类型转换
Apr 11 #Javascript
使用Vue父子组件通信实现todolist的功能示例代码
Apr 11 #Javascript
详解jQuery设置内容和属性
Apr 11 #jQuery
You might like
PHP可逆加密/解密函数分享
2012/09/25 PHP
如何让CI框架支持service层
2014/10/29 PHP
详解PHP的Yii框架中自带的前端资源包的使用
2016/03/31 PHP
php通过curl添加cookie伪造登陆抓取数据的方法
2016/04/02 PHP
PHP+Session防止表单重复提交的解决方法
2018/04/09 PHP
使用swoole 定时器变更超时未支付订单状态的解决方案
2019/07/24 PHP
小议Function.apply()之二------利用Apply的参数数组化来提高 JavaScript程序性能
2006/11/30 Javascript
javascript getElementsByClassName 和js取地址栏参数
2010/01/02 Javascript
jquery.validate使用攻略 第一部
2010/07/01 Javascript
javascript继承的六大模式小结
2015/04/13 Javascript
纯JS实现本地图片预览的方法
2015/07/31 Javascript
基于jQuery实现Div窗口震动特效代码-代码简单
2015/08/28 Javascript
理解JS绑定事件
2016/01/19 Javascript
Bootstrap 折叠(Collapse)插件用法实例详解
2016/06/01 Javascript
jQuery ztree实现动态树形多选菜单
2016/08/12 Javascript
JavaScript实现自定义媒体播放器方法介绍
2017/01/03 Javascript
AngularJS中的按需加载ocLazyLoad示例
2017/01/11 Javascript
js实现百度登录框鼠标拖拽效果
2017/03/07 Javascript
浅谈Vue的加载顺序探讨
2017/10/25 Javascript
解决vue 使用setTimeout,离开当前路由setTimeout未销毁的问题
2020/07/21 Javascript
Python操作Word批量生成文章的方法
2015/07/28 Python
详解使用pymysql在python中对mysql的增删改查操作(综合)
2017/01/18 Python
浅析python中的迭代与迭代对象
2018/10/08 Python
浅谈python下含中文字符串正则表达式的编码问题
2018/12/07 Python
Python 基于wxpy库实现微信添加好友功能(简洁)
2019/11/29 Python
python 已知三条边求三角形的角度案例
2020/04/12 Python
Python中BeautifulSoup通过查找Id获取元素信息
2020/12/07 Python
HTML5 SEO优化的一些建议
2020/08/27 HTML / CSS
微软台湾官方网站:Microsoft台湾
2018/08/15 全球购物
香港网上花店:FlowerAdvisor香港
2019/05/30 全球购物
工商管理毕业生推荐信
2013/12/24 职场文书
幼儿园秋游感想
2014/03/12 职场文书
活动总结怎么写
2014/04/28 职场文书
幼儿园师德师风学习材料
2014/05/29 职场文书
大学生自我评价200字(4篇)
2014/09/17 职场文书
用电申请报告范文
2015/05/18 职场文书