普通视图

发现新文章,点击刷新页面。
今天 — 2025年7月2日首页

JavaScript 函数式编程思想与柯里化的深度剖析

作者 天涯学馆
2025年7月1日 22:39

JavaScript 作为一门多范式语言,既支持面向对象编程,也为函数式编程(Functional Programming, FP)提供了强大的支持。函数式编程以其声明式、不可变性和高阶函数等特性,正在现代前端开发中占据越来越重要的地位。而柯里化(Currying)作为函数式编程的核心技术之一,通过将多参数函数转换为单参数函数链,极大地提升了代码的灵活性和复用性。


1. 函数式编程的基础

1.1 什么是函数式编程?

函数式编程是一种编程范式,强调将计算过程建模为数学函数的求值,避免状态变化和可变数据。其核心思想包括:

  • 纯函数:函数的输出仅依赖于输入,且无副作用。
  • 不可变性:数据一旦创建不可修改,变化通过创建新数据实现。
  • 高阶函数:函数可以作为参数传递或作为返回值返回。
  • 声明式:关注“做什么”而非“怎么做”,代码更简洁。

在 JavaScript 中,函数是一等公民(First-Class Citizen),支持高阶函数、闭包等特性,使其天然适合函数式编程。

1.2 函数式编程的核心原则

  • 纯函数:相同的输入始终产生相同的输出,无副作用。例如:

    function add(a, b) {
      return a + b;
    }
    console.log(add(2, 3)); // 5
    

    反例(非纯函数):

    let total = 0;
    function addToTotal(value) {
      total += value;
      return total;
    }
    
  • 不可变性:避免直接修改数据:

    const numbers = [1, 2, 3];
    const doubled = numbers.map(n => n * 2); // [2, 4, 6]
    console.log(numbers); // [1, 2, 3](原数组未变)
    
  • 避免副作用:函数不应修改外部状态:

    const log = console.log;
    function greet(name) {
      log(`Hello, ${name}`); // 副作用
      return `Hello, ${name}`;
    }
    
  • 函数组合:通过组合小函数实现复杂逻辑:

    const compose = (f, g) => x => f(g(x));
    const addOne = x => x + 1;
    const double = x => x * 2;
    const addOneThenDouble = compose(double, addOne);
    console.log(addOneThenDouble(5)); // 12
    

1.3 为什么在 JavaScript 中使用函数式编程?

  • 可预测性:纯函数和不可变性降低调试难度。
  • 模块化:高阶函数和函数组合提升代码复用性。
  • 并发友好:无状态操作更适合异步和并发场景。
  • 现代框架支持:React、Redux 等框架大量采用函数式思想。

2. 核心函数式编程概念

2.1 纯函数与副作用

纯函数是函数式编程的基石。实现纯函数需遵循:

  • 输入决定输出:不依赖外部变量。
  • 无外部修改:不更改全局状态或 DOM。

示例:

function filterEvens(numbers) {
  return numbers.filter(n => n % 2 === 0);
}
console.log(filterEvens([1, 2, 3, 4])); // [2, 4]

避免副作用:

// 非纯函数
let counter = 0;
function increment() {
  counter++;
  return counter;
}

// 纯函数
function incrementCounter(current) {
  return current + 1;
}

2.2 高阶函数

高阶函数接受函数作为参数或返回函数。JavaScript 的数组方法(如 mapfilterreduce)是典型的高阶函数。

const numbers = [1, 2, 3, 4];
const doubled = numbers.map(n => n * 2); // [2, 4, 6, 8]
const evens = numbers.filter(n => n % 2 === 0); // [2, 4]
const sum = numbers.reduce((acc, n) => acc + n, 0); // 10

自定义高阶函数:

function withLogging(fn) {
  return (...args) => {
    console.log(`Calling ${fn.name} with`, args);
    const result = fn(...args);
    console.log(`Result:`, result);
    return result;
  };
}

const add = (a, b) => a + b;
const loggedAdd = withLogging(add);
loggedAdd(2, 3);
// Calling add with [2, 3]
// Result: 5

2.3 闭包与函数式编程

闭包允许函数访问其定义时的词法作用域,是实现函数式编程的重要机制。

function createCounter() {
  let count = 0;
  return {
    increment: () => ++count,
    get: () => count,
  };
}

const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.get()); // 1

闭包实现私有状态:

function createUser(name) {
  let _name = name;
  return {
    getName: () => _name,
    setName: newName => (_name = newName),
  };
}

const user = createUser('Alice');
console.log(user.getName()); // Alice
user.setName('Bob');
console.log(user.getName()); // Bob

2.4 不可变性

JavaScript 中的数组和对象是可变的,需通过复制实现不可变性。

数组不可变操作:

const numbers = [1, 2, 3];
const newNumbers = [...numbers, 4]; // [1, 2, 3, 4]
console.log(numbers); // [1, 2, 3]

对象不可变操作:

const user = { name: 'Alice', age: 30 };
const updatedUser = { ...user, age: 31 };
console.log(user); // { name: 'Alice', age: 30 }
console.log(updatedUser); // { name: 'Alice', age: 31 }

使用 Object.freeze

const config = Object.freeze({
  apiUrl: 'https://api.example.com',
  timeout: 5000,
});
config.apiUrl = 'new-url'; // 无效果
console.log(config.apiUrl); // https://api.example.com

2.5 函数组合与管道

函数组合通过将多个函数串联实现复杂逻辑。

组合(compose):

const compose = (...fns) => x => fns.reduceRight((y, f) => f(y), x);
const addOne = x => x + 1;
const double = x => x * 2;
const addOneThenDouble = compose(double, addOne);
console.log(addOneThenDouble(5)); // 12

管道(pipe):

const pipe = (...fns) => x => fns.reduce((y, f) => f(y), x);
const addOneThenDouble = pipe(addOne, double);
console.log(addOneThenDouble(5)); // 12

3. 柯里化的核心概念

3.1 什么是柯里化?

柯里化是将一个多参数函数转换为一系列单参数函数的过程。形式上:

// 非柯里化
function add(a, b) {
  return a + b;
}

// 柯里化
function curriedAdd(a) {
  return function(b) {
    return a + b;
  };
}

const addFive = curriedAdd(5);
console.log(addFive(3)); // 8

3.2 柯里化的优势

  • 参数复用:固定部分参数,生成专用函数。
  • 延迟执行:只有提供所有参数时才执行计算。
  • 函数组合:柯里化函数易于组合。
  • 模块化:将复杂逻辑拆分为小函数。

3.3 手动实现柯里化

简单柯里化:

function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn(...args);
    }
    return (...nextArgs) => curried(...args, ...nextArgs);
  };
}

const add = (a, b, c) => 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.4 处理任意参数

支持动态参数:

function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn(...args);
    }
    return (...nextArgs) => curried(...args, ...nextArgs);
  };
}

const join = (...args) => args.join('');
const curriedJoin = curry(join);

console.log(curriedJoin('a')('b')('c')); // abc
console.log(curriedJoin('a', 'b')('c')); // abc

3.5 占位符支持

实现带占位符的柯里化(如 Lodash 的 _.curry):

const _ = Symbol('placeholder');

function curry(fn) {
  const arity = fn.length;
  return function curried(...args) {
    const actualArgs = args.filter(arg => arg !== _);
    if (actualArgs.length >= arity) {
      return fn(...args.slice(0, arity));
    }
    return (...nextArgs) => {
      const combined = [];
      let argIdx = 0;
      let nextIdx = 0;
      for (let i = 0; i < args.length; i++) {
        if (args[i] === _ && nextIdx < nextArgs.length) {
          combined.push(nextArgs[nextIdx++]);
        } else {
          combined.push(args[i]);
        }
      }
      while (nextIdx < nextArgs.length) {
        combined.push(nextArgs[nextIdx++]);
      }
      return curried(...combined);
    };
  };
}

const add = (a, b, c) => a + b + c;
const curriedAdd = curry(add);

console.log(curriedAdd(1, _, 3)(2)); // 6
console.log(curriedAdd(_, 2, _)(1, 3)); // 6

4. 柯里化在函数式编程中的应用

4.1 参数复用

柯里化通过固定参数生成专用函数:

const multiply = curry((a, b) => a * b);
const double = multiply(2);
const triple = multiply(3);

console.log(double(5)); // 10
console.log(triple(5)); // 15

4.2 事件处理

为 DOM 事件创建专用处理器:

const addEventListener = curry((event, handler, element) =>
  element.addEventListener(event, handler)
);

const onClick = addEventListener('click');
const logClick = () => console.log('Clicked');

const button = document.querySelector('#myButton');
onClick(logClick)(button);

4.3 数据转换

处理数据管道:

const map = curry((fn, arr) => arr.map(fn));
const filter = curry((fn, arr) => arr.filter(fn));
const addOne = x => x + 1;
const isEven = x => x % 2 === 0;

const processNumbers = pipe(
  map(addOne),
  filter(isEven)
);

console.log(processNumbers([1, 2, 3, 4])); // [2, 4]

4.4 配置化函数

为函数注入配置:

const fetchData = curry((baseUrl, endpoint, params) =>
  fetch(`${baseUrl}/${endpoint}?${new URLSearchParams(params)}`).then(res =>
    res.json()
  )
);

const api = fetchData('https://api.example.com');
const getUsers = api('users');

getUsers({ limit: 10 }).then(console.log);

5. 函数式编程与柯里化在前端框架中的应用

5.1 React 中的函数式编程

React 的函数组件和 Hooks 天然契合函数式编程。

纯组件:

function UserList({ users }) {
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

高阶组件(HOC):

const withLoading = Component => ({ isLoading, ...props }) =>
  isLoading ? <div>Loading...</div> : <Component {...props} />;

const UserListWithLoading = withLoading(UserList);

function App() {
  const [users, setUsers] = useState([]);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    fetch('/api/users')
      .then(res => res.json())
      .then(data => {
        setUsers(data);
        setIsLoading(false);
      });
  }, []);

  return <UserListWithLoading isLoading={isLoading} users={users} />;
}

柯里化在 React:

const useFetch = curry((url, options, setState) =>
  useEffect(() => {
    fetch(url, options)
      .then(res => res.json())
      .then(setState);
  }, [url, options])
);

function UserList() {
  const [users, setUsers] = useState([]);
  const fetchUsers = useFetch('/api/users', { method: 'GET' });

  fetchUsers(setUsers);

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

5.2 Vue 中的函数式编程

Vue 3 的组合式 API 支持函数式风格。

纯函数组件:

import { defineComponent } from 'vue';

export default defineComponent({
  props: ['users'],
  setup({ users }) {
    return () => (
      <ul>
        {users.map(user => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    );
  },
});

高阶组件:

const withLoading = Component => ({
  props: ['isLoading'],
  setup(props) {
    return () => (props.isLoading ? <div>Loading...</div> : <Component {...props} />);
  },
});

const UserListWithLoading = withLoading(UserList);

柯里化:

const useFetch = curry((url, options, setState) => {
  onMounted(() => {
    fetch(url, options)
      .then(res => res.json())
      .then(setState);
  });
});

export default defineComponent({
  setup() {
    const users = ref([]);
    const fetchUsers = useFetch('/api/users', { method: 'GET' });

    fetchUsers(users.value);

    return () => (
      <ul>
        {users.value.map(user => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    );
  },
});

6. 函数式编程工具库

6.1 Ramda

Ramda 是一个专注于函数式编程的库,内置柯里化支持。

安装:

npm install ramda

使用:

import * as R from 'ramda';

const addOne = R.map(R.add(1));
const filterEvens = R.filter(x => x % 2 === 0);
const processNumbers = R.pipe(addOne, filterEvens);

console.log(processNumbers([1, 2, 3, 4])); // [2, 4]

柯里化:

const add = R.curry((a, b) => a + b);
const addFive = add(5);

console.log(addFive(3)); // 8

6.2 Lodash/fp

Lodash 的函数式模块提供柯里化支持。

安装:

npm install lodash

使用:

import { flow, map, filter, curry } from 'lodash/fp';

const addOne = map(x => x + 1);
const filterEvens = filter(x => x % 2 === 0);
const processNumbers = flow([addOne, filterEvens]);

console.log(processNumbers([1, 2, 3, 4])); // [2, 4]

const add = curry((a, b) => a + b);
const addFive = add(5);

console.log(addFive(3)); // 8

7. 性能优化

7.1 记忆化

通过缓存结果优化纯函数性能:

function memoize(fn) {
  const cache = new Map();
  return (...args) => {
    const key = JSON.stringify(args);
    if (cache.has(key)) {
      return cache.get(key);
    }
    const result = fn(...args);
    cache.set(key, result);
    return result;
  };
}

const factorial = memoize(n => (n <= 1 ? 1 : n * factorial(n - 1)));

console.log(factorial(5)); // 120
console.log(factorial(5)); // 120(从缓存获取)

7.2 惰性求值

延迟计算以提升性能:

function lazyMap(fn, arr) {
  return {
    next: () => {
      const result = arr.map(fn);
      this.next = () => result;
      return result;
    },
  };
}

const numbers = [1, 2, 3, 4];
const lazyDouble = lazyMap(x => x * 2, numbers);

console.log(lazyDouble.next()); // [2, 4, 6, 8]
console.log(lazyDouble.next()); // [2, 4, 6, 8](缓存结果)

7.3 柯里化性能优化

缓存柯里化函数:

function curry(fn) {
  const cache = new Map();
  return function curried(...args) {
    const key = JSON.stringify(args);
    if (cache.has(key)) {
      return cache.get(key);
    }
    if (args.length >= fn.length) {
      const result = fn(...args);
      cache.set(key, result);
      return result;
    }
    const next = (...nextArgs) => curried(...args, ...nextArgs);
    cache.set(key, next);
    return next;
  };
}

const add = curry((a, b, c) => a + b + c);
const addFive = add(5);

console.log(addFive(2)(3)); // 10
console.log(addFive(2)(3)); // 10(缓存)

8. 函数式编程与 TypeScript

8.1 纯函数

const add = (a: number, b: number): number => a + b;
console.log(add(2, 3)); // 5

8.2 高阶函数

type Fn<T, R> = (arg: T) => R;

function withLogging<T, R>(fn: Fn<T, R>): Fn<T, R> {
  return (...args: T[]) => {
    console.log(`Calling ${fn.name} with`, args);
    const result = fn(...args);
    console.log(`Result:`, result);
    return result;
  };
}

const add = (a: number, b: number) => a + b;
const loggedAdd = withLogging(add);
loggedAdd(2, 3);

8.3 柯里化

function curry<T extends any[], R>(fn: (...args: T) => R) {
  return function curried(...args: any[]): any {
    if (args.length >= fn.length) {
      return fn(...args);
    }
    return (...nextArgs: any[]) => curried(...args, ...nextArgs);
  };
}

const add = (a: number, b: number, c: number) => a + b + c;
const curriedAdd = curry(add);

console.log(curriedAdd(1)(2)(3)); // 6

8.4 不可变性

interface User {
  readonly name: string;
  readonly age: number;
}

const user: User = { name: 'Alice', age: 30 };
const updatedUser: User = { ...user, age: 31 };

console.log(user); // { name: 'Alice', age: 30 }
console.log(updatedUser); // { name: 'Alice', age: 31 }

9. 函数式编程与异步编程

9.1 Promise 链

const fetchData = url =>
  fetch(url)
    .then(res => res.json())
    .then(data => data.results);

const processData = pipe(
  map(item => ({ ...item, processed: true })),
  filter(item => item.id > 0)
);

fetchData('/api/users')
  .then(processData)
  .then(console.log);

9.2 异步柯里化

const asyncCurry = fn => {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn(...args);
    }
    return (...nextArgs) => curried(...args, ...nextArgs);
  };
};

const fetchData = async (url, params) =>
  fetch(`${url}?${new URLSearchParams(params)}`).then(res => res.json());

const curriedFetch = asyncCurry(fetchData);
const getUsers = curriedFetch('/api/users');

getUsers({ limit: 10 }).then(console.log);

10. 函数式编程与状态管理

10.1 Redux

Redux 使用纯函数(Reducer)管理状态:

const initialState = { count: 0 };

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    case 'DECREMENT':
      return { ...state, count: state.count - 1 };
    default:
      return state;
  }
};

const increment = () => ({ type: 'INCREMENT' });
const decrement = () => ({ type: 'DECREMENT' });

柯里化 Action Creator:

const createAction = curry((type, payload) => ({ type, payload }));
const increment = createAction('INCREMENT');
const decrement = createAction('DECREMENT');

console.log(increment({ value: 1 })); // { type: 'INCREMENT', payload: { value: 1 } }

10.2 Zustand

Zustand 支持函数式状态管理:

import create from 'zustand';

const useStore = create(set => ({
  count: 0,
  increment: () => set(state => ({ count: state.count + 1 })),
  decrement: () => set(state => ({ count: state.count - 1 })),
}));

const increment = useStore(state => state.increment);
const decrement = useStore(state => state.decrement);

柯里化:

const createAction = curry((fn, set) => (...args) => set(state => fn(state, ...args)));

const increment = createAction((state, value) => ({
  count: state.count + value,
}));
const decrement = createAction((state, value) => ({
  count: state.count - value,
}));

const useStore = create(set => ({
  count: 0,
  increment: increment(set),
  decrement: decrement(set),
}));

11. 函数式编程与测试

11.1 测试纯函数

describe('add', () => {
  it('should add two numbers', () => {
    const add = (a, b) => a + b;
    expect(add(2, 3)).toBe(5);
  });
});

11.2 测试柯里化函数

describe('curriedAdd', () => {
  const add = curry((a, b, c) => a + b + c);
  it('should add three numbers', () => {
    expect(add(1)(2)(3)).toBe(6);
    expect(add(1, 2)(3)).toBe(6);
    expect(add(1)(2, 3)).toBe(6);
  });
});

11.3 Mock 高阶函数

jest.mock('./utils', () => ({
  withLogging: jest.fn(fn => (...args) => fn(...args)),
}));

describe('withLogging', () => {
  it('should wrap function', () => {
    const add = (a, b) => a + b;
    const loggedAdd = require('./utils').withLogging(add);
    expect(loggedAdd(2, 3)).toBe(5);
    expect(require('./utils').withLogging).toHaveBeenCalledWith(add);
  });
});

12. 函数式编程与模块化

12.1 CommonJS

// utils.js
module.exports = {
  curry: fn => {
    return function curried(...args) {
      if (args.length >= fn.length) {
        return fn(...args);
      }
      return (...nextArgs) => curried(...args, ...nextArgs);
    };
  },
};

// app.js
const { curry } = require('./utils');
const add = curry((a, b) => a + b);
console.log(add(2)(3)); // 5

12.2 ES Modules

// utils.mjs
export const curry = fn => {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn(...args);
    }
    return (...nextArgs) => curried(...args, ...nextArgs);
  };
};

// app.mjs
import { curry } from './utils.mjs';
const add = curry((a, b) => a + b);
console.log(add(2)(3)); // 5

13. 函数式编程与微前端

13.1 模块化状态管理

const createModuleStore = curry((moduleName, initialState, reducers) =>
  create(set => ({
    ...initialState,
    ...Object.keys(reducers).reduce(
      (acc, action) => ({
        ...acc,
        [action]: (...args) =>
          set(state => reducers[action](state, ...args)),
      }),
      {}
    ),
  }))
);

const userStore = createModuleStore('user', { users: [] }, {
  addUser: (state, user) => ({ users: [...state.users, user] }),
});

userStore.getState().addUser({ name: 'Alice' });
console.log(userStore.getState().users); // [{ name: 'Alice' }]

13.2 Qiankun 微前端

import { registerMicroApps, start } from 'qiankun';

const createMicroApp = curry((name, config) => ({
  name,
  ...config,
}));

const registerApp = curry((apps, app) => {
  apps.push(app);
  return apps;
});

const apps = [];
const registerReactApp = registerApp(apps);
const createReactApp = createMicroApp('reactApp');

registerReactApp(
  createReactApp({
    entry: '//localhost:3001',
    container: '#reactContainer',
    activeRule: '/react',
  })
);

registerMicroApps(apps);
start();

14. 函数式编程与错误处理

14.1 Either 容器

实现简化的 Either 容器处理错误:

class Either {
  constructor(value, isRight = true) {
    this.value = value;
    this.isRight = isRight;
  }

  static Right(value) {
    return new Either(value, true);
  }

  static Left(value) {
    return new Either(value, false);
  }

  map(fn) {
    return this.isRight ? Either.Right(fn(this.value)) : this;
  }

  getOrElse(defaultValue) {
    return this.isRight ? this.value : defaultValue;
  }
}

const safeDivide = curry((a, b) =>
  b === 0 ? Either.Left('Division by zero') : Either.Right(a / b)
);

console.log(safeDivide(10)(2).getOrElse(0)); // 5
console.log(safeDivide(10)(0).getOrElse(0)); // 0

14.2 Try-Catch

const tryCatch = curry((fn, ...args) => {
  try {
    return Either.Right(fn(...args));
  } catch (error) {
    return Either.Left(error.message);
  }
});

const parseJSON = tryCatch(JSON.parse);

console.log(parseJSON('{"name":"Alice"}').getOrElse({})); // { name: 'Alice' }
console.log(parseJSON('invalid').getOrElse({})); // {}

15. 函数式编程与性能分析

15.1 性能测试

const numbers = Array.from({ length: 1000 }, (_, i) => i);

const start = performance.now();
numbers.map(x => x * 2).filter(x => x % 2 === 0);
const end = performance.now();
console.log(`Map and filter took ${end - start}ms`);

15.2 优化循环

使用 reduce 减少多次遍历:

const processNumbers = numbers =>
  numbers.reduce((acc, x) => {
    const doubled = x * 2;
    if (doubled % 2 === 0) {
      acc.push(doubled);
    }
    return acc;
  }, []);

const start = performance.now();
processNumbers(numbers);
const end = performance.now();
console.log(`Reduce took ${end - start}ms`);

16. 函数式编程与 Node.js

16.1 文件操作

const fs = require('fs').promises;

const readFile = curry((encoding, path) => fs.readFile(path, encoding));
const writeFile = curry((path, data) => fs.writeFile(path, data));

const processFile = pipe(
  readFile('utf8'),
  map(line => line.toUpperCase()),
  writeFile('output.txt')
);

processFile('input.txt');

16.2 HTTP 服务器

const http = require('http');

const createRoute = curry((method, path, handler) => ({
  method,
  path,
  handler,
}));

const handleRequest = curry((routes, req, res) => {
  const route = routes.find(
    r => r.method === req.method && r.path === req.url
  );
  if (route) {
    route.handler(req, res);
  } else {
    res.writeHead(404);
    res.end('Not Found');
  }
});

const routes = [
  createRoute('GET', '/users', (req, res) => {
    res.writeHead(200);
    res.end(JSON.stringify([{ name: 'Alice' }]));
  }),
];

const server = http.createServer(handleRequest(routes));
server.listen(3000);

17. 函数式编程与事件处理

const createEventHandler = curry((event, handler, element) =>
  element.addEventListener(event, handler)
);

const onClick = createEventHandler('click');
const logClick = () => console.log('Clicked');

const button = document.querySelector('#myButton');
onClick(logClick)(button);

18. 函数式编程与数据模型

const createModel = curry((transform, data) => transform(data));

const userModel = createModel(data => ({
  id: data.id,
  name: data.name,
  getFullName: () => data.name,
}));

const user = userModel({ id: 1, name: 'Alice' });
console.log(user.getFullName()); // Alice

19. 函数式编程与插件系统

const createPlugin = curry((name, fn) => ({
  name,
  apply: fn,
}));

const loggerPlugin = createPlugin('logger', config => message =>
  console.log(`[${config.level}] ${message}`)
);

const logger = loggerPlugin({ level: 'INFO' });
logger('System started'); // [INFO] System started

20. 函数式编程与配置管理

const createConfig = curry((env, config) => ({
  ...config,
  env,
}));

const devConfig = createConfig('development', {
  apiUrl: 'http://localhost:3000',
  debug: true,
});

console.log(devConfig); // { env: 'development', apiUrl: 'http://localhost:3000', debug: true }
❌
❌