什么是函数的柯理化
柯里化(英语:Currying),又叫函数的部分求值,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
通俗一点来说:
- 柯里化就是一个函数原本有多个参数,只传入一个参数,生成一个新函数,由新函数接收剩下的参数来运行得到结果.
- 与柯里化类似的一个概念:高阶函数(可以参考我上一篇文章什么是高阶函数)
JavaScript高级程序设计里写到:
-
柯里化函数通常由以下步骤动态创建:调用另一个函数并为它传入要柯里化的函数和必要的参数.
-
高级程序设计上的通用例子:
function curry(fn) {
// 获取剩余参数 将类数组转化成数组
var args = Array.prototype.slice.call(arguments, 1);
return function() {
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.contact(innerArgs);
return fn.apply(null, finalArgs);
}
}
function add (num1, num2) {
return num1 + num2;
}
var curriedAdd = curry(add, 5);
alert(curriedAdd(3); // 8
这个一上来就给出结果可能不好理解,下面我们一步一步来,讲解柯理化的实现步骤及它解决了什么问题
我们目前有一个函数A
function A(a, b, c) {
return a + b + c;
}
假如我们已经有一个封装好的柯理化函数 curry
他接收 A
作为参数,能够将 A
转化成柯理化函数,返回的结果就是这个被转化后的函数
var _A = currying(A);
那么 _A
作为柯理化函数,他能够处理 A
剩下的剩余参数,因此要求下面的运行结果都是等价的:
_A(1, 2, 3);
_A(1, 2)(3);
_A(1)(2, 3);
_A(1)(2)(3);
A(1, 2, 3);
在简单的场景下,我们凭眼里来封装得到柯理化函数可能是下面这样的
function myA(a) {
return function(b) {
return function(c) {
return a + b + c;
}
}
}
那么下面的运算方式确实是等价的
A(1, 2, 3);
myA(1)(2)(3);
但是按照要求,要求 myA(1, 2)(3)
也要与其他的等价,但并不是,所以,这样封装的柯理化函数
自由度偏低,而且有些要求达不到
因此我们需要知道如何去封装一个柯理化的通用式
封装如下:
function curry(fn, args) {
args = args || []
var arity = fn.length
return function() {
var _args = Array.prototype.slice.call(arguments)
Array.prototype.unshift.call(_args, ...args)
_args = _args.concat(args)
if (_args.length < arity) {
return currying.call(null, fn, _args)
}
return fn.apply(null, _args)
}
}
遇到的坑(重要)
在编写函数柯理化的时候遇到了一些坑,虽然不大,但是没注意的话还是会掉下去的,既然我掉下去了,那么就记录下来防止大家掉下去吧
函数的长度:Function.length
问问大家,知道函数的长度吗?
什么?函数还有长度?不就字符串,数组有长度吗?
是的,函数有长度,函数的长度就表示 该函数有多少个必须要传入的参数,即形参的个数
那我们先来看一个例子
var fn = function(a, b) {}
console.log(fn.length);
不知道函数的长度的概念的人可能不知道这题的答案,但是根据上面的说法,不是有两个形参吗,那么好,答案不就是 2
吗,好那看下一题
var fn = function(a, b = []) {}
console.log(fn.length);
这个打印多少呢?有的人应该就有点蒙了,应该还是 2
吧,我之前也这样以为,但正确答案却是 1
,那么这是为什么呢
刚才说了,函数的长度表示该函数有多少个必须要传入的参数,即形参的个数,但是:形参数量不包括剩余参数个数,仅包括第一个具有默认值之前的参数个数,与之对应的是:arguments.length
是函数被调用是实际传参的个数
好的,知道结论后大家可以将下面的代码拷贝到浏览器控制台粘贴看看答案,加深一下印象
function fn1(a = () => {}, b = [], c) {}
function fn2(a, b = [], c) {}
function fn3(...args) {}
function fn4() { alert(arguments.length) }
console.log(fn1.length); // 0
console.log(fn2.length); // 1
console.log(fn3.length); // 0
console.log(fn4.length); // 0
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!