logo

JavaScript进阶:手写实现10个核心高阶函数

作者:狼烟四起2025.09.19 12:47浏览量:0

简介:本文深入解析JavaScript进阶开发中必须掌握的10个核心高阶函数的手写实现,涵盖函数式编程、异步控制、数据结构等关键领域,提供可复用的代码模板和性能优化方案。

一、函数式编程核心:柯里化与反柯里化

1.1 通用柯里化函数

柯里化是将多参数函数转换为连续单参数函数的技术。实现时需处理参数累积和自动执行条件:

  1. function curry(fn) {
  2. return function curried(...args) {
  3. if (args.length >= fn.length) {
  4. return fn.apply(this, args);
  5. } else {
  6. return function(...args2) {
  7. return curried.apply(this, args.concat(args2));
  8. }
  9. }
  10. }
  11. }
  12. // 使用示例
  13. const add = curry((a, b, c) => a + b + c);
  14. console.log(add(1)(2)(3)); // 6
  15. console.log(add(1, 2)(3)); // 6

关键点:通过fn.length判断参数是否收集完毕,利用闭包保存中间状态。性能优化可添加缓存机制,避免重复创建函数。

1.2 反柯里化实现

反柯里化将方法从特定对象解耦,增强通用性:

  1. function unCurry(fn) {
  2. return function(obj, ...args) {
  3. return fn.apply(obj, args);
  4. }
  5. }
  6. const push = unCurry(Array.prototype.push);
  7. let obj = { length: 0 };
  8. push(obj, 1, 2, 3);
  9. console.log(obj); // { '0': 1, '1': 2, '2': 3, length: 3 }

应用场景:当需要将对象方法作为通用函数使用时,如实现跨类型操作。

二、异步控制进阶:Promise与Generator

2.1 手写Promise实现

完整实现需包含状态管理、链式调用和异常处理:

  1. class MyPromise {
  2. constructor(executor) {
  3. this.state = 'pending';
  4. this.value = undefined;
  5. this.reason = undefined;
  6. this.onFulfilledCallbacks = [];
  7. this.onRejectedCallbacks = [];
  8. const resolve = (value) => {
  9. if (this.state === 'pending') {
  10. this.state = 'fulfilled';
  11. this.value = value;
  12. this.onFulfilledCallbacks.forEach(fn => fn());
  13. }
  14. };
  15. const reject = (reason) => {
  16. if (this.state === 'pending') {
  17. this.state = 'rejected';
  18. this.reason = reason;
  19. this.onRejectedCallbacks.forEach(fn => fn());
  20. }
  21. };
  22. try {
  23. executor(resolve, reject);
  24. } catch (err) {
  25. reject(err);
  26. }
  27. }
  28. then(onFulfilled, onRejected) {
  29. // 实现链式调用...
  30. }
  31. }

核心机制:状态机管理(pending→fulfilled/rejected)、微任务队列模拟(可用setTimeout替代)、值穿透处理。

2.2 Generator自动执行器

将Generator函数转换为类似async/await的语法:

  1. function co(gen) {
  2. return new Promise((resolve, reject) => {
  3. const iterator = gen();
  4. function step(nextFn) {
  5. try {
  6. const { value, done } = nextFn();
  7. if (done) return resolve(value);
  8. Promise.resolve(value).then(
  9. v => step(() => iterator.next(v)),
  10. e => step(() => iterator.throw(e))
  11. );
  12. } catch (err) {
  13. reject(err);
  14. }
  15. }
  16. step(() => iterator.next());
  17. });
  18. }
  19. // 使用示例
  20. co(function* () {
  21. const a = yield Promise.resolve(1);
  22. const b = yield Promise.resolve(a + 1);
  23. return b;
  24. }).then(console.log); // 2

实现要点:递归执行Generator、自动处理Promise、错误传播机制。

三、数据结构操作:深度克隆与扁平化

3.1 深度克隆实现

处理循环引用、特殊对象(Date、RegExp等)和Symbol属性:

  1. function deepClone(obj, hash = new WeakMap()) {
  2. if (obj === null || typeof obj !== 'object') return obj;
  3. if (hash.has(obj)) return hash.get(obj);
  4. let clone;
  5. if (obj instanceof Date) clone = new Date(obj);
  6. else if (obj instanceof RegExp) clone = new RegExp(obj);
  7. else {
  8. clone = Array.isArray(obj) ? [] : {};
  9. hash.set(obj, clone);
  10. Reflect.ownKeys(obj).forEach(key => {
  11. if (typeof key === 'symbol') {
  12. clone[key] = deepClone(obj[key], hash);
  13. } else {
  14. clone[key] = deepClone(obj[key], hash);
  15. }
  16. });
  17. }
  18. return clone;
  19. }

关键处理:使用WeakMap解决循环引用,Reflect.ownKeys获取所有属性(包括不可枚举和Symbol)。

3.2 数组扁平化实现

支持指定深度和自动判断深度:

  1. function flatten(arr, depth = Infinity) {
  2. let result = [];
  3. for (const item of arr) {
  4. if (Array.isArray(item) && depth > 0) {
  5. result.push(...flatten(item, depth - 1));
  6. } else {
  7. result.push(item);
  8. }
  9. }
  10. return result;
  11. }
  12. // 使用示例
  13. console.log(flatten([1, [2, [3, [4]]]], 2)); // [1, 2, 3, [4]]

性能优化:使用展开运算符替代concat,减少中间数组创建。

四、高阶工具函数:组合与管道

4.1 函数组合实现

从右到左执行函数:

  1. function compose(...fns) {
  2. return function(arg) {
  3. return fns.reduceRight((prev, fn) => fn(prev), arg);
  4. }
  5. }
  6. // 使用示例
  7. const add5 = x => x + 5;
  8. const multiply2 = x => x * 2;
  9. const result = compose(multiply2, add5)(10); // 30

4.2 管道函数实现

从左到右执行函数:

  1. function pipe(...fns) {
  2. return function(arg) {
  3. return fns.reduce((prev, fn) => fn(prev), arg);
  4. }
  5. }
  6. // 使用示例
  7. const result = pipe(add5, multiply2)(10); // 30

应用场景:构建数据处理流水线,提升代码可读性。

五、性能优化技巧

  1. 尾递归优化:对于支持ES6的环境,使用尾调用形式避免栈溢出
  2. 记忆化缓存:为计算密集型函数添加缓存
    1. function memoize(fn) {
    2. const cache = new Map();
    3. return function(...args) {
    4. const key = JSON.stringify(args);
    5. if (cache.has(key)) return cache.get(key);
    6. const result = fn.apply(this, args);
    7. cache.set(key, result);
    8. return result;
    9. }
    10. }
  3. 惰性求值:延迟计算直到真正需要

    1. function lazy(fn) {
    2. let executed = false;
    3. let result;
    4. return function() {
    5. if (!executed) {
    6. result = fn.apply(this, arguments);
    7. executed = true;
    8. }
    9. return result;
    10. }
    11. }

六、实际应用建议

  1. 测试驱动开发:为每个手写函数编写单元测试
    1. // 示例测试用例
    2. describe('deepClone', () => {
    3. it('should clone object with circular reference', () => {
    4. const obj = { a: 1 };
    5. obj.self = obj;
    6. const clone = deepClone(obj);
    7. expect(clone).not.toBe(obj);
    8. expect(clone.self).toBe(clone);
    9. });
    10. });
  2. 性能基准测试:使用console.time()对比原生方法
  3. 渐进式重构:先实现基础版本,再逐步优化

七、常见问题解决方案

  1. this绑定问题:在柯里化时保留原始this
    1. function bindThis(fn, context) {
    2. return function(...args) {
    3. return fn.apply(context, args);
    4. }
    5. }
  2. 参数顺序处理:实现部分应用时保持参数灵活性
    1. function partial(fn, ...presetArgs) {
    2. return function(...laterArgs) {
    3. const args = [...presetArgs, ...laterArgs];
    4. return fn.apply(this, args);
    5. }
    6. }
  3. 异步错误处理:完善Promise的catch链

通过系统掌握这些核心函数的手写实现,开发者能够深入理解JavaScript底层机制,提升代码质量和开发效率。建议从简单函数开始实践,逐步构建自己的工具库,最终达到灵活运用函数式编程解决复杂问题的水平。

相关文章推荐

发表评论