FE-Interview
FE-Interview copied to clipboard
第 15 题:实现 add(1)(2)(3)
欢迎在下方发表您的优质见解
考点:函数柯里化
函数柯里化概念: 柯里化(Currying)是把接受多个参数的函数转变为接受一个单一参数的函数,并且返回接受余下的参数且返回结果的新函数的技术。
1)粗暴版
function add (a) {
return function (b) {
return function (c) {
return a + b + c;
}
}
}
console.log(add(1)(2)(3)); // 6
2)柯里化解决方案
- 参数长度固定
const curry = (fn) =>
(judge = (...args) =>
args.length === fn.length
? fn(...args)
: (...arg) => judge(...args, ...arg));
const add = (a, b, c) => a + b + c;
const curryAdd = curry(add);
console.log(curryAdd(1)(2)(3)); // 6
console.log(curryAdd(1, 2)(3)); // 6
console.log(curryAdd(1)(2, 3)); // 6
- 参数长度不固定
function add (...args) {
//求和
return args.reduce((a, b) => a + b)
}
function currying (fn) {
let args = []
return function temp (...newArgs) {
if (newArgs.length) {
args = [
...args,
...newArgs
]
return temp
} else {
let val = fn.apply(this, args)
args = [] //保证再次调用时清空
return val
}
}
}
let addCurry = currying(add)
console.log(addCurry(1)(2)(3)(4, 5)()) //15
console.log(addCurry(1)(2)(3, 4, 5)()) //15
console.log(addCurry(1)(2, 3, 4, 5)()) //15
function currying(){
let args = [...arguments]
temp.getValue = ()=>{
return args.reduce((a,b)=> a + b, 0)
}
function temp(...arg){
if(arg.length){
args = [
...args,
...arg
]
return temp
}
}
return temp
}
const add = (a: number, b: number, c: number) => a + b + c;
const adding = (...args: number[]) => args.reduce((pre, cur) => pre + cur, 0);
//参数确定
const curry = (fn: Function) => {
let args = [];
return function temp(...newArgs) {
args.push(...newArgs);
if (args.length === fn.length) {
const val = fn.apply(this, args);
args = [];
return val;
} else {
return temp;
}
};
};
//参数不确定
const currying = (fn: Function) => {
let args = [];
return function temp(...newArgs) {
if (newArgs.length) {
args.push(...newArgs);
return temp;
} else {
const val = fn.apply(this, args);
args = [];
return val;
}
};
};
const curryAdd = curry(add);
console.log(curryAdd(1)(2)(3)); // 6
console.log(curryAdd(1, 2)(3)); // 6
console.log(curryAdd(1)(2, 3)); // 6
let addCurry = currying(adding);
console.log(addCurry(1)(2)(3)(4, 5)()); //15
console.log(addCurry(1)(2)(3, 4, 5)()); //15
console.log(addCurry(1)(2, 3, 4, 5)()); //15
function curring(fn,arr = []){
var length = fn.length;
return (...args) => {
const currentArr = [...arr.push(args)]
if(arr.length < length){
return curring(fn,currentArr];
} else {
fn(...currentArr )
}
}
}
function currying(fn, args = []) {
return function temp(...innerArgs) {
if (innerArgs.length > 0) {
// 收集后面传入的参数
args = [...args, ...innerArgs];
// 返回函数供后面可以继续调用
return temp;
} else {
const val = fn.apply(this, args);
// 清空参数数组,为了保证下次执行函数可以继续迭代
args = [];
return val;
}
}
}
// 求和函数
const add = (...args) => args.reduce((a, b) => a + b);
let addCurry = currying(add)
console.log(addCurry(1)(2)(3)(4, 5)()) //15
console.log(addCurry(1)(2)(3, 4, 5)()) //15
console.log(addCurry(1)(2, 3, 4, 5)()) //15
除了typeof为function 正常运算都没问题
function add(num) {
const add2 = (num2) => {
num = num + num2;
add2.toString = () => num;
return add2;
}
return add2;
}
add(1)(2)(3) + 5 // 11
add(1)(2)(3)(4) // ƒ 10
有个疑问,就是参数长度不固定时,addCurry(1)(2)(3)(4, 5)(),最后的需要加函数执行的(),但是题目不是没有吗,也就是只要addCurry(1)(2)(3)(4, 5)这样
function curry(fn, ...args) {
if (args.length >= fn.length) {
return fn(...args);
}
return (...args2) => curry(fn, ...args, ...args2);
}
function sum(a, b, c) {
return a + b + c;
}
let add = curry(sum);
console.log(add(1)(2)(3));
function add (...params) {
let result = params.reduceRight((a, b) => a + b)
const tmp = (...paramsInit) => {
result = [...paramsInit, result].reduceRight((a, b) => a + b)
return tmp
}
tmp.toString = () => `${result}`
tmp.valueOf = () => result
return tmp
}
可以这样实现 @ABoyCDog
const curryAdd = (...args) => {
const Add = (...args2) => {
return curry(...args, ...args2)
}
Add.toString = () => args.reduce((t, v) => t+v);
return Add
}
console.log(curryAdd(1)(2)(3,4))
function curry(fn, args) {
var length = fn.length;
args = args || [];
return function () {
newArgs = args.conct(Array.prototype.slice.call(arguments));
return newArgs.length < length
? curry.call(this, fn, newArgs)
: fn.apply(this, newArgs);
};
}
function multiFn(a, b, c) {
return a * b * c;
}
var multi = curry(multiFn);
console.log(multi(2)(3)(4));
const sum = (arr) => { return arr.reduce((pre, cur, index) => { return pre + cur }, 0) }
function add() { const outArgs = Array.from(arguments) let res = sum(outArgs);
function newAdd() { if (arguments.length > 0) { const innerArgs = Array.from(arguments); res += sum(innerArgs) return newAdd } else { return res; } }
newAdd.valueOf = function () { return res }
newAdd.toString = function () { return res + '' }
return newAdd }
var result = add(1, 2)(3)(4)(5); // 参数可能为多个的情况下
console.log(result());
function curry(fn, args) {
const { length } = fn;
const params = args || [];
return function() {
const args = params.concat([].slice.call(arguments));
if (args.length < length) {
return curry.apply(this, fn, args);
} else {
return fn.apply(this, args);
}
}
}
const curryAdd = (...args) => { const Add = (...args2) => { return curry(...args, ...args2) } Add.toString = () => args.reduce((t, v) => t+v); return Add } console.log(curryAdd(1)(2)(3,4))
测一测吧,测好了再发出来。curry已经undefined了。
const curry = (fn) => {
const prevArgs = [];
const rec = (...currArgs) => {
prevArgs.push(...currArgs);
if(fn.length - prevArgs.length <= 0) {
return fn(...prevArgs);
}
return rec;
}
return rec;
}
const add = (a: number, b: number, c: number) => a + b + c;
const curryAdd = curry(add);
函数的柯里化的应用
const curry = (fn, args) => {
const length = fn.length;
let _args = args || [];
return function () {
let argArray = _args.slice(0);
for (let i = 0; i < arguments.length; i++) {
argArray.push(arguments[i]);
}
if (argArray.length < length) {
return curry(fn, argArray);
} else {
return fn.apply(this, argArray);
}
}
}
const add = curry(function (a, b, c) {
return a + b + c;
})
console.log(add(1)(2)(3));
const add = a => b => c => a + b + c
function curry(fn) { const length = fn.length return function _curry(...args) { if (args.length >= length) { return fn.apply(this, args) } else { return _curry.bind(this, ...args) } } } // 测试 function add(x, y, z) { return this.val + x + y + z } let fun1 = curry(add) let obj = { val: 10, fun1 } console.log(obj.fun1(1)(2)(3))
function curry(...args1) {
const fn = args1[0]
const restArgs = args1.slice(1)
function curried(...args2) {
return curry.call(this, fn, ...[...restArgs, ...args2])
}
curried.toString = function() {
return fn.call(this, ...restArgs)
}
return curried
}
function sum(...args) {
let result = 0
args.forEach(arg => {
result += arg
})
return result
}
const add = curry(sum)
// toString 修改了但是不生效,需要自己利用 + 操作符进行转换
console.log(+add(1)(2)(3, 4, 5))
暴力写法
function add(a) {
return function (b) {
return function (c) {
return a + b + c;
};
};
}
console.log(add(1)(2)(3))
如果不限调用3次呢,比如add(1)(2)(3)(4)返回8
// 通过返回一个拥有获取值方法的函数
function add(x) {
let sum = x;
function innerAdd(y) {
sum += y;
return innerAdd;
}
innerAdd.getResult = function () {
return sum;
};
return innerAdd;
}
console.log(add(1)(2)(3)(4).getResult()); // 输出 10
// 缺点:获取值时需要额外调用.getResult()
题目没说add(1)(2)(3)就是返回值了,有没有可能是类里的方法
class MyNumber {
constructor(value) {
this.value = value;
}
add(num) {
this.value += num;
return this.add.bind(this);
}
}
const myNum = new MyNumber(0);
myNum.add(1)(2)(3);
console.log(myNum.value);
函数柯里化
// Function.length返回函数必传参数的长度
const curry = (fn) => {
return function curried(...args) {
if (args.length >= fn.length) {
return fn(...args);
} else {
return function (...nextArgs) {
return curried(...args, ...nextArgs);
};
}
};
};
const baseAdd = (a, b, c) => a + b + c;
const add = curry(baseAdd);
console.log(add(1)(2)(3)); // 6
console.log(add(1, 2)(3)); // 6
console.log(add(1)(2, 3)); // 6
console.log(add(1, 2, 3)); // 6
console.log(add(1)(2)); // 返回方法
try {
console.log(add(1)(2)(3)(4)); // 报错
} catch (error) {
console.error(error);
}
// 缺点,baseAdd长度写死,比暴力好在修改baseAdd更简单
不限长度的函数柯里化
const infiniteCurry = (fn) => {
let lastArgsLength = 0;
return function curried(...args) {
if (args.length === lastArgsLength) {
return fn(...args);
} else {
lastArgsLength = args.length;
return function (...nextArgs) {
return curried(...args, ...nextArgs);
};
}
};
};
const infiniteAdd = (...args) => {
return Array.from(args).reduce((a, b) => a + b);
};
const add = infiniteCurry(infiniteAdd);
console.log(add(1)(2)());
console.log(add(1)(2)(3)());
console.log(add(1)(2)(3)(4)());
console.log(add(1, 2, 3)(4, 5)());
console.log(add(1, 2, 3, 4, 5, 6)());
// 缺点:获取值时要()