js实现参数定长/不定长的柯里化
文章原文: https://www.cnblogs.com/yalong/p/14298085.html
题目1:把一个计算加法的函数fn 进行柯里化,其中fn 分为 参数个数固定 和 参数个数不固定两种
参数个数固定的柯里化实现:
function fn(a, b, c) {
return a + b + c
}
function curry(fn) {
// 获取原函数的参数长度
const argLen = fn.length;
// 保存预置参数, 当预置参数 有三个的时候 直接返回了函数,需要单独执行一次
const presetArgs = [].slice.call(arguments, 1)
// 返回一个新函数
return function() {
// 新函数调用时会继续传参
const restArgs = [].slice.call(arguments)
const allArgs = [...presetArgs, ...restArgs]
if (allArgs.length >= argLen) {
// 如果参数够了,就执行原函数
return fn.apply(null, allArgs)
} else {
// 否则继续柯里化
return curry.call(null, fn, ...allArgs)
}
}
}
// 用例一
let c1 = curry(fn, 1);
let c2 = curry(c1, 2);
let c3 = curry(c2, 3);
console.log(c3()) // 6
// 用例二
let curried = curry(fn);
console.log(curried(1, 2, 3)) // 6
console.log(curried(1, 2)(3)) // 6
console.log(curried(1)(2, 3)) // 6
console.log(curried(1)(2)(3)) // 6
// 用例三
// 注意这个, 因为初始的时候 把参数全部传进去了,导致返回的是一个函数, 没能走到 apply 的立即执行
console.log(curry(fn, 1, 2, 3)()) // 6
console.log(curry(fn, 1, 2)(3)) // 6
console.log(curry(fn, 1)(2, 3)) // 6
console.log(curry(fn, 1)(2)(3)) // 6
参数个数不固定的柯里化实现
function curry(fn) {
// 保存预置参数
const presetArgs = [].slice.call(arguments, 1)
// 返回一个新函数
function curried () {
// 新函数调用时会继续传参
const restArgs = [].slice.call(arguments)
const allArgs = [...presetArgs, ...restArgs]
// 下面这个相当于 return currl(fn, ...allArgs)
return curry.call(null, fn, ...allArgs)
}
// 重写toString
curried.toString = function() {
return fn.apply(null, presetArgs)
// 下面这个是一样的
// return fn.call(null, ...presetArgs)
}
return curried;
}
function fn() {
return [...arguments].reduce((prev, curr) => {
return prev + curr
}, 0)
}
var add = curry(fn);
console.log(add(1)(2)(3)(4)) // 10
console.log(add(1, 2)(3, 4)(5, 6)) // 21
题目2: 实现add(1)(2)(3)(4)的打印结果为10,并且要求可以随意调用,不过每次只传一个参数,如add(1)(2)(3)(4)(5)的打印结果为15
实现代码如下:
function add(x) {
let sum = x;
let tmp = function (y) {
sum = sum + y;
return tmp;
};
tmp.toString = function () {
return sum;
};
return tmp;
}
console.log(add(1)(2)(3) + '') // 6
console.log(add(1)(2)(3)(4) + '') // 10
console.log(add(1)(2)(3)(4)(5) + '') // 15
题目3: 实现add(1, 2)(3)的打印结果为6,add(1)(2, 3, 4)(5) 结果为15, 意思就是 传递的参数个数不固定
实现代码如下:
function add () {
let args = [...arguments];
let fn = function () {
args.push(...arguments);
return fn
}
fn.toString=function(){
return args.reduce((a, b) => {
return a + b
})
}
return fn
}
console.log(add(1, 2)(3) + '') // 6
console.log(add(1)(1,2,3)(2) + '') // 9
console.log(add(1)(2, 3, 4)(5) + '') // 15
上面用到了toString 这里就联想到了valueOf 这两者的区别简单来说如下:
- valueOf():返回最适合该对象类型的原始值
- toString(): 将该对象的原始值以字符串形式返回
这两个方法一般是交由JS去隐式调用,以满足不同的运算情况。
在数值运算里,会优先调用valueOf(),如a + b
在字符串运算里,会优先调用toString(),如alert(c)。
当然更深入的说法还有,不过这里就不讨论了。