柯里化(Currying)是一种将多参数函数转换为一系列单参数函数的技术。它由数学家Haskell Curry命名,是函数式编程中的一个重要概念。
在JavaScript中,柯里化指的是将一个接受多个参数的函数转换为接受一个参数并返回一个新函数的过程,新函数继续接受下一个参数,直到所有参数都被收集完毕,最后返回结果。
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2));
}
}
}
}
// 使用示例
function sum(a, b, c) {
return a + b + c;
}
const curriedSum = curry(sum);
console.log(curriedSum(1)(2)(3)); // 6
console.log(curriedSum(1, 2)(3)); // 6
console.log(curriedSum(1)(2, 3)); // 6
const curry = fn => {
const curried = (...args) =>
args.length >= fn.length
? fn(...args)
: (...more) => curried(...args, ...more);
return curried;
};
解决方案:需要明确指定参数数量或使用占位符
function curryWithPlaceholder(fn) {
return function curried(...args) {
// 检查是否所有参数都已提供(跳过占位符)
const complete = args.length >= fn.length &&
!args.slice(0, fn.length).includes(curryWithPlaceholder.placeholder);
if (complete) {
return fn.apply(this, args);
} else {
return function(...args2) {
// 用实际参数替换占位符
const combined = args.map(arg =>
arg === curryWithPlaceholder.placeholder && args2.length ? args2.shift() : arg
).concat(args2);
return curried.apply(this, combined);
}
}
}
}
curryWithPlaceholder.placeholder = Symbol();
// 使用示例
const _ = curryWithPlaceholder.placeholder;
const fn = (a, b, c, d) => a + b + c + d;
const curriedFn = curryWithPlaceholder(fn);
console.log(curriedFn(1)(2)(3)(4)); // 10
console.log(curriedFn(1, _, 3)(2)(4)); // 10
console.log(curriedFn(1, _, _, 4)(2)(3)); // 10
解决方案:使用apply或call正确传递this
function curry(fn) {
return function curried(...args) {
const context = this; // 保存当前this
if (args.length >= fn.length) {
return fn.apply(context, args);
} else {
return function(...args2) {
return curried.apply(context, args.concat(args2));
}
}
}
}
// 使用示例
const obj = {
value: 10,
add: function(a, b) {
return this.value + a + b;
}
};
obj.curriedAdd = curry(obj.add);
console.log(obj.curriedAdd(1)(2)); // 13 (正确保留了this)
解决方案:对于性能敏感的场景,可以:
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = args.join('|');
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
};
}
const memoizedCurry = fn => {
const curried = memoize(function(...args) {
return args.length >= fn.length
? fn(...args)
: memoize((...more) => curried(...args, ...more));
});
return curried;
};
JavaScript柯里化是一种强大的函数转换技术,它通过将多参数函数转换为一系列单参数函数,提供了更大的灵活性和代码复用性。虽然柯里化可能会带来一些性能开销,但在大多数应用场景中,它带来的好处远大于其成本。理解柯里化的原理和应用场景,可以帮助开发者编写更简洁、更模块化的代码。