JavaScript 高阶函数与柯里化完整指南
1. 高阶函数基础
1.1 定义
高阶函数是指满足下列条件之一的函数:
- 接受一个或多个函数作为参数
- 返回一个函数作为结果
1.2 基本示例
// 接受函数作为参数
function operate(x, y, operator) {
return operator(x, y);
}
// 使用示例
const add = (a, b) => a + b;
const multiply = (a, b) => a * b;
console.log(operate(5, 3, add)); // 8
console.log(operate(5, 3, multiply)); // 15
// 返回函数作为结果
function createMultiplier(factor) {
return function(number) {
return number * factor;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
2. 常见的高阶函数
2.1 Array 方法中的高阶函数
const numbers = [1, 2, 3, 4, 5];
// map
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
// filter
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // [2, 4]
// reduce
const sum = numbers.reduce((acc, curr) => acc + curr, 0);
console.log(sum); // 15
// forEach
numbers.forEach(num => console.log(num));
2.2 自定义高阶函数
// 函数组合
function compose(...fns) {
return function(x) {
return fns.reduceRight((value, fn) => fn(value), x);
};
}
const addOne = x => x + 1;
const double = x => x * 2;
const addThenDouble = compose(double, addOne);
console.log(addThenDouble(3)); // 8 (3 + 1) * 2
// 函数记忆(缓存)
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
const expensiveFunction = memoize((n) => {
console.log('Computing...');
return n * 2;
});
console.log(expensiveFunction(5)); // Computing... 10
console.log(expensiveFunction(5)); // 10 (从缓存中获取)
3. 函数柯里化
3.1 柯里化定义
柯里化是将一个多参数函数转换成一系列单参数函数的过程。
3.2 基本实现
// 简单的柯里化实现
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
}
return function(...moreArgs) {
return curried.apply(this, args.concat(moreArgs));
};
};
}
// 使用示例
function add(a, b, c) {
return a + b + c;
}
const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3)); // 6
console.log(curriedAdd(1, 2)(3)); // 6
console.log(curriedAdd(1)(2, 3)); // 6
3.3 高级柯里化实现
// TypeScript 版本的柯里化
type Curry<P extends any[], R> =
P extends [infer First, ...infer Rest]
? (arg: First) => Rest extends []
? R
: Curry<Rest, R>
: R;
function curryTyped<P extends any[], R>(
fn: (...args: P) => R
): Curry<P, R> {
return function curried(...args: any[]): any {
if (args.length >= fn.length) {
return fn.apply(this, args);
}
return function(...moreArgs: any[]) {
return curried.apply(this, args.concat(moreArgs));
};
} as any;
}
// 使用示例
interface User {
name: string;
age: number;
}
function updateUser(id: number, key: keyof User, value: User[keyof User]) {
console.log(`Updating user ${id}: ${key} = ${value}`);
}
const curriedUpdate = curryTyped(updateUser);
const updateUser1 = curriedUpdate(1);
const updateUser1Name = updateUser1('name');
updateUser1Name('John'); // Updating user 1: name = John
4. 实际应用场景
4.1 事件处理
// 事件处理器生成器
const createEventHandler = (eventType) => (handler) => (element) => {
element.addEventListener(eventType, handler);
return element;
};
const handleClick = createEventHandler('click');
const handleHover = createEventHandler('mouseover');
const button = document.querySelector('button');
handleClick(e => console.log('Clicked'))(button);
handleHover(e => console.log('Hovered'))(button);
4.2 数据转换
// 数据转换管道
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);
const capitalize = str => str.toUpperCase();
const addExclamation = str => `${str}!`;
const repeat = str => `${str} ${str}`;
const transform = pipe(
capitalize,
addExclamation,
repeat
);
console.log(transform('hello')); // "HELLO! HELLO!"
4.3 API 调用
// API 调用包装器
const createApiCall = (baseUrl) => (endpoint) => async (params) => {
try {
const response = await fetch(`${baseUrl}${endpoint}`, {
method: 'POST',
body: JSON.stringify(params)
});
return response.json();
} catch (error) {
console.error('API Error:', error);
throw error;
}
};
const api = createApiCall('https://api.example.com');
const getUserData = api('/users');
const getOrderData = api('/orders');
// 使用
getUserData({ id: 123 }).then(data => console.log(data));
5. 最佳实践
5.1 性能考虑
- 使用记忆化避免重复计算
- 注意闭包导致的内存占用
- 合理使用柯里化,避免过度抽象
5.2 代码组织
- 保持函数纯净
- 使用有意义的函数名
- 适当的错误处理
- 注意函数组合的顺序
5.3 调试技巧
- 使用 console.log 跟踪函数执行
- 在开发环境保留详细的错误信息
- 使用 TypeScript 增加类型安全
6. 总结
高阶函数和柯里化的优点:
- 提高代码复用性
- 增加代码灵活性
- 提供更好的抽象
- 支持函数式编程范式
使用建议:
- 根据实际需求选择合适的抽象级别
- 平衡代码可读性和灵活性
- 考虑团队成员的接受程度
- 注意性能影响 高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。 1.若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数。 2.若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数。常见的高阶函数有:Promise、setTimeout、arr.map()等等 函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。