004-函数式编程[FP]深度解析

函数式编程(FP)深度解析

函数式编程核心理解

函数式编程是一种声明式编程范式,核心思想是”通过纯函数组合构建程序”,主要特点:

特性 说明 示例
纯函数 相同输入永远返回相同输出,无副作用(不改变外部状态) const add = (a,b) => a + b;
不可变性 数据创建后不可修改,通过生成新数据实现变更 使用map代替for循环+push
函数一等公民 函数可作为参数/返回值/变量 const logger = fn => (...args) => { console.log(...args); return fn(...args); }
引用透明 函数调用可直接替换为其返回值 add(2,3) 可替换为 5
高阶函数 接收或返回函数的函数 map, filter, reduce
函数组合 将多个函数组合成新函数(f(g(x)) const process = compose(validate, format, save);

函数柯里化(Currying)详解

概念:将多参数函数转换为一系列单参数函数的过程
f(a, b, c)f(a)(b)(c)

实现原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 基础柯里化实现
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return (...nextArgs) => curried.apply(this, [...args, ...nextArgs]);
}
};
}

// 使用示例
const sum = (a, b, c) => a + b + c;
const curriedSum = curry(sum);
console.log(curriedSum(1)(2)(3)); // 6


#### 柯里化特点

1. **参数延迟传递**:分步传入参数
2. **函数复用性**:基于部分参数创建新函数
3. **动态函数生成**:按需组合函数逻辑

### 实际应用场景

#### 场景1:参数复用

```javascript
// 通用URL构建器
const buildUrl = curry((protocol, domain, path) =>
`${protocol}://${domain}/${path}`
);

// 创建特定环境URL生成器
const createHttpsUrl = buildUrl('https');
const githubUrl = createHttpsUrl('github.com');
const apiUrl = createHttpsUrl('api.example.com');

console.log(githubUrl('user/repo')); // https://github.com/user/repo
console.log(apiUrl('v1/data')); // https://api.example.com/v1/data

场景2:事件处理

1
2
3
4
5
6
7
8
9
10
11
// 通用事件监听器
const addListener = curry((eventType, element, handler) =>
element.addEventListener(eventType, handler)
);

// 创建特定元素监听器
const addButtonListener = addListener('click')(document.querySelector('button'));

// 添加不同按钮处理逻辑
addButtonListener(handleLogin);
addButtonListener(handleLogout);

场景3:数据校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 校验规则组合
const validate = curry((rules, value) =>
rules.every(rule => rule(value))
);

// 创建特定校验器
const isString = v => typeof v === 'string';
const minLength = len => v => v.length >= len;
const hasNumber = v => /\d/.test(v);

// 密码校验器
const isValidPassword = validate([
isString,
minLength(8),
hasNumber
]);

console.log(isValidPassword('abc123')); // false (长度不足)
console.log(isValidPassword('securePwd1')); // true

场景4:React高阶组件

1
2
3
4
5
6
7
8
9
10
11
12
// 柯里化HOC
const withFeatures = curry((features, Component) =>
props => <Component {...props} features={features} />
);

// 创建特性注入器
const withAnalytics = withFeatures(['analytics']);
const withLogger = withFeatures(['logger']);

// 应用特性
const DashboardWithAnalytics = withAnalytics(Dashboard);
const AppWithLogger = withLogger(App);

函数式编程实践价值

  1. 可维护性:纯函数+不可变性使代码更可预测
  2. 可测试性:无副作用函数易于单元测试
  3. 并发安全:避免共享状态带来的竞态条件
  4. 模块化:函数组合实现高度复用
  5. 调试友好:引用透明性简化问题追踪

使用注意事项

1
2
3
4
5
6
7
8
// 避免过度柯里化
// 反模式:curried(1)(2)(3)(4)(5)...
// 解决方案:合理设计参数分组

// 性能考量:深度柯里化可能创建大量闭包
// 优化方案:限制柯里化深度,关键路径避免使用

// 团队协作:在非FP团队中适度使用,避免认知负担

现代JS中的FP支持

工具 用途 示例
Lodash/fp 函数式工具库 _.map(_.trim, strings)
Ramda 纯函数式工具库 R.compose(R.filter(f), R.map(g))
React Hooks 函数组件+状态管理 useMemo, useCallback
Redux 不可变状态管理 reducer(state, action) => newState
1