logo

JavaScript进阶:手写实现10个高频工具函数详解

作者:蛮不讲李2025.09.19 12:56浏览量:0

简介:本文深度解析JavaScript进阶阶段必须掌握的10个核心工具函数的手写实现,涵盖数组处理、函数式编程、异步控制等场景,通过原理剖析和代码示例帮助开发者突破原生API依赖,提升代码掌控力。

JavaScript进阶:手写实现10个高频工具函数详解

在JavaScript开发中,过度依赖第三方库会导致代码体积膨胀和性能损耗。本文将系统讲解10个进阶场景下必须掌握的核心工具函数的手写实现,涵盖数组处理、函数式编程、异步控制等关键领域,帮助开发者建立扎实的底层实现能力。

一、数组扁平化处理(flatten)

1.1 递归实现方案

  1. function flatten(arr) {
  2. let result = [];
  3. for (const item of arr) {
  4. if (Array.isArray(item)) {
  5. result = result.concat(flatten(item));
  6. } else {
  7. result.push(item);
  8. }
  9. }
  10. return result;
  11. }
  12. // 测试用例
  13. console.log(flatten([1, [2, [3, 4]], 5])); // [1, 2, 3, 4, 5]

1.2 迭代实现方案

  1. function flattenIterative(arr) {
  2. const stack = [...arr];
  3. const result = [];
  4. while (stack.length) {
  5. const next = stack.pop();
  6. if (Array.isArray(next)) {
  7. stack.push(...next);
  8. } else {
  9. result.push(next);
  10. }
  11. }
  12. return result.reverse();
  13. }

1.3 深度控制实现

  1. function flattenDeep(arr, depth = 1) {
  2. return depth > 0
  3. ? arr.reduce((prev, curr) =>
  4. prev.concat(Array.isArray(curr)
  5. ? flattenDeep(curr, depth - 1)
  6. : curr), [])
  7. : arr.slice();
  8. }

二、函数柯里化(Currying)

2.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 sum = (a, b, c) => a + b + c;
  14. const curriedSum = curry(sum);
  15. console.log(curriedSum(1)(2)(3)); // 6

2.2 带占位符的柯里化

  1. function curryWithPlaceholder(fn) {
  2. const placeholder = Symbol();
  3. const curried = (...args) => {
  4. const filledArgs = args.map(arg =>
  5. arg === placeholder ? undefined : arg
  6. );
  7. const missingArgs = fn.length - filledArgs.filter(Boolean).length;
  8. if (missingArgs <= 0) {
  9. return fn(...filledArgs);
  10. } else {
  11. return (...newArgs) => {
  12. const newArgsWithPlaceholders = newArgs.map(arg =>
  13. arg === placeholder ? placeholder : arg
  14. );
  15. const combinedArgs = args.map((arg, i) =>
  16. arg === placeholder ? newArgsWithPlaceholders.shift() || placeholder : arg
  17. );
  18. return curried(...combinedArgs);
  19. }
  20. }
  21. };
  22. curried.placeholder = placeholder;
  23. return curried;
  24. }

三、防抖与节流(Debounce & Throttle)

3.1 防抖函数实现

  1. function debounce(fn, delay, immediate = false) {
  2. let timer = null;
  3. return function(...args) {
  4. const context = this;
  5. if (timer) clearTimeout(timer);
  6. if (immediate && !timer) {
  7. fn.apply(context, args);
  8. }
  9. timer = setTimeout(() => {
  10. if (!immediate) {
  11. fn.apply(context, args);
  12. }
  13. timer = null;
  14. }, delay);
  15. }
  16. }
  17. // 使用场景
  18. window.addEventListener('resize', debounce(() => {
  19. console.log('Window resized');
  20. }, 300));

3.2 节流函数实现

  1. function throttle(fn, delay) {
  2. let lastTime = 0;
  3. return function(...args) {
  4. const now = Date.now();
  5. if (now - lastTime >= delay) {
  6. fn.apply(this, args);
  7. lastTime = now;
  8. }
  9. }
  10. }
  11. // 时间戳版改进
  12. function throttleAdvanced(fn, delay) {
  13. let lastTime = 0;
  14. let timer = null;
  15. return function(...args) {
  16. const now = Date.now();
  17. const remaining = delay - (now - lastTime);
  18. if (remaining <= 0) {
  19. if (timer) {
  20. clearTimeout(timer);
  21. timer = null;
  22. }
  23. lastTime = now;
  24. fn.apply(this, args);
  25. } else if (!timer) {
  26. timer = setTimeout(() => {
  27. lastTime = Date.now();
  28. timer = null;
  29. fn.apply(this, args);
  30. }, remaining);
  31. }
  32. }
  33. }

四、Promise并行控制(Promise.all变体)

4.1 限制并发数的Promise调度器

  1. class PromiseScheduler {
  2. constructor(maxConcurrent = 3) {
  3. this.maxConcurrent = maxConcurrent;
  4. this.running = 0;
  5. this.queue = [];
  6. }
  7. add(promiseCreator) {
  8. return new Promise((resolve, reject) => {
  9. this.queue.push({ promiseCreator, resolve, reject });
  10. this.run();
  11. });
  12. }
  13. run() {
  14. while (this.running < this.maxConcurrent && this.queue.length) {
  15. const { promiseCreator, resolve, reject } = this.queue.shift();
  16. this.running++;
  17. promiseCreator()
  18. .then(resolve)
  19. .catch(reject)
  20. .finally(() => {
  21. this.running--;
  22. this.run();
  23. });
  24. }
  25. }
  26. }
  27. // 使用示例
  28. const scheduler = new PromiseScheduler(2);
  29. const tasks = Array(5).fill(0).map((_, i) =>
  30. () => new Promise(res => setTimeout(() => {
  31. console.log(`Task ${i} completed`);
  32. res(i);
  33. }, Math.random() * 1000))
  34. );
  35. tasks.forEach(task => scheduler.add(task));

4.2 带超时控制的Promise.all

  1. function promiseAllWithTimeout(promises, timeout) {
  2. return new Promise((resolve, reject) => {
  3. const timeoutId = setTimeout(() => {
  4. reject(new Error('Promise.all timeout'));
  5. }, timeout);
  6. Promise.all(promises)
  7. .then(resolve)
  8. .catch(reject)
  9. .finally(() => {
  10. clearTimeout(timeoutId);
  11. });
  12. });
  13. }

五、深拷贝实现(Deep Clone)

5.1 完整深拷贝实现

  1. function deepClone(obj, hash = new WeakMap()) {
  2. // 处理基本类型和null/undefined
  3. if (obj === null || typeof obj !== 'object') {
  4. return obj;
  5. }
  6. // 处理循环引用
  7. if (hash.has(obj)) {
  8. return hash.get(obj);
  9. }
  10. // 处理Date和RegExp
  11. if (obj instanceof Date) return new Date(obj);
  12. if (obj instanceof RegExp) return new RegExp(obj);
  13. // 处理Map和Set
  14. if (obj instanceof Map) {
  15. const clone = new Map();
  16. hash.set(obj, clone);
  17. obj.forEach((value, key) => {
  18. clone.set(deepClone(key, hash), deepClone(value, hash));
  19. });
  20. return clone;
  21. }
  22. if (obj instanceof Set) {
  23. const clone = new Set();
  24. hash.set(obj, clone);
  25. obj.forEach(value => {
  26. clone.add(deepClone(value, hash));
  27. });
  28. return clone;
  29. }
  30. // 处理普通对象和数组
  31. const cloneObj = Array.isArray(obj) ? [] : {};
  32. hash.set(obj, cloneObj);
  33. for (const key in obj) {
  34. if (obj.hasOwnProperty(key)) {
  35. cloneObj[key] = deepClone(obj[key], hash);
  36. }
  37. }
  38. // 处理Symbol属性
  39. const symbolKeys = Object.getOwnPropertySymbols(obj);
  40. for (const symKey of symbolKeys) {
  41. cloneObj[symKey] = deepClone(obj[symKey], hash);
  42. }
  43. return cloneObj;
  44. }

六、函数组合(Function Composition)

6.1 从右到左的组合实现

  1. function compose(...fns) {
  2. return function(initialValue) {
  3. return fns.reduceRight((acc, fn) => fn(acc), initialValue);
  4. }
  5. }
  6. // 使用示例
  7. const add5 = x => x + 5;
  8. const multiplyBy2 = x => x * 2;
  9. const subtract3 = x => x - 3;
  10. const composedFn = compose(subtract3, multiplyBy2, add5);
  11. console.log(composedFn(10)); // (10+5)*2-3 = 27

6.2 从左到右的组合实现

  1. function pipe(...fns) {
  2. return function(initialValue) {
  3. return fns.reduce((acc, fn) => fn(acc), initialValue);
  4. }
  5. }
  6. // 与compose的对比
  7. const pipedFn = pipe(add5, multiplyBy2, subtract3);
  8. console.log(pipedFn(10)); // ((10+5)*2)-3 = 27

七、发布订阅模式(Pub/Sub)

7.1 基础实现

  1. class EventEmitter {
  2. constructor() {
  3. this.events = {};
  4. }
  5. on(event, callback) {
  6. if (!this.events[event]) {
  7. this.events[event] = [];
  8. }
  9. this.events[event].push(callback);
  10. }
  11. emit(event, ...args) {
  12. if (this.events[event]) {
  13. this.events[event].forEach(callback => {
  14. callback.apply(this, args);
  15. });
  16. }
  17. }
  18. off(event, callback) {
  19. if (!this.events[event]) return;
  20. if (!callback) {
  21. delete this.events[event];
  22. } else {
  23. this.events[event] = this.events[event].filter(
  24. cb => cb !== callback
  25. );
  26. }
  27. }
  28. once(event, callback) {
  29. const onceWrapper = (...args) => {
  30. callback.apply(this, args);
  31. this.off(event, onceWrapper);
  32. };
  33. this.on(event, onceWrapper);
  34. }
  35. }
  36. // 使用示例
  37. const emitter = new EventEmitter();
  38. const handler = data => console.log('Received:', data);
  39. emitter.on('message', handler);
  40. emitter.emit('message', 'Hello'); // Received: Hello
  41. emitter.off('message', handler);
  42. emitter.emit('message', 'World'); // 无输出

八、惰性函数(Lazy Evaluation)

8.1 惰性求值实现

  1. function createLazyFunction(fn) {
  2. let cache = null;
  3. return function(...args) {
  4. if (cache === null) {
  5. cache = fn.apply(this, args);
  6. }
  7. return cache;
  8. }
  9. }
  10. // 使用示例
  11. const expensiveCalculation = createLazyFunction(() => {
  12. console.log('Performing expensive calculation...');
  13. return Math.random();
  14. });
  15. console.log(expensiveCalculation()); // 输出日志并返回随机数
  16. console.log(expensiveCalculation()); // 直接返回缓存值

8.2 惰性链式调用

  1. class LazyChain {
  2. constructor(value) {
  3. this._calls = [];
  4. this._value = value;
  5. }
  6. through(fn) {
  7. this._calls.push(fn);
  8. return this;
  9. }
  10. value() {
  11. return this._calls.reduce((val, fn) => fn(val), this._value);
  12. }
  13. static of(value) {
  14. return new LazyChain(value);
  15. }
  16. }
  17. // 使用示例
  18. const result = LazyChain.of([1, 2, 3])
  19. .through(arr => arr.map(x => x * 2))
  20. .through(arr => arr.filter(x => x > 3))
  21. .value(); // [4, 6]

九、观察者模式(Observer Pattern)

9.1 可观察对象实现

  1. class Observable {
  2. constructor() {
  3. this.observers = [];
  4. }
  5. subscribe(observer) {
  6. this.observers.push(observer);
  7. return {
  8. unsubscribe: () => {
  9. this.observers = this.observers.filter(
  10. obs => obs !== observer
  11. );
  12. }
  13. };
  14. }
  15. notify(data) {
  16. this.observers.forEach(observer => {
  17. if (typeof observer.update === 'function') {
  18. observer.update(data);
  19. }
  20. });
  21. }
  22. }
  23. // 使用示例
  24. const observable = new Observable();
  25. const observer1 = {
  26. update: data => console.log('Observer1:', data)
  27. };
  28. const observer2 = {
  29. update: data => console.log('Observer2:', data)
  30. };
  31. const subscription1 = observable.subscribe(observer1);
  32. const subscription2 = observable.subscribe(observer2);
  33. observable.notify('Test message');
  34. subscription1.unsubscribe();
  35. observable.notify('Another message');

十、记忆化(Memoization)

10.1 基础记忆化实现

  1. function memoize(fn) {
  2. const cache = new Map();
  3. return function(...args) {
  4. const key = JSON.stringify(args);
  5. if (cache.has(key)) {
  6. return cache.get(key);
  7. }
  8. const result = fn.apply(this, args);
  9. cache.set(key, result);
  10. return result;
  11. }
  12. }
  13. // 使用示例
  14. const factorial = memoize(n => {
  15. if (n <= 1) return 1;
  16. return n * factorial(n - 1);
  17. });
  18. console.log(factorial(5)); // 计算并缓存
  19. console.log(factorial(5)); // 从缓存获取

10.2 带过期时间的记忆化

  1. function memoizeWithExpiry(fn, ttl) {
  2. const cache = new Map();
  3. return function(...args) {
  4. const key = JSON.stringify(args);
  5. const now = Date.now();
  6. // 检查缓存是否存在且未过期
  7. if (cache.has(key)) {
  8. const { value, expiry } = cache.get(key);
  9. if (now < expiry) {
  10. return value;
  11. }
  12. cache.delete(key);
  13. }
  14. const result = fn.apply(this, args);
  15. cache.set(key, {
  16. value: result,
  17. expiry: now + ttl
  18. });
  19. return result;
  20. }
  21. }
  22. // 使用示例
  23. const expensiveOperation = memoizeWithExpiry(
  24. () => {
  25. console.log('Performing expensive operation...');
  26. return Math.random();
  27. },
  28. 5000 // 5秒过期
  29. );

性能优化建议

  1. 缓存策略:对于记忆化函数,根据数据特性选择合适的缓存键生成方式,复杂对象建议使用JSON.stringify或自定义序列化方法

  2. 错误处理:在防抖/节流函数中添加错误边界处理,防止意外错误导致定时器无法清除

  3. 内存管理:对于事件发射器,定期清理不再使用的事件监听器,避免内存泄漏

  4. 类型检查:在深拷贝实现中增加更严格的类型检查,防止意外行为

  5. 并发控制:Promise调度器可根据实际需求调整队列策略(FIFO/LIFO)

总结

本文系统讲解了10个进阶JavaScript工具函数的手写实现,涵盖从基础数组操作到复杂异步控制的各种场景。这些实现不仅帮助开发者理解底层原理,更能在实际项目中减少对第三方库的依赖,提升代码性能和可维护性。建议开发者在实践中逐步掌握这些模式,并根据具体需求进行定制化改造。

相关文章推荐

发表评论