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


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 相关文章推荐
VBScript版代码高亮
Jun 26 Javascript
javascript js cookie的存储,获取和删除
Dec 29 Javascript
js特殊字符转义介绍
Nov 05 Javascript
Seajs的学习笔记
Mar 04 Javascript
Underscore.js常用方法总结
Feb 28 Javascript
JavaScript设置获取和设置属性的方法
Mar 04 Javascript
javascript实现检验的各种规则
Jul 31 Javascript
jQuery插件imgPreviewQs实现上传图片预览
Jan 15 Javascript
jquery.tableSort.js表格排序插件使用方法详解
Aug 12 Javascript
JQuery实现文字无缝滚动效果示例代码(Marquee插件)
Mar 07 Javascript
详解基于vue-cli优化的webpack配置
Nov 06 Javascript
微信小程序新手教程之页面打开数量限制
Mar 03 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的中问验证码
2006/11/25 PHP
微盾PHP脚本加密专家php解密算法
2020/09/13 PHP
laravel创建类似ThinPHP中functions.php的全局函数
2016/11/26 PHP
js滚动条多种样式,推荐
2007/02/05 Javascript
JS trim去空格的最佳实践
2011/10/30 Javascript
JSON 数字排序多字段排序介绍
2013/09/18 Javascript
jquery操作checked属性以及disabled属性的多种方法
2014/06/20 Javascript
javascript实现的HashMap类代码
2014/06/27 Javascript
JavaScript的9种继承实现方式归纳
2015/05/18 Javascript
JQuery通过AJAX从后台获取信息显示在表格上并支持行选中
2015/09/15 Javascript
jQuery 1.9.1源码分析系列(十)事件系统之主动触发事件和模拟冒泡处理
2015/11/24 Javascript
js数组去重的N种方法(小结)
2018/06/07 Javascript
vue element动态渲染、移除表单并添加验证的实现
2019/01/16 Javascript
使用Vant完成DatetimePicker 日期的选择器操作
2020/11/12 Javascript
[59:30]完美世界DOTA2联赛PWL S3 access vs LBZS 第二场 12.20
2020/12/23 DOTA
python的urllib模块显示下载进度示例
2014/01/17 Python
Django学习笔记之Class-Based-View
2017/02/15 Python
快速查询Python文档方法分享
2017/12/27 Python
Python/ArcPy遍历指定目录中的MDB文件方法
2018/10/27 Python
linux下安装python3和对应的pip环境教程详解
2019/07/01 Python
python中提高pip install速度
2020/02/14 Python
Python PyQt5运行程序把输出信息展示到GUI图形界面上
2020/04/27 Python
Python基于httpx模块实现发送请求
2020/07/07 Python
canvas学习笔记之2d画布基础的实现
2019/02/21 HTML / CSS
日本著名的平价时尚女性购物网站:Fifth
2016/08/24 全球购物
沙特阿拉伯电子产品和家用电器购物网站:Black Box
2019/07/24 全球购物
英国鞋网:Rubber Sole
2020/03/03 全球购物
美国名牌手表折扣网站:Jomashop
2020/05/22 全球购物
给医务人员表扬信
2014/01/12 职场文书
幼儿园消防安全制度
2014/01/26 职场文书
铣床操作工岗位职责
2014/06/13 职场文书
邮政竞聘演讲稿
2014/09/03 职场文书
初中学习计划书范文
2014/09/15 职场文书
2014年护理部工作总结
2014/11/14 职场文书
关于学习的决心书
2015/02/05 职场文书
归元寺导游词
2015/02/06 职场文书