前端战五渣学JavaScript——函数柯里化

阅读本篇博客以前须要对JavaScript的闭包有一个很好的了解,能够看一下我以前写的《前端战五渣学JavaScript——闭包》javascript

我自认为你们是在了解闭包的状况下阅读这篇博客的。前端

最近对什么都提不起兴趣,什么都不想干,什么都不想学,游戏也不想打。。。哎。。可是最近看了一部国产动画电影《哪吒之魔童降世》,感受如今国产动画的水平真是愈来愈高了,很不错,值得一看哦java

什么是函数柯里化

函数柯里化(function currying),把函数作成咖喱味的??其实我初次据说这个词的时候,感受好高大上啊,音译,深奥,等我翻看了相关书籍(《JavaScript高级程序设计》)以及一些前辈写的博客之后,发现原来函数柯里化就是使用闭包返回一个函数闭包

柯里化的函数能够延迟接收参数,就是好比我一个函数须要接收的参数是两个,我执行的时候必须接收两个参数,不然我无法执行啊,是否是,就容易出问题。可是柯里化后的函数,能够先接收一个函数,而后再接收一个函数,这么说太生硬了,那咱们就来看一个简单的例子(也是全网最广泛的例子)⬇️app

这是普通的函数函数

// 正常咱们声明函数的时候是这样的
function 求两数之和(第一个数, 第二个数) {
  return 第一个数 + 第二个数
}
const 和 = 求两数之和(1, 2);
console.log(`两数之和为 ${和}`); // 3
复制代码

那咱们按照柯里化写出来的函数是什么样的呢

// 理解柯里化的思想
function 求两数之和(第一个数) {
  return function (第二个数) {
    return 第一个数 + 第二个数
  }
}
// 第一种方法
const 和 = 求两数之和(1)(2);
console.log(`第一种方法的两个数之和为 ${和}`);
// 第二种方法
const 已接收第一个数的求和函数 = 求两数之和(1);
const 两个数都已接收的和 = 已接收第一个数的求和函数(2);
console.log(`第二种方法的两个数之和为 ${两个数都已接收的和}`);
复制代码

从上面的函数对比咱们就能够发现,柯里化的函数能够先接收一个函数,而后在咱们须要的传入第二个参数的时候,咱们再传入,并执行最终的结果。post

因此咱们能够动态生成好比第一个参数相同,第二个参数不一样,或者第二个参数相同,第一个参数不一样的函数学习

把函数柯里化的函数

在咱们熟知的《JavaScript高级程序设计》中给出了一个方法,这个方法,可让咱们把一个原本不支持柯里化的函数,转化成支持柯里化思想的函数。动画

function 把函数柯里化(须要柯里化的函数) {
  const 调用柯里化时除了函数之外的参数 = Array.prototype.slice.call(arguments, 1);
  return function () {
    const 后接受的参数 = [...arguments];
    const 最终的参数 = [...调用柯里化时除了函数之外的参数, ...后接受的参数];
    return 须要柯里化的函数.apply(null, 最终的参数);
  }
}

function 求两数之和(第一个数, 第二个数) {
  return 第一个数 + 第二个数
}

const 柯里化的求两数之和 = 把函数柯里化(求两数之和, 1);

console.log(
  `被柯里化后的函数求的两数之和为 ${ 柯里化的求两数之和(2) }`
); // 被柯里化后的函数求的两数之和为 3
复制代码

咱们发现,咱们能够单独写一个函数,而后把一个普通函数转化成支持柯里化的函数,可是高级程序设计上提供的这个方法,只能提供两次调用,什么意思?咱们来看看lodashcurry方法是如何实现的ui

const _ = require('lodash');

function 求三个数之和(第一个数, 第二个数, 第三个数) {
  return 第一个数 + 第二个数 + 第三个数
}

const 柯里化后的求三个数之和 = _.curry(求三个数之和);

console.log(柯里化后的求三个数之和(1)(2)(3)); // 6
console.log(柯里化后的求三个数之和(1)(2, 3)); // 6
console.log(柯里化后的求三个数之和(1, 2, 3)); // 6
复制代码

这下咱们看到,lodash中对转化柯里化的处理,咱们能够任意调用被柯里化的函数,无论参数怎么传,只要传够三个就行,也无论是分几回传。

咱们本身来一个柯里化函数吧

咱们的需求是什么?

feature

  1. 须要把普通函数转化成柯里函数
  2. 只要参数没达到被转换函数的数量,就返回函数,保存已传参数
  3. 支持参数没达到被转换函数的数量时,无限调用

那咱们先来看看咱们须要转换的函数⬇️

const 封神榜 = (名字, 宝物, 出生地) => console.log(`我是${出生地}${名字},我有${宝物}`);

封神榜('哪吒', '乾坤圈', '陈塘关'); // 我是陈塘关的哪吒,我有乾坤圈
复制代码

看看咱们普通转化的结果是什么样的⬇️

const 封神榜 = 名字 => 宝物 => 出生地 => console.log(`我是${出生地}${名字},我有${宝物}`);

封神榜('哪吒')('乾坤圈')('陈塘关');
复制代码

普通转化的函数,咱们传参不是很自由,必须穿三次,每次传一个,那咱们来个牛逼的⬇️

const 封神榜 = (名字, 宝物, 出生地) => console.log(`我是${出生地}${名字},我有${宝物}`);

const 柯里化 = (须要柯里化的函数, ...参数) => 须要柯里化的函数.length <= 参数.length
  ? 须要柯里化的函数(...参数)
  : (...更多参数) => 柯里化(须要柯里化的函数, ...参数, ...更多参数);

const 柯里化后的封神榜 = 柯里化(封神榜);

柯里化后的封神榜('哪吒', '乾坤圈', '陈塘关'); // 我是陈塘关的哪吒,我有乾坤圈
柯里化后的封神榜('孙悟空')('金箍鲁棒')('花果山'); // 我是花果山的孙悟空,我有金箍鲁棒
柯里化后的封神榜('雷震子', '黄金棍')('终南山玉柱洞'); // 我是终南山玉柱洞的雷震子,我有黄金棍
柯里化后的封神榜()()()()()()()()('姜子牙', '打神鞭', '昆仑山'); // 我是昆仑山的姜子牙,我有打神鞭
复制代码

看,如今咱们实现的柯里化函数已经基本知足咱们刚才提的需求了

固然,有柯里化就有反柯里化,可是我以为没什么必要,我既然都已经柯里化了,柯里化后的函数固然支持非柯里化函数的传参方式,可是有兴趣的小伙伴仍是能够了解一下的

总结

其实函数柯里化这个概念,可能咱们以前没有据说过,可是工做或者学习中咱们可能或多或少接触过这种方式,只是不知道这么写就是柯里化,这个函数就是柯里化函数。

柯里化函数这种方式方法仍是很实用的,在平常开发过程当中仍是会遇到须要这种需求的地方。


我是前端战五渣,一个前端界的小学生。

相关文章
相关标签/搜索