JavaScript 函数式编程
函数式编程强调纯函数、不可变数据和函数组合,代码更易测试和推理。
纯函数
相同输入永远返回相同输出,无副作用:
JavaScript
// 纯函数
function add(a, b) {
return a + b;
}
// 非纯函数(依赖外部状态)
let counter = 0;
function increment() {
counter++; // 副作用
return counter;
}
// 非纯函数(修改输入)
function addItem(arr, item) {
arr.push(item); // 修改原数组
return arr;
}
不可变性
避免直接修改数据,返回新副本:
JavaScript
// 可变方式(不推荐)
const user = { name: 'Alice', age: 25 };
user.age = 26;
// 不可变方式(推荐)
const updatedUser = { ...user, age: 26 };
// 数组不可变操作
const arr = [1, 2, 3];
const newArr = [...arr, 4]; // 添加
const filtered = arr.filter(x => x !== 2); // 删除
const mapped = arr.map(x => x * 2); // 修改
深拷贝工具
JavaScript
// 简单深拷贝
const deepClone = obj => JSON.parse(JSON.stringify(obj));
// 结构化克隆
const cloned = structuredClone(obj);
柯里化
将多参数函数转为单参数链式调用:
JavaScript
// 手动柯里化
function curry(fn) {
return function curried(...args) {
return args.length >= fn.length
? fn(...args)
: (...more) => curried(...args, ...more);
};
}
// 示例
const add = (a, b, c) => a + b + c;
const curriedAdd = curry(add);
curriedAdd(1)(2)(3); // 6
curriedAdd(1, 2)(3); // 6
函数组合
将多个函数串联执行:
JavaScript
// pipe: 从左到右
const pipe = (...fns) => x => fns.reduce((v, fn) => fn(v), x);
// compose: 从右到左
const compose = (...fns) => x => fns.reduceRight((v, fn) => fn(v), x);
// 使用
const double = x => x * 2;
const addOne = x => x + 1;
const toString = x => String(x);
const transform = pipe(double, addOne, toString);
transform(3); // "7" (3 * 2 + 1)
高阶函数模式
偏函数应用
JavaScript
const partial = (fn, ...presetArgs) => (...laterArgs) =>
fn(...presetArgs, ...laterArgs);
const multiply = (a, b, c) => a * b * c;
const double = partial(multiply, 2);
double(3, 4); // 24
记忆化
JavaScript
const memoize = fn => {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (!cache.has(key)) {
cache.set(key, fn(...args));
}
return cache.get(key);
};
};
const factorial = memoize(n => {
if (n <= 1) return 1;
return n * factorial(n - 1);
});
常用函数式工具
map/filter/reduce
JavaScript
const numbers = [1, 2, 3, 4, 5];
// 链式调用
numbers
.filter(x => x % 2 === 0)
.map(x => x * 2)
.reduce((sum, x) => sum + x, 0); // 12
函数式链式操作
JavaScript
// 无需中间变量的数据处理
const result = [1, 2, 3, 4, 5]
.filter(x => x > 2)
.map(x => x * x)
.reduce((a, b) => a + b, 0); // 50
函数式 vs 命令式
JavaScript
// 命令式
const doubled = [];
for (let i = 0; i < arr.length; i++) {
doubled.push(arr[i] * 2);
}
// 函数式
const doubled = arr.map(x => x * 2);
| 特点 | 命令式 | 函数式 |
|---|---|---|
| 关注点 | 如何做 | 做什么 |
| 状态 | 可变 | 不可变 |
| 副作用 | 允许 | 避免 |
| 测试 | 较难 | 容易 |
要点总结
- 纯函数无副作用,相同输入必返回相同输出
- 不可变性通过返回副本实现,避免直接修改
- 柯里化将多参数转为单参数链式调用
pipe/compose实现函数组合- 函数式代码更易测试、推理和并行
📝 发现内容有误?点击此处直接编辑