每日前端手写题--day1:从基础到进阶的实战演练
2025.09.19 12:47浏览量:1简介:本文围绕"每日前端手写题--day1"主题,通过手写实现经典前端功能(如防抖节流、数组扁平化、深拷贝),结合理论解析与代码实践,帮助开发者提升编码能力与问题解决思维。
每日前端手写题—day1:从基础到进阶的实战演练
一、为什么需要”每日前端手写题”?
在前端开发领域,框架与工具的迭代速度极快,React、Vue、Angular等主流框架不断更新,TypeScript、Webpack等配套工具链持续演进。然而,无论技术栈如何变化,底层编码能力始终是区分开发者水平的核心指标。手写代码不仅能加深对语言特性的理解,更能培养解决复杂问题的思维模式。
以”每日前端手写题”为形式的练习,具有以下价值:
- 强化基础:通过重复实现常见功能(如防抖、节流、数组操作),巩固JavaScript/TypeScript核心语法。
- 提升调试能力:手写过程中暴露的边界问题(如循环引用、类型转换),能倒逼开发者完善测试用例。
- 优化代码风格:在无框架约束下,更关注变量命名、函数拆分、注释规范等细节。
- 模拟面试场景:许多前端面试题直接考察手写能力(如实现Promise、虚拟DOM),日常练习可降低临场压力。
二、Day1核心题目解析
题目1:实现防抖函数(debounce)
需求:输入框实时搜索时,避免每次输入都触发请求,需在用户停止输入后延迟300ms再发送请求。
基础实现
function debounce(fn, delay) {let timer = null;return function(...args) {if (timer) clearTimeout(timer);timer = setTimeout(() => {fn.apply(this, args);}, delay);};}
关键点:
- 使用
clearTimeout清除未执行的定时器。 - 通过
apply绑定上下文,确保this指向正确。 - 参数传递使用剩余参数语法
...args,兼容任意数量参数。
进阶优化
- 立即执行版:首次触发时立即执行,后续触发仍防抖。
function debounce(fn, delay, immediate = false) {let timer = null;return function(...args) {if (timer) clearTimeout(timer);if (immediate && !timer) {fn.apply(this, args);}timer = setTimeout(() => {if (!immediate) fn.apply(this, args);timer = null;}, delay);};}
- 取消功能:添加
cancel方法手动终止防抖。function debounce(fn, delay) {let timer = null;const debounced = function(...args) {if (timer) clearTimeout(timer);timer = setTimeout(() => fn.apply(this, args), delay);};debounced.cancel = () => clearTimeout(timer);return debounced;}
题目2:数组扁平化(flatten)
需求:将嵌套数组[1, [2, [3, 4]], 5]转换为[1, 2, 3, 4, 5]。
方法1:递归实现
function flatten(arr) {let result = [];for (const item of arr) {if (Array.isArray(item)) {result = result.concat(flatten(item));} else {result.push(item);}}return result;}
优点:逻辑清晰,兼容任意深度嵌套。
缺点:递归可能导致栈溢出(极端情况下)。
方法2:reduce+展开运算符
function flatten(arr) {return arr.reduce((acc, val) =>acc.concat(Array.isArray(val) ? flatten(val) : val),[]);}// 或使用ES6展开运算符function flatten(arr) {while (arr.some(item => Array.isArray(item))) {arr = [].concat(...arr);}return arr;}
性能对比:展开运算符版本在浅层嵌套时更快,递归版本在深层嵌套时更稳定。
题目3:深拷贝对象
需求:完整复制一个对象,包括嵌套对象、数组、日期等特殊类型。
基础实现
function deepClone(obj, hash = new WeakMap()) {if (obj === null || typeof obj !== 'object') return obj;if (hash.has(obj)) return hash.get(obj); // 处理循环引用let clone;if (obj instanceof Date) {clone = new Date(obj);} else if (obj instanceof RegExp) {clone = new RegExp(obj);} else if (Array.isArray(obj)) {clone = [];} else {clone = Object.create(Object.getPrototypeOf(obj));}hash.set(obj, clone);for (const key in obj) {if (obj.hasOwnProperty(key)) {clone[key] = deepClone(obj[key], hash);}}return clone;}
关键处理:
- 使用
WeakMap避免循环引用导致的无限递归。 - 区分
Date、RegExp、Array等特殊对象类型。 - 通过
Object.create保持原型链。
简化版(仅处理普通对象)
function deepClone(obj) {return JSON.parse(JSON.stringify(obj));}
局限性:
- 无法处理函数、Symbol、循环引用。
- 会丢失
undefined和对象原型。
三、实践建议
- 每日一题:固定时间(如晨间15分钟)完成一道手写题,记录耗时与错误点。
- 对比优化:实现基础版本后,参考开源库(如Lodash)的源码,学习性能优化技巧。
- 场景扩展:为每个函数添加TypeScript类型定义,或编写单元测试(如Jest)。
- 建立题库:按类型分类(算法、工具函数、设计模式),形成个人知识体系。
四、总结
“每日前端手写题—day1”不仅是编码练习,更是思维训练。通过防抖、数组扁平化、深拷贝等经典题目的实现,开发者能深入理解闭包、递归、原型链等核心概念。坚持每日练习,将基础能力转化为解决复杂问题的自信,最终在技术面试与实际项目中脱颖而出。

发表评论
登录后可评论,请前往 登录 或 注册