函数式编程概念
理解纯函数、柯里化、高阶函数和副作用
问题
解释函数式编程中的纯函数、柯里化、高阶函数和副作用。
解答
纯函数
相同输入永远返回相同输出,且没有副作用。
// 纯函数:只依赖输入,不修改外部状态
function add(a, b) {
return a + b;
}
// 非纯函数:依赖外部变量
let count = 0;
function increment() {
return ++count; // 每次调用结果不同
}
// 非纯函数:修改了输入参数
function addItem(arr, item) {
arr.push(item); // 修改了原数组
return arr;
}
// 纯函数版本
function addItemPure(arr, item) {
return [...arr, item]; // 返回新数组
}
副作用
函数执行过程中对外部环境产生的影响。
// 常见副作用
function sideEffects() {
console.log('打印日志'); // 控制台输出
document.title = 'New Title'; // 修改 DOM
localStorage.setItem('key', 'value'); // 存储操作
fetch('/api'); // 网络请求
}
// 管理副作用:将副作用隔离
function calculatePrice(price, discount) {
return price * (1 - discount); // 纯计算
}
function displayPrice(price) {
document.getElementById('price').textContent = price; // 副作用隔离
}
高阶函数
接收函数作为参数或返回函数的函数。
// 接收函数作为参数
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
const evens = numbers.filter(n => n % 2 === 0);
const sum = numbers.reduce((acc, n) => acc + n, 0);
// 返回函数
function multiply(a) {
return function(b) {
return a * b;
};
}
const double = multiply(2);
console.log(double(5)); // 10
// 实际应用:防抖函数
function debounce(fn, delay) {
let timer = null;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
const debouncedSearch = debounce(query => {
console.log('搜索:', query);
}, 300);
柯里化
将多参数函数转换为一系列单参数函数。
// 普通函数
function add(a, b, c) {
return a + b + c;
}
add(1, 2, 3); // 6
// 柯里化版本
function curriedAdd(a) {
return function(b) {
return function(c) {
return a + b + c;
};
};
}
curriedAdd(1)(2)(3); // 6
// 箭头函数简写
const curriedAddArrow = a => b => c => a + b + c;
// 通用柯里化函数
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));
};
};
}
// 使用
const curriedSum = curry((a, b, c) => a + b + c);
console.log(curriedSum(1)(2)(3)); // 6
console.log(curriedSum(1, 2)(3)); // 6
console.log(curriedSum(1)(2, 3)); // 6
// 柯里化应用:参数复用
const log = curry((level, message) => {
console.log(`[${level}] ${message}`);
});
const info = log('INFO');
const error = log('ERROR');
info('应用启动'); // [INFO] 应用启动
error('连接失败'); // [ERROR] 连接失败
函数组合
将多个函数组合成一个函数。
// compose:从右到左执行
const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x);
// pipe:从左到右执行
const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x);
// 示例
const addOne = x => x + 1;
const double = x => x * 2;
const square = x => x * x;
const compute = pipe(addOne, double, square);
console.log(compute(2)); // ((2 + 1) * 2)² = 36
// 实际应用:数据处理管道
const users = [
{ name: 'Alice', age: 25, active: true },
{ name: 'Bob', age: 30, active: false },
{ name: 'Charlie', age: 35, active: true }
];
const getActiveNames = pipe(
users => users.filter(u => u.active),
users => users.map(u => u.name),
names => names.join(', ')
);
console.log(getActiveNames(users)); // "Alice, Charlie"
关键点
- 纯函数:相同输入相同输出,无副作用,便于测试和缓存
- 副作用:对外部环境的影响,应隔离管理而非完全消除
- 高阶函数:函数作为参数或返回值,是函数式编程的基础
- 柯里化:参数复用、延迟执行、函数组合的基础
- 函数组合:将小函数组合成复杂功能,提高代码复用性
目录