【每日五题系列】前端面试高频题目

devtools/2025/3/15 0:33:57/

比如防抖、节流、深度优先遍历和广度优先遍历的实现,还有Promise、async/await这些。

提到了数组扁平化、Localstorage缓存系统设计、ES6模板语法。数组扁平化是一个常见的手写题,应该加入。缓存系统设计可能比较复杂,但作为设计题也是常考的,可以考虑。

编程题有红绿灯Promise实现、bind/call/apply、字符串压缩、new操作符、深拷贝等。这些都是经典题目。比如实现bind或者new,深拷贝这些,都是常见的手写题,应该包含进去。

比如事件循环、模块化发展历程等,但手写代码可能较少。

提供了数组去重、快速排序的实现,这两个都是基础算法题,适合手写。特别是快速排序的不同实现方式,可以作为一个点。

闭包应用、Promise实现、事件循环解释等。其中手写Promise是一个高级题目,可以选。

二叉树遍历、对称二叉树、最大深度、有序数组转BST等。这些算法题在前端面试中也常见,可以考虑加入,比如二叉树的遍历或者对称二叉树的判断。

调整后的列表可能包括:

  1. 数组扁平化
  2. 深拷贝
  3. 实现bind
  4. 手写Promise
  5. 快速排序
  6. 红绿灯交替(Promise)
  7. 二叉树遍历
  8. 字符串压缩
  9. 实现new
  10. 观察者模式或发布订阅模式实现

以下是2025年前端面试高频手撕代码题目及实现示例(含10个新题型,综合多个技术领域):

一、数组扁平化(多层级嵌套转一维数组)

javascript">// 递归实现(网页2、网页5)
function flatten(arr) {return arr.reduce((acc, cur) => acc.concat(Array.isArray(cur) ? flatten(cur) : cur), []);
}
// ES6实现
const flattenES6 = arr => arr.flat(Infinity); 

二、深拷贝实现(含循环引用处理)

javascript">// 支持对象/数组/日期/正则等类型(网页3、网页8)
function deepClone(target, map = new WeakMap()) {if (target instanceof Date) return new Date(target);if (target instanceof RegExp) return new RegExp(target);if (typeof target !== 'object' || target === null) return target;if (map.has(target)) return map.get(target);const cloneObj = new target.constructor();map.set(target, cloneObj);for (let key in target) {if (target.hasOwnProperty(key)) {cloneObj[key] = deepClone(target[key], map);}}return cloneObj;
}

三、实现bind方法

javascript">// 兼容new操作符(网页3)
Function.prototype.myBind = function(context, ...args) {const fn = this;return function Fn(...newArgs) {return fn.apply(this instanceof Fn ? this : context,args.concat(newArgs));};
};

四、手写Promise核心实现

javascript">// 含then链式调用(网页7)
class MyPromise {constructor(executor) {this.state = 'pending';this.value = undefined;this.onFulfilledCallbacks = [];const resolve = value => {if (this.state === 'pending') {this.state = 'fulfilled';this.value = value;this.onFulfilledCallbacks.forEach(fn => fn());}};executor(resolve);}then(onFulfilled) {return new MyPromise(resolve => {const wrapped = () => {const result = onFulfilled(this.value);resolve(result instanceof MyPromise ? result : new MyPromise(r => r(result)));};this.state === 'fulfilled' ? wrapped() : this.onFulfilledCallbacks.push(wrapped);});}
}

五、快速排序实现

javascript">// 原地排序版(网页5)
function quickSort(arr, left = 0, right = arr.length - 1) {if (left < right) {const pivot = partition(arr, left, right);quickSort(arr, left, pivot - 1);quickSort(arr, pivot + 1, right);}return arr;function partition(arr, low, high) {const pivot = arr[high];let i = low;for (let j = low; j < high; j++) {if (arr[j] < pivot) {[arr[i], arr[j]] = [arr[j], arr[i]];i++;}}[arr[i], arr[high]] = [arr[high], arr[i]];return i;}
}

六、Promise实现红绿灯控制

javascript">// 红绿黄交替(网页3)
function lightControl() {function light(color, duration) {return new Promise(resolve => {console.log(color);setTimeout(resolve, duration);});}async function run() {while(true) {await light('红', 3000);await light('绿', 2000);await light('黄', 1000);}}run();
}

七、二叉树前序遍历(非递归)

javascript">// 使用栈实现(网页9)
function preorderTraversal(root) {const stack = [], res = [];while(root || stack.length) {while(root) {res.push(root.val);stack.push(root);root = root.left;}root = stack.pop().right;}return res;
}

八、字符串压缩算法

javascript">// "aabcccccaaa" → "a2b1c5a3"(网页3)
function compressString(str) {let count = 1, res = '';for (let i = 0; i < str.length; i++) {if (str[i] === str[i+1]) {count++;} else {res += str[i] + count;count = 1;}}return res.length < str.length ? res : str;
}

九、实现new操作符

javascript">// 完整实现(网页3、网页4)
function myNew(constructor, ...args) {const obj = Object.create(constructor.prototype);const result = constructor.apply(obj, args);return result instanceof Object ? result : obj;
}

十、发布订阅模式实现

javascript">// 支持once/异步触发(网页3)
class EventEmitter {constructor() {this.events = new Map();}on(type, handler) {const handlers = this.events.get(type) || [];handlers.push(handler);this.events.set(type, handlers);}emit(type, ...args) {const handlers = this.events.get(type) || [];handlers.forEach(handler => handler(...args));}off(type, handler) {const handlers = this.events.get(type) || [];this.events.set(type, handlers.filter(h => h !== handler));}once(type, handler) {const wrapper = (...args) => {handler(...args);this.off(type, wrapper);};this.on(type, wrapper);}
}

以上题目覆盖了算法、设计模式、原生API实现、异步编程等核心领域,建议结合具体业务场景理解实现原理。如需完整测试用例或更多扩展实现(如虚拟DOM Diff算法、大文件分片上传等),可参考相关技术文档。


华为OD的题目列表,包括滑动窗口、贪心算法等,可能适合提取一些新题。涉及大数相加、数组乱序、并发控制等.网页9和10提到Promise源码、LRU缓存,这些也是常见题目。

大数相加、大数相乘、数组乱序、对象扁平化;有并发控制、Promise调度器、链式调用有LRU缓存

以下是2025年前端面试高频手撕代码题目及实现示例(基于最新技术趋势和面试题库整理):


一、LRU缓存实现(高频算法)

要求:实现一个支持get/put操作的LRU缓存,时间复杂度O(1)

javascript">class LRUCache {constructor(capacity) {this.cache = new Map();this.capacity = capacity;}get(key) {if (!this.cache.has(key)) return -1;const value = this.cache.get(key);this.cache.delete(key); // 删除后重新插入保证顺序this.cache.set(key, value);return value;}put(key, value) {if (this.cache.has(key)) this.cache.delete(key);this.cache.set(key, value);if (this.cache.size > this.capacity) {// 删除最久未使用的键(Map的迭代顺序保证)this.cache.delete(this.cache.keys().next().value);}}
}

二、大数相加(精度处理)

场景:解决JS精度丢失问题,如"9999999999999999" + “1”

javascript">function addStrings(num1, num2) {let i = num1.length - 1, j = num2.length - 1, carry = 0;let result = '';while (i >= 0 || j >= 0 || carry) {const n1 = i >= 0 ? num1[i--] - '0' : 0;const n2 = j >= 0 ? num2[j--] - '0' : 0;const sum = n1 + n2 + carry;result = (sum % 10) + result;carry = Math.floor(sum / 10);}return result.replace(/^0+/, '') || '0';
}

三、并发请求控制

要求:实现最多同时执行N个请求的调度器

javascript">class Scheduler {constructor(limit) {this.queue = [];this.running = 0;this.limit = limit;}addTask(task) {return new Promise(resolve => {const execute = () => {this.running++;task().then(resolve).finally(() => {this.running--;this.runNext();});};this.queue.push(execute);this.runNext();});}runNext() {if (this.running < this.limit && this.queue.length) {const task = this.queue.shift();task();}}
}

四、对象扁平化

场景:将嵌套对象转为单层结构

javascript">function flattenObject(obj, prefix = '') {return Object.keys(obj).reduce((acc, key) => {const pre = prefix ? `${prefix}.` : '';if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {Object.assign(acc, flattenObject(obj[key], pre + key));} else {acc[pre + key] = obj[key];}return acc;}, {});
}
// 示例输入:{a: {b: {c: 1}, d: 2}} → {'a.b.c': 1, 'a.d': 2}

五、Lazy链式调用

场景:实现LazyMan('Tony').sleep(10).eat('lunch')的链式调用

javascript">class LazyMan {constructor(name) {this.tasks = [];console.log(`Hi I'm ${name}`);setTimeout(() => this.run(), 0);}next() {this.tasks.length && this.tasks.shift()();}run() {this.next();}sleep(sec) {this.tasks.push(() => {setTimeout(() => {console.log(`等待了${sec}`);this.next();}, sec * 1000);});return this;}eat(food) {this.tasks.push(() => {console.log(`吃了${food}`);this.next();});return this;}
}

六、手写Promise核心

重点:实现基本状态管理和then链式调用

javascript">class MyPromise {constructor(executor) {this.state = 'pending';this.value = undefined;this.callbacks = [];const resolve = value => {if (this.state !== 'pending') return;this.state = 'fulfilled';this.value = value;this.callbacks.forEach(cb => this.handle(cb));};try {executor(resolve);} catch (e) {reject(e);}}then(onFulfilled) {return new MyPromise(resolve => {this.handle({onFulfilled: onFulfilled || (value => value),resolve});});}handle(callback) {if (this.state === 'pending') {this.callbacks.push(callback);return;}setTimeout(() => {try {const result = callback.onFulfilled(this.value);callback.resolve(result);} catch (e) {callback.reject(e);}}, 0);}
}

七、节流与防抖

高频优化场景:滚动事件/输入框优化

javascript">// 节流(时间窗口内只执行一次)
function throttle(fn, delay) {let last = 0;return function(...args) {const now = Date.now();if (now - last >= delay) {fn.apply(this, args);last = now;}};
}// 防抖(最后一次操作后执行)
function debounce(fn, delay) {let timer = null;return function(...args) {clearTimeout(timer);timer = setTimeout(() => {fn.apply(this, args);}, delay);};
}

八、数组乱序(Fisher-Yates算法)

重点:实现真正的随机排序

javascript">function shuffle(arr) {for (let i = arr.length - 1; i > 0; i--) {const j = Math.floor(Math.random() * (i + 1));[arr[i], arr[j]] = [arr[j], arr[i]];}return arr;
}

九、浅拷贝实现

基础考点:区分深浅拷贝差异

javascript">function shallowClone(obj) {if (typeof obj !== 'object' || obj === null) return obj;return Array.isArray(obj) ? [...obj] : { ...obj };
}

十、观察者模式

设计模式考点:实现事件订阅机制

javascript">class Observer {constructor() {this.events = new Map();}on(event, fn) {const handlers = this.events.get(event) || [];handlers.push(fn);this.events.set(event, handlers);}emit(event, ...args) {const handlers = this.events.get(event) || [];handlers.forEach(fn => fn(...args));}off(event, fn) {const handlers = this.events.get(event) || [];this.events.set(event, handlers.filter(h => h !== fn));}
}

建议结合具体业务场景理解实现原理,这些题目覆盖了算法、设计模式、框架原理等核心领域。如需完整测试用例或更多扩展实现,可参考相关技术文档。


以下是对虚拟DOM Diff算法、大文件分片上传、Web Worker通信机制和Canvas图形绘制的详解及代码示例:


一、虚拟DOM Diff算法实现

核心原理(结合网页)

Diff算法通过双端比较策略key标识优化实现高效节点对比:

  1. 层级比较:仅对比同层级节点,避免跨层级遍历(复杂度从O(n³)降为O(n))
  2. 双指针策略:通过新旧子节点列表的头部和尾部指针,快速定位可复用节点
  3. Key优化:通过唯一key值建立节点映射表,避免顺序错乱导致冗余操作
节点对比实现代码
javascript">function diff(oldVNode, newVNode) {// 1. 类型不同直接替换if (oldVNode.tag !== newVNode.tag) {replaceNode(oldVNode, newVNode);return;}// 2. 比较属性(网页1)const propsPatches = diffProps(oldVNode.props, newVNode.props);if (propsPatches.length) updateProps(oldVNode, propsPatches);// 3. 比较子节点(网页3)if (oldVNode.children && newVNode.children) {diffChildren(oldVNode.children, newVNode.children);}
}function diffChildren(oldChildren, newChildren) {let oldStartIdx = 0, newStartIdx = 0;let oldEndIdx = oldChildren.length - 1;let newEndIdx = newChildren.length - 1;while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {// 双端比较逻辑(网页4)if (sameVNode(oldChildren[oldStartIdx], newChildren[newStartIdx])) {patch(oldChildren[oldStartIdx], newChildren[newStartIdx]);oldStartIdx++;newStartIdx++;} else if (sameVNode(oldChildren[oldEndIdx], newChildren[newEndIdx])) {// ...尾部对比逻辑}}
}

二、大文件分片上传实现(断点续传)

核心流程(网页)
  1. 文件切片:将文件按固定大小(如5MB)分割
  2. 哈希生成:使用SparkMD5等库生成文件唯一标识
  3. 分片上传:并发控制上传切片(通常限制5个并发)
  4. 断点续传:通过本地存储记录已上传切片
  5. 服务端合并:所有切片上传完成后触发合并请求
前端实现代码
javascript">// 文件切片(网页5)
function sliceFile(file, chunkSize = 5 * 1024 * 1024) {const chunks = [];let start = 0;while (start < file.size) {chunks.push(file.slice(start, start + chunkSize));start += chunkSize;}return chunks;
}// 分片上传(网页6)
async function uploadChunks(fileHash, chunks) {const maxConcurrent = 5; // 最大并发数const uploaded = await checkUploadedChunks(fileHash);for (let i = 0; i < chunks.length; i += maxConcurrent) {await Promise.all(chunks.slice(i, i + maxConcurrent).map(async (chunk, index) => {if (!uploaded.includes(i + index)) {const formData = new FormData();formData.append('chunk', chunk);formData.append('hash', `${fileHash}-${i + index}`);await fetch('/upload', { method: 'POST', body: formData });}}));}await mergeChunks(fileHash, file.name);
}

三、Web Worker通信机制

主线程与Worker交互(网页)
  1. 线程创建
javascript">// 主线程
const worker = new Worker('worker.js');
worker.postMessage({ type: 'CALC', data: [1,2,3] });// Worker线程(worker.js)
self.onmessage = (e) => {if (e.data.type === 'CALC') {const result = e.data.data.reduce((a, b) => a + b, 0);self.postMessage({ type: 'RESULT', result });}
};
  1. 数据传输限制
    • 采用结构化克隆算法(支持除DOM、Function外的多数类型)
    • 大数据量建议使用Transferable Objects减少拷贝开销:
javascript">// 主线程发送二进制数据
const buffer = new ArrayBuffer(1024);
worker.postMessage(buffer, [buffer]); // 转移所有权
  1. 错误处理
javascript">worker.onerror = (err) => {console.error('Worker错误:', err.message);
};

四、Canvas画板功能实现

核心功能实现(网页)
<canvas id="drawboard" width="800" height="600"></canvas>
<button onclick="javascript language-javascript">clearCanvas()">清空</button><script>javascript">
const canvas = document.getElementById('drawboard');
const ctx = canvas.getContext('2d');
let isDrawing = false;
let lastX = 0;
let lastY = 0;// 画笔设置
ctx.strokeStyle = '#000';
ctx.lineWidth = 5;
ctx.lineCap = 'round';// 事件监听
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', endDrawing);function startDrawing(e) {isDrawing = true;[lastX, lastY] = [e.offsetX, e.offsetY];
}function draw(e) {if (!isDrawing) return;ctx.beginPath();ctx.moveTo(lastX, lastY);ctx.lineTo(e.offsetX, e.offsetY);ctx.stroke();[lastX, lastY] = [e.offsetX, e.offsetY];
}function endDrawing() {isDrawing = false;
}function clearCanvas() {ctx.clearRect(0, 0, canvas.width, canvas.height);
}
</script>
高级功能扩展
  1. 笔刷类型:通过修改ctx.globalCompositeOperation实现橡皮擦
  2. 历史记录:使用ctx.getImageData保存画布状态
  3. 移动端适配:添加触摸事件监听(touchstart/touchmove

以上实现方案综合了虚拟DOM的高效更新策略、大文件处理的可靠性方案、多线程通信机制以及Canvas的底层绘图能力,建议根据具体业务场景调整参数和功能扩展。


http://www.ppmy.cn/devtools/166859.html

相关文章

生成对抗网络(GAN)原理与应用

目录 一、引言 二、GAN的基本原理 &#xff08;一&#xff09;生成器&#xff08;Generator&#xff09;的工作机制 &#xff08;二&#xff09;判别器&#xff08;Discriminator&#xff09;的工作机制 &#xff08;三&#xff09;对抗训练的过程 三、GAN在AIGC生图中的应…

GC安全点导致停顿时间过长的案例

GC安全点导致停顿时间过长的案例 前言安全点的概念案例分析解决方法如有需要收藏的看官&#xff0c;顺便也用发财的小手点点赞哈&#xff0c;如有错漏&#xff0c;也欢迎各位在评论区评论&#xff01; 前言 前段时间在使用G1垃圾收集时&#xff0c;因服务读写压力过大&#xf…

Word 小黑第2套

对应大猫42 Word1 从文件中导入新样式 样式组 -管理样式 -导入导出 -关闭Normal文件 -打开文件 -修改文件 -选中所需 -复制 调整字符宽度 调整字符间距 -字体组 加宽 适当修改磅值 文字效果通过文字组修改 另起一页&#xff0c;分隔符&#xff08;布局 -分隔符 -分节符 -下一…

《PaddleOCR》—— OCR

文章目录 PaddleOCR简介核心功能与特点快速安装与使用典型应用场景实例 PaddleOCR简介 PaddleOCR 是百度基于飞桨&#xff08;PaddlePaddle&#xff09;框架开源的全场景文字识别工具&#xff0c;支持多语言、多场景、高精度的 OCR 能力&#xff0c;覆盖文本检测、识别、方向分…

python之爬虫入门实例

链家二手房数据抓取与Excel存储 目录 开发环境准备爬虫流程分析核心代码实现关键命令详解进阶优化方案注意事项与扩展 一、开发环境准备 1.1 必要组件安装 # 安装核心库 pip install requests beautifulsoup4 openpyxl pandas# 各库作用说明&#xff1a; - requests&#x…

【计算机网络】UDP

1.基本概念 UDP全名叫做用户数据报协议&#xff0c;它是存在于传输层的一个协议 2.核心特点 无连接 它不用像TCP那样每次发送数据之前都需要建立连接&#xff0c; 不可靠传输 这也叫尽最大努力交付&#xff0c;也就是UDP无法保证数据的完整和有序传输&#xff0c;只能尽自…

重生之我在学Vue--第6天 Vue 3 状态管理(Pinia)

重生之我在学Vue–第6天 Vue 3 状态管理&#xff08;Pinia&#xff09; 文章目录 重生之我在学Vue--第6天 Vue 3 状态管理&#xff08;Pinia&#xff09;前言一、Pinia 核心概念速览1.1 为什么需要状态管理&#xff1f;1.2 Pinia 核心三要素 二、Pinia 快速上手2.1 安装与初始化…

[动手学习深度学习]13.丢弃法 Dropout

权重衰退是常见处理过拟合的方法 丢弃法比权重衰退效果要好 动机 一个好的模型 需要第输入数据的扰动具有鲁棒性 使用有噪音的数据等价于Tikhonov正则丢弃法&#xff1a;在层之间加入噪音 &#xff08;所以丢弃法其实是一个正则&#xff09; 无偏差的加入噪音 对x加入噪音…