logo

JavaScript进阶必会:七大核心手写功能全解析

作者:渣渣辉2025.09.19 12:56浏览量:0

简介:本文深入解析JavaScript进阶阶段必须掌握的七大核心手写功能,涵盖从基础工具函数到高级设计模式的实现细节。通过代码示例和场景分析,帮助开发者突破框架依赖,提升代码质量与工程能力。

JavaScript进阶必会的手写功能:从工具到架构的深度实践

在JavaScript开发中,依赖第三方库虽能快速实现功能,但过度依赖会限制开发者对语言本质的理解。本文将系统梳理进阶阶段必须掌握的七大核心手写功能,涵盖工具函数、设计模式、异步处理等关键领域,帮助开发者构建扎实的底层能力。

一、核心工具函数实现

1. 深度克隆函数

  1. function deepClone(obj, hash = new WeakMap()) {
  2. if (obj === null || typeof obj !== 'object') return obj;
  3. // 处理循环引用
  4. if (hash.has(obj)) return hash.get(obj);
  5. const cloneObj = Array.isArray(obj) ? [] : {};
  6. hash.set(obj, cloneObj);
  7. for (let key in obj) {
  8. if (obj.hasOwnProperty(key)) {
  9. cloneObj[key] = deepClone(obj[key], hash);
  10. }
  11. }
  12. // 处理Symbol属性
  13. const symbolKeys = Object.getOwnPropertySymbols(obj);
  14. for (let key of symbolKeys) {
  15. cloneObj[key] = deepClone(obj[key], hash);
  16. }
  17. return cloneObj;
  18. }

该实现突破了JSON.parse(JSON.stringify())的三大局限:

  • 正确处理函数、Symbol、循环引用等特殊类型
  • 保持原型链完整性
  • 支持Date、RegExp等内置对象的克隆

2. 防抖与节流优化

  1. // 可配置的防抖函数
  2. function debounce(fn, delay = 300, immediate = false) {
  3. let timer = null;
  4. return function(...args) {
  5. const context = this;
  6. if (immediate && !timer) {
  7. fn.apply(context, args);
  8. immediate = false;
  9. }
  10. clearTimeout(timer);
  11. timer = setTimeout(() => {
  12. if (!immediate) fn.apply(context, args);
  13. }, delay);
  14. };
  15. }
  16. // 带取消功能的节流
  17. function throttle(fn, delay = 200) {
  18. let lastTime = 0;
  19. let timer = null;
  20. const throttled = function(...args) {
  21. const now = Date.now();
  22. const remaining = delay - (now - lastTime);
  23. if (remaining <= 0) {
  24. clearTimeout(timer);
  25. lastTime = now;
  26. fn.apply(this, args);
  27. } else if (!timer) {
  28. timer = setTimeout(() => {
  29. lastTime = Date.now();
  30. timer = null;
  31. fn.apply(this, args);
  32. }, remaining);
  33. }
  34. };
  35. throttled.cancel = function() {
  36. clearTimeout(timer);
  37. lastTime = 0;
  38. };
  39. return throttled;
  40. }

优化点:

  • 支持首次立即执行选项
  • 提供取消功能
  • 精确计算剩余时间

二、设计模式手写实现

1. 单例模式实现

  1. // 透明单例(需注意this指向)
  2. const Singleton = (function() {
  3. let instance;
  4. class Single {
  5. constructor() {
  6. if (instance) {
  7. return instance;
  8. }
  9. instance = this;
  10. this.init();
  11. }
  12. init() {
  13. console.log('初始化');
  14. }
  15. }
  16. return Single;
  17. })();
  18. // 更安全的实现方式
  19. function createSingleton(className) {
  20. let instance;
  21. return function(...args) {
  22. if (!instance) {
  23. instance = new className(...args);
  24. }
  25. return instance;
  26. };
  27. }

关键考量:

  • 延迟创建实例
  • 线程安全处理
  • 继承支持

2. 发布订阅模式

  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(cb => cb(...args));
  14. }
  15. }
  16. off(event, callback) {
  17. if (!callback) {
  18. delete this.events[event];
  19. } else {
  20. const callbacks = this.events[event];
  21. if (callbacks) {
  22. this.events[event] = callbacks.filter(cb => cb !== callback);
  23. }
  24. }
  25. }
  26. once(event, callback) {
  27. const onceWrapper = (...args) => {
  28. callback(...args);
  29. this.off(event, onceWrapper);
  30. };
  31. this.on(event, onceWrapper);
  32. }
  33. }

设计要点:

  • 支持一次性监听
  • 安全的移除机制
  • 事件参数透传

三、异步编程进阶

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. onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
  30. onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err; };
  31. const promise2 = new MyPromise((resolve, reject) => {
  32. if (this.state === 'fulfilled') {
  33. setTimeout(() => {
  34. try {
  35. const x = onFulfilled(this.value);
  36. resolvePromise(promise2, x, resolve, reject);
  37. } catch (e) {
  38. reject(e);
  39. }
  40. }, 0);
  41. } else if (this.state === 'rejected') {
  42. setTimeout(() => {
  43. try {
  44. const x = onRejected(this.reason);
  45. resolvePromise(promise2, x, resolve, reject);
  46. } catch (e) {
  47. reject(e);
  48. }
  49. }, 0);
  50. } else {
  51. this.onFulfilledCallbacks.push(() => {
  52. setTimeout(() => {
  53. try {
  54. const x = onFulfilled(this.value);
  55. resolvePromise(promise2, x, resolve, reject);
  56. } catch (e) {
  57. reject(e);
  58. }
  59. }, 0);
  60. });
  61. this.onRejectedCallbacks.push(() => {
  62. setTimeout(() => {
  63. try {
  64. const x = onRejected(this.reason);
  65. resolvePromise(promise2, x, resolve, reject);
  66. } catch (e) {
  67. reject(e);
  68. }
  69. }, 0);
  70. });
  71. }
  72. });
  73. return promise2;
  74. }
  75. }
  76. function resolvePromise(promise2, x, resolve, reject) {
  77. if (promise2 === x) {
  78. return reject(new TypeError('Chaining cycle detected'));
  79. }
  80. let called = false;
  81. if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
  82. try {
  83. const then = x.then;
  84. if (typeof then === 'function') {
  85. then.call(
  86. x,
  87. y => {
  88. if (called) return;
  89. called = true;
  90. resolvePromise(promise2, y, resolve, reject);
  91. },
  92. r => {
  93. if (called) return;
  94. called = true;
  95. reject(r);
  96. }
  97. );
  98. } else {
  99. resolve(x);
  100. }
  101. } catch (e) {
  102. if (called) return;
  103. called = true;
  104. reject(e);
  105. }
  106. } else {
  107. resolve(x);
  108. }
  109. }

关键实现点:

  • 三态管理(pending/fulfilled/rejected)
  • 异步执行保证
  • 链式调用支持
  • 循环引用检测

2. Async/Await原理模拟

  1. function asyncToGenerator(generatorFn) {
  2. return function(...args) {
  3. const generator = generatorFn.apply(this, args);
  4. function handle(result) {
  5. if (result.done) return Promise.resolve(result.value);
  6. return Promise.resolve(result.value).then(
  7. res => handle(generator.next(res)),
  8. err => handle(generator.throw(err))
  9. );
  10. }
  11. try {
  12. return handle(generator.next());
  13. } catch (err) {
  14. return Promise.reject(err);
  15. }
  16. };
  17. }
  18. // 使用示例
  19. const asyncFunc = asyncToGenerator(function* () {
  20. const a = yield 1;
  21. const b = yield a + 2;
  22. return b;
  23. });

核心机制:

  • Generator自动执行
  • 状态机管理
  • Promise链式调用

四、性能优化技巧

1. 惰性函数实现

  1. // 传统方式每次调用都判断
  2. function createXHR() {
  3. return window.XMLHttpRequest
  4. ? new XMLHttpRequest()
  5. : new ActiveXObject('Microsoft.XHR');
  6. }
  7. // 惰性函数优化
  8. function createXHR() {
  9. if (window.XMLHttpRequest) {
  10. createXHR = function() {
  11. return new XMLHttpRequest();
  12. };
  13. } else {
  14. createXHR = function() {
  15. return new ActiveXObject('Microsoft.XHR');
  16. };
  17. }
  18. return createXHR();
  19. }
  20. // 更简洁的ES6实现
  21. const createXHR = (function() {
  22. const xhr = window.XMLHttpRequest
  23. ? function() { return new XMLHttpRequest(); }
  24. : function() { return new ActiveXObject('Microsoft.XHR'); };
  25. return xhr();
  26. })();

优势分析:

  • 减少重复判断
  • 提升后续调用性能
  • 代码更简洁

2. 函数柯里化实现

  1. // 基础柯里化
  2. function curry(fn) {
  3. return function curried(...args) {
  4. if (args.length >= fn.length) {
  5. return fn.apply(this, args);
  6. } else {
  7. return function(...args2) {
  8. return curried.apply(this, args.concat(args2));
  9. };
  10. }
  11. };
  12. }
  13. // 带占位符的柯里化
  14. function curryWithPlaceholder(fn) {
  15. return function curried(...args) {
  16. const context = this;
  17. const placeholderIndex = args.indexOf('_');
  18. if (placeholderIndex === -1 && args.length >= fn.length) {
  19. return fn.apply(context, args);
  20. } else {
  21. return function(...args2) {
  22. const newArgs = [...args];
  23. let offset = 0;
  24. args2.forEach(arg => {
  25. const argIndex = newArgs.indexOf('_');
  26. if (argIndex !== -1) {
  27. newArgs[argIndex] = arg;
  28. offset++;
  29. } else {
  30. newArgs.push(arg);
  31. }
  32. });
  33. return curried.apply(context, newArgs);
  34. };
  35. }
  36. };
  37. }

应用场景:

  • 参数复用
  • 延迟执行
  • 函数组合

五、实践建议

  1. 渐进式学习:从工具函数开始,逐步掌握设计模式和底层原理
  2. 代码对比:实现后与原生方法或成熟库进行性能对比
  3. 单元测试:为每个手写功能编写完整的测试用例
  4. 场景分析:在实际项目中寻找应用场景,避免过度设计
  5. 性能监控:使用Performance API监控手写功能的实际性能

结语

手写核心功能不仅是技术能力的体现,更是深入理解JavaScript语言特性的有效途径。通过系统掌握这些进阶技能,开发者能够:

  • 减少对第三方库的依赖
  • 编写更高效、可控的代码
  • 在复杂场景中设计出更优雅的解决方案
  • 提升问题排查和调试能力

建议开发者在日常工作中刻意练习,从简单的工具函数开始,逐步挑战更复杂的设计模式和底层实现,最终形成自己的技术体系。

相关文章推荐

发表评论