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


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 相关文章推荐
JQuery动态创建DOM、表单元素的实现代码
Aug 09 Javascript
Javascript实现关联数据(Linked Data)查询及注意细节
Feb 22 Javascript
js弹出层(jQuery插件形式附带reLoad功能)
Apr 12 Javascript
JavaScript修改css样式style动态改变元素样式
Dec 16 Javascript
Javascript 遍历页面text控件详解
Jan 06 Javascript
Css3制作变形与动画效果
Jul 24 Javascript
layui 选择列表,打勾,点击确定返回数据的例子
Sep 02 Javascript
基于Vue和Element-Ui搭建项目的方法
Sep 06 Javascript
vue-cli2与vue-cli3在一台电脑共存的实现方法
Sep 25 Javascript
vue props对象validator自定义函数实例
Nov 13 Javascript
如何在微信小程序中存setStorage
Dec 13 Javascript
VUE 单页面使用 echart 窗口变化时的用法
Jul 30 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缓冲 output_buffering的使用详解
2013/06/13 PHP
免费手机号码归属地API查询接口和PHP使用实例分享
2014/04/10 PHP
YII Framework框架教程之安全方案详解
2016/03/14 PHP
JavaScript自定义日期格式化函数详细解析
2014/01/14 Javascript
Jquery中ajax方法data参数的用法小结
2014/02/12 Javascript
jquery制作搜狐快站页面效果示例分享
2014/02/21 Javascript
js使用setTimeout实现定时炸弹的方法
2015/04/10 Javascript
使用requestAnimationFrame实现js动画性能好
2015/08/06 Javascript
jQuery 禁止表单用户名、密码自动填充功能
2017/10/30 jQuery
详解如何使用 vue-cli 开发多页应用
2017/12/16 Javascript
vue展示dicom文件医疗系统的实现代码
2018/08/27 Javascript
详解JavaScript作用域和作用域链
2019/03/19 Javascript
Python实现的HTTP并发测试完整示例
2020/04/23 Python
Python中的rfind()方法使用详解
2015/05/19 Python
对json字符串与python字符串的不同之处详解
2018/12/19 Python
python爬取cnvd漏洞库信息的实例
2019/02/14 Python
Python XlsxWriter模块Chart类用法实例分析
2019/03/11 Python
在Python中合并字典模块ChainMap的隐藏坑【推荐】
2019/06/27 Python
python绘制双Y轴折线图以及单Y轴双变量柱状图的实例
2019/07/08 Python
Python面向对象之继承原理与用法案例分析
2019/12/31 Python
详解Python实现进度条的4种方式
2020/01/15 Python
Tensorflow 1.0之后模型文件、权重数值的读取方式
2020/02/12 Python
Python网络爬虫信息提取mooc代码实例
2020/03/06 Python
小白教你PyCharm从下载到安装再到科学使用PyCharm2020最新激活码
2020/09/25 Python
Python是如何进行类型转换的
2013/06/09 面试题
魅力教师事迹材料
2014/01/10 职场文书
中英文求职信范文
2014/01/27 职场文书
协议书与合同的区别
2014/04/18 职场文书
圣诞节活动策划方案
2014/06/09 职场文书
中国在我心中演讲稿
2014/09/13 职场文书
高校师德师风自我剖析材料
2014/09/29 职场文书
财务工作失误检讨书
2015/02/19 职场文书
加入学生会自荐书
2015/03/05 职场文书
2015年学校办公室主任工作总结
2015/07/20 职场文书
nginx常用配置conf的示例代码详解
2022/03/21 Servers
Python之matplotlib绘制折线图
2022/04/13 Python