ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

2026前端面试3天突击计划:核心考点与高频手写题全解

2026前端面试3天突击计划:核心考点与高频手写题全解 每年 8 月前后都是前端候选人集中准备秋招和跳槽面试的高峰期。这个阶段最容易出现的状态是刷题刷不完、知识点越背越乱、项目经历不知道从哪讲起最后陷入“这也不会那也不会”的焦虑。我自己也经历过类似阶段所以很能理解这种压力。本文将围绕 2026 前端面试季的高频考点把“前端八股文面试题”按照复习优先级拆成 3 天的节奏覆盖 JavaScript 核心、浏览器与网络、Vue/React 框架、工程化与性能优化、安全、TypeScript 以及高频手写题。适合正在准备前端岗位面试的读者也适合想系统梳理基础知识的初中级开发者。不过要先说明一点3 天突击更适合已经有基础、需要快速拉起知识体系的候选人。如果你刚学完 HTML/CSS/JavaScript建议把节奏放慢到 2 到 4 周否则容易因为堆积过多产生挫败感。下面进入正题。1. 前端八股文是什么为什么面试还要背1.1 八股文的真实作用“前端八股文”并不是贬义词它指的是面试中反复出现的基础原理题、概念题和手写题比如事件循环、闭包、原型链、HTTP 缓存、Vue 响应式原理、React Hooks 依赖等。在面试流程里八股文承担的是“初筛”功能。面试官通过这些问题快速判断候选人基础是否扎实能不能用清晰的语言把原理讲明白。即使你的项目经验很丰富如果连this指向、v-if和v-show的区别都说不清面试很难通过。所以我认为八股文不是目的而是一条快速串起知识体系的线索。你要做的不是逐字背诵而是把每个高频问题理解透然后用“结论 原理 例子”的方式讲出来。1.2 怎么背才有价值很多人刷前端面试题时习惯把答案复制到笔记里然后从头看到尾。这个方法效率很低因为大脑只是“见过”并没有真正掌握。更有效的做法是“费曼学习法”每看完一个知识点合上笔记用自己的话解释一遍。如果解释的时候卡住了说明这块还没有真正理解。建议用录音或打字的方式记录下来再对照标准答案查漏补缺。另外一个实用技巧是给每个知识点总结一个回答模板一句话结论先直接回答面试官的问题。核心原理解释底层机制或关键流程。场景举例结合项目或代码说明。易错点主动说出常见的坑。这样回答会显得更有条理也不会因为紧张而漏掉关键信息。1.3 2026 前端面试考点趋势从近两年的岗位要求和面试反馈看前端面试的考点其实越来越“稳”基本集中在几个固定方向。JavaScript 底层机制依然是必考项尤其是闭包、this、原型链、事件循环、异步编程。框架考察从“会写页面”升级到“懂原理”比如 Vue 的响应式、虚拟 DOM、diff 过程React 的 Hooks 依赖、渲染优化。工程化与性能优化占比明显提升构建工具、打包体积、首屏加载、代码分割都是常见问题。TypeScript 几乎成为中高级岗位的基础要求至少要知道 interface、type、泛型、类型守卫。安全相关题目虽然占比不高但 XSS、CSRF、CORS 是高频基础题。随着 AI 工具普及部分团队开始关注候选人是否会用工程化手段接入大模型能力以及是否理解 AI 辅助开发中的质量边界。这些趋势不是绝对的不同公司和不同团队差异很大但把以上方向覆盖到面试通过率会有明显提升。2. 3 天复习计划与资料准备2.1 时间安排表下面是适合“速通”的 3 天安排每天拆成上午、下午、晚上三个时段。天数复习主题核心内容目标产出第 1 天JavaScript 核心作用域、闭包、this、原型链、事件循环、Promise、手写题练习能口述 5 个高频 JS 题会写 3 个手写题第 2 天浏览器、网络、框架HTTP 协议、缓存、渲染流程、Vue 或 React 高频题能回答框架原理并串讲一个项目中的缓存或渲染优化第 3 天工程化、性能、安全、TS构建原理、性能优化、安全防御、TypeScript、模拟面试完整答一遍高频清单做一次 30 分钟模拟面试每天的“晚间复盘”很重要。建议用一张思维导图记录当天错题和卡壳问题第二天早上先花 20 分钟复习。2.2 推荐资料与学习工具资料方面优先看官方文档。MDN 是 JavaScript 和 Web API 最权威的参考Vue 和 React 的官方文档也比二手博客更可靠。书籍类可以选《JavaScript 高级程序设计》和《你不知道的 JavaScript》但 3 天突击阶段不建议整本阅读只看对应章节即可。学习工具方面可以用 AI 工具辅助提问和代码调试但要注意大模型给出的答案不一定正确尤其是版本相关的 API。遇到不确定的问题一定要回到官方文档或源码里验证。另外强烈建议准备一个自己的“前端面试题清单”把已经掌握的问题打勾没掌握的问题标红。这样做的好处是复习过程有进度感不会乱了方寸。3. 第 1 天JavaScript 核心机制3.1 作用域、闭包与 thisJavaScript 的作用域分为全局作用域、函数作用域和块级作用域。var声明会被提升到函数作用域顶部而let和const会形成块级作用域并且存在暂时性死区。闭包是 JavaScript 中最核心也最容易绕晕的概念。简单说闭包就是一个函数能够访问它定义时所在作用域中的变量即使外部函数已经执行结束。function createCounter() { let count 0; return function () { count 1; return count; }; } const counter createCounter(); console.log(counter()); // 1 console.log(counter()); // 2上面的count被内部函数引用所以不会被垃圾回收每次调用都会在原来的基础上累加。这就是闭包的典型应用。闭包可以用于实现私有变量、柯里化、函数防抖等但也要注意如果闭包引用大对象且长期不释放会造成内存泄漏。this的指向是一个高频陷阱。在普通函数中this取决于调用方式直接调用指向window严格模式下为undefined作为对象方法调用指向该对象使用call、apply、bind可以显式指定指向使用new调用时指向新创建的对象。箭头函数没有自己的this它继承外层普通函数或全局作用域的this。3.2 事件循环事件循环是面试必考题它解释的是 JavaScript 单线程如何协调同步任务和异步任务。先看一段经典代码console.log(script start); setTimeout(() { console.log(setTimeout); }, 0); Promise.resolve().then(() { console.log(promise1); }); console.log(script end);在浏览器中的输出顺序是script start script end promise1 setTimeout原因在于执行同步代码时先输出script start和script endsetTimeout回调属于宏任务被放入宏任务队列Promise.then回调属于微任务被放入微任务队列。当前调用栈清空后事件循环会先清空所有微任务再执行下一个宏任务所以promise1比setTimeout先输出。回答事件循环问题时可以按这个顺序说调用栈、宏任务、微任务、渲染时机。在浏览器中每执行完一个宏任务会先处理微任务队列然后在合适时机进行渲染。3.3 异步编程异步编程的演进路线是回调函数、Promise、Generator 和 async/await。回调函数容易形成“回调地狱”Promise 用链式调用解决了嵌套问题async/await 则让异步代码看起来更像同步代码。使用 async/await 时要注意错误处理。await如果抛出异常会中断后面的代码建议用try/catch包裹async function fetchData(url) { try { const response await fetch(url); if (!response.ok) { throw new Error(请求失败); } const data await response.json(); return data; } catch (error) { console.error(接口异常, error); return null; } }面试中还可能追问Promise.all和Promise.allSettled的区别。前者只要有一个 Promise 变成 rejected 就会整体失败后者会等所有 Promise 结束后返回每个结果适合批量请求场景。4. 第 2 天浏览器、网络与框架题4.1 浏览器渲染与缓存浏览器从拿到 HTML 到页面显示大致经过以下步骤解析 HTML 生成 DOM 树。解析 CSS 生成 CSSOM 树。合并成渲染树。计算布局Layout/Reflow。绘制Paint。合成与显示Composite。面试常问的“回流和重绘”就发生在这个过程中。回流是指页面布局发生变化需要重新计算元素的位置和尺寸比如修改宽度、删除节点。重绘是指元素外观变化但不影响布局比如修改颜色、背景。回流的开销更大所以在项目中应该避免频繁修改触发回流的属性比如把多个样式变更合并为一次操作或者使用requestAnimationFrame批量更新。浏览器缓存也是一个高频题可以分为强缓存和协商缓存。类型关键词流程强缓存Expires、Cache-Control命中缓存直接使用不发请求协商缓存Last-Modified / If-Modified-Since、ETag / If-None-Match发请求给服务端验证304 则使用缓存Cache-Control是更推荐的强缓存控制方式常用配置有max-age、no-cache、no-store等。no-cache并不是不使用缓存而是每次需要先向服务端验证no-store才是不存储任何缓存。4.2 网络协议高频题网络相关的问题容易让前端开发者紧张但其实只需要掌握几条主线。HTTP/1.1 存在队头阻塞问题一个连接只能串行发送请求。HTTP/2 引入了多路复用、二进制分帧、头部压缩等能力解决了 HTTP/1.1 的队头阻塞问题但 TCP 层的队头阻塞仍然存在。HTTP/3 使用基于 UDP 的 QUIC 协议进一步降低连接延迟弱网环境下表现更好。HTTPS 握手可以这样一句话概括客户端与服务端通过非对称加密协商出对称密钥之后使用对称加密通信。握手过程中还包含证书验证用来确认服务端身份。TCP 三次握手是建立连接的过程客户端发送 SYN服务端回复 SYNACK客户端再发送 ACK。四次挥手是断开连接的过程因为 TCP 是全双工通信需要双方独立关闭各自的发送通道。4.3 Vue 高频面试题Vue 现在通常以 Vue 3 为主但 Vue 2 仍然存在于大量存量项目中所以高频题往往覆盖两个版本的核心概念。v-if 是真正的条件渲染不满足条件时不会渲染节点适合切换频率低的场景。v-show 只是通过 CSS 的display控制显示隐藏节点始终存在适合高频切换场景。computed 和 watch 的区别也很常考。computed 是基于依赖缓存的只有依赖变化时才会重新计算适合模板中需要派生数据的场景。watch 用于监听某个数据变化后执行副作用适合异步请求或复杂逻辑。组件通信方式包括父传子用 props子传父用 emit跨层级可以用 provide/inject全局状态用 Vuex 或 Pinia。Vue 3 中更多推荐 Pinia。关于 v-modelVue 3 中它是modelValue和update:modelValue的语法糖本质上是通过 props 接收值再通过事件通知父组件更新。!-- 子组件 Child.vue -- template input :valuemodelValue input$emit(update:modelValue, $event.target.value) / /template script setup defineProps([modelValue]) defineEmits([update:modelValue]) /scriptkey 的作用是帮助虚拟 DOM 在 diff 时识别节点是否复用。使用稳定的唯一 id 作为 key可以避免列表更新时的渲染错乱并提高复用率。Vue 3 的响应式系统是一个加分项。Vue 2 使用Object.defineProperty拦截对象的属性读取和修改Vue 3 改用Proxy可以监听新增和删除属性也支持数组索引变化。ref适合包装基本类型值reactive适合对象类型两者在模板中都会自动解包。4.4 React 高频面试题React 的核心考点包括虚拟 DOM、Hooks、组件更新机制和渲染性能优化。虚拟 DOM 是 React 对真实 DOM 的一层抽象。当状态变化时React 会先计算出新的虚拟 DOM再与旧虚拟 DOM 进行 diff最后只更新发生变化的真实节点。这个机制减少了直接操作真实 DOM 的次数配合批量更新提升了渲染性能。Hooks 的出现是为了让函数组件拥有状态和副作用能力。最常见的问题是useEffect的依赖数组到底该怎么写。如果依赖数组为空只在挂载时执行如果依赖项发生变化会在更新时重新执行如果不传依赖数组每次渲染都会执行。闭包陷阱是 Hooks 的经典坑。比如在setInterval中读取 state如果依赖数组没有包含这个 state定时器回调拿到的仍然是旧值。解决办法是在依赖数组中加入该 state或使用useRef保存最新值。useMemo和useCallback都用于性能优化。useMemo缓存的是计算结果useCallback缓存的是函数引用。它们需要配合子组件的React.memo使用否则子组件仍然会因为父组件重新渲染而跟着渲染。受控组件和非受控组件也是基础题。受控组件的表单值由 React state 控制非受控组件通过 ref 直接读取 DOM 值。大多数场景推荐受控组件因为数据流更清晰逻辑更可控。Fiber 可以简单理解为 React 的调度架构。它把渲染工作拆分成可中断的单元通过优先级调度实现并发渲染避免长时间阻塞主线程。持续版本特性建议以官方文档为准因为 React 迭代较快。5. 第 3 天工程化、性能优化、安全与题型演练5.1 前端工程化到底在考什么前端工程化是一个大的方向面试中常见的问题包括构建工具、模块化、代码规范等。Webpack 的核心概念是入口、输出、Loader 和 Plugin。Loader 用于处理非 JavaScript 文件比如把 TypeScript 编译成 JavaScript、把 CSS 解析成 JavaScript 可导入的模块。Plugin 用于处理 Loader 无法完成的构建任务比如打包前清理目录、生成 HTML 文件、压缩代码。用一句话区分 Loader 和 PluginLoader 是文件转换器Plugin 是构建生命周期中的扩展能力。Vite 之所以快是因为它在开发环境基于浏览器原生 ES Module利用依赖预构建和按需编译跳过 Webpack 的全量打包过程。生产环境则使用 Rollup 进行打包。模块化演进也是一个可能考到的方向从早期的全局变量、AMD到 CommonJS再到 ES Module。CommonJS 是同步的主要用于 Node 端ES Module 是静态的支持 Tree Shaking是前端主流方案。规范化方面团队一般会使用 ESLint、Prettier、husky 和 commitlint 来约束代码风格和提交信息。另外在后台管理系统中经常提到的“字典管理”一般用于把业务枚举值统一维护起来比如订单状态、用户类型前端通过接口拉取后渲染为下拉框或状态标签避免在代码里写死魔法数字。5.2 性能优化从哪些维度回答性能优化题很容易答散建议按“加载性能、渲染性能、运行时性能、监控体系”四个维度回答。加载性能优化包括减少首屏请求体积、开启 HTTP 缓存、使用 CDN、路由懒加载、组件按需引入、图片使用合适格式并开启懒加载。渲染性能优化包括减少 DOM 深度、避免频繁回流、使用 CSS transform 代替位置动画、对长列表使用虚拟滚动。运行时性能优化包括避免组件重复渲染、合理使用 memo 和 useCallback、大数据量计算放到 Web Worker 中执行。提到 Web Worker 时可以顺带讲一下大文件上传场景用 Worker 做分片读取和哈希计算避免阻塞主线程。监控体系方面需要知道常见的 Web 性能指标FCP、LCP、CLS、TTFB、FID 或 INP。FCP 表示首屏内容绘制时间LCP 表示最大内容绘制时间CLS 表示布局稳定性TTFB 表示服务端响应时间。5.3 前端安全该掌握到什么程度安全问题不需要深入攻击细节但要知道常见攻击形式和后端配套方案的原理。XSS 分为存储型、反射型和 DOM 型核心原因是把不可信数据当成 HTML 执行了。防御思路是对用户输入进行转义、使用 CSP 限制脚本来源、对敏感 Cookie 设置 HttpOnly。CSRF 攻击的核心是利用了用户的登录状态。防御手段有校验 Referer、使用自定义请求头、在请求中加入随机 Token、设置 Cookie 的 SameSite 属性。CORS 是浏览器同源策略下的跨域机制。开发时常见的是配置响应头Access-Control-Allow-Origin前端还需要注意预检请求OPTIONS。真正解决跨域问题应该由服务端配置开发环境可以使用 Vite 的 proxy 做代理转发。点击劫持通常通过透明 iframe 实现防御手段是设置X-Frame-Options或 CSP 的frame-ancestors。5.4 TypeScript 与业务场景题TypeScript 在面试中不一定要求精通但基础概念要能说清楚。interface和type都可以用来描述对象结构interface更强调接口的扩展性type更灵活可以定义联合类型、交叉类型、工具类型。实际项目中优先用interface描述对象用type组合复杂类型。泛型可以理解为类型的参数化。例如function identityT(value: T): T { return value; } const num identitynumber(10); const str identitystring(hello);类型守卫用来在运行时收窄类型。常见的写法包括typeof、instanceof和自定义类型谓词。function isString(value: unknown): value is string { return typeof value string; }业务场景题更看重你的分析能力。举一个常见的后台管理需求要新增一个“订单状态管理”页面应该如何设计可以从前端数据流、组件拆分、接口设计、状态字典映射、权限控制几个角度回答。这类题目是八股文的延伸考察的是工程思维。6. 代码题专项高频手写题完整答案6.1 手写题的回答框架手写题是很多人的心理障碍其实面试官并不一定要求你写出一模一样的源码更看重思路和边界意识。回答手写题可以按四步走先说思路我要实现的核心功能是什么。写代码先写最简版本再补边界情况。测试边界如果是空数组、嵌套对象、循环引用怎么处理。说复杂度时间和空间复杂度是多少。下面这几道手写题是前端面试中出现频率很高的题目。6.2 防抖与节流防抖和节流都用于控制函数执行频率。防抖是“触发后等待一段时间期间再次触发则重新计时”适合输入框搜索节流是“固定时间间隔内最多执行一次”适合滚动事件。function debounce(fn, delay 300) { let timer null; return function (...args) { if (timer) clearTimeout(timer); timer setTimeout(() { fn.apply(this, args); }, delay); }; } function throttle(fn, interval 300) { let pre 0; return function (...args) { const now Date.now(); if (now - pre interval) { pre now; fn.apply(this, args); } }; }使用function而不是箭头函数是为了保留调用时的this指向。通过fn.apply(this, args)可以把外层this正确传递给原函数。6.3 深拷贝深拷贝的关键是处理对象嵌套和循环引用。直接JSON.parse(JSON.stringify(obj))会丢失undefined、函数、Symbol也无法处理循环引用。function deepClone(target, map new WeakMap()) { if (target null || typeof target ! object) { return target; } if (target instanceof Date) { return new Date(target); } if (target instanceof RegExp) { return new RegExp(target.source, target.flags); } if (map.has(target)) { return map.get(target); } const clone Array.isArray(target) ? [] : {}; map.set(target, clone); Reflect.ownKeys(target).forEach((key) { clone[key] deepClone(target[key], map); }); return clone; }这里使用 WeakMap 记录已经克隆过的对象避免循环引用导致死循环。Reflect.ownKeys可以拿到包括Symbol在内的所有属性键。6.4 手写 Promise.allPromise.all接收一个 Promise 数组全部成功后返回结果数组失败则直接 reject。function promiseAll(promises) { return new Promise((resolve, reject) { if (!Array.isArray(promises)) { return reject(new TypeError(promises must be an array)); } const results []; let count 0; if (promises.length 0) { return resolve([]); } promises.forEach((item, index) { Promise.resolve(item).then( (value) { results[index] value; count 1; if (count promises.length) { resolve(results); } }, (error) { reject(error); } ); }); }); }注意两点传入的数组可能包含普通值所以需要用Promise.resolve包装结果数组的下标要与原数组保持一致而不是按完成顺序 push。6.5 new 实现、数组去重与发布订阅手写new是一个经典题。核心是创建一个新对象、绑定原型、调用构造函数并处理返回值为对象的情况。function myNew(Constructor, ...args) { const obj Object.create(Constructor.prototype); const result Constructor.apply(obj, args); return typeof result object result ! null ? result : obj; }数组去重最简单的方法是使用 Setconst unique [...new Set([1, 2, 2, 3, 3, 4])]; console.log(unique); // [1, 2, 3, 4]如果需要去重对象数组则要根据某个 id 字段手动处理。发布订阅模式常被用来考察事件模型的理解。下面是一个简单的 EventEmitterclass EventEmitter { constructor() { this.events new Map(); } on(name, fn) { if (!this.events.has(name)) { this.events.set(name, []); } this.events.get(name).push(fn); } emit(name, ...args) { if (this.events.has(name)) { this.events.get(name).forEach((fn) fn(...args)); } } off(name, fn) { if (this.events.has(name)) { const list this.events.get(name).filter((item) item ! fn); this.events.set(name, list); } } once(name, fn) { const wrapper (...args) { fn(...args); this.off(name, wrapper); }; this.on(name, wrapper); } }发布订阅模式在跨组件通信、消息通知场景中很常见理解了它再看 Vue 2 的$on、$emit或一些事件总线实现就会很轻松。6.6 基于 Web Worker 的大文件分片上传热词中有一个“前端使用 Worker 上传大文件”这确实是近两年性能优化方向的加分题。大文件上传如果直接在主线程读取会阻塞 UI用 Worker 做分片和哈希计算可以保证页面流畅。主线程部分// index.js const input document.getElementById(fileInput); input.addEventListener(change, () { const file input.files[0]; if (!file) return; const worker new Worker(upload.worker.js); const chunkSize 2 * 1024 * 1024; // 每个分片 2MB worker.postMessage({ file, chunkSize }); worker.onmessage (event) { const { progress, chunkIndex } event.data; console.log(分片 ${chunkIndex} 上传完成总进度 ${progress}%); }; });Worker 内部// upload.worker.js self.onmessage async (event) { const { file, chunkSize } event.data; const totalChunks Math.ceil(file.size / chunkSize); for (let i 0; i totalChunks; i 1) { const chunk file.slice(i * chunkSize, (i 1) * chunkSize); const formData new FormData(); formData.append(chunk, chunk); formData.append(index, i); formData.append(total, totalChunks); // 这里只是示例实际要换成真实的上传接口 await uploadChunk(formData); const progress Math.round(((i 1) / totalChunks) * 100); self.postMessage({ progress, chunkIndex: i }); } }; async function uploadChunk(formData) { // await fetch(/api/upload, { method: POST, body: formData }); return new Promise((resolve) setTimeout(resolve, 200)); }需要提醒的是File对象可以通过结构化克隆算法传递给 Worker这个方案适合大型文件处理。实际项目中还需要考虑分片失败重试、服务端合并分片、请求鉴权等逻辑并且只能将用户主动选择上传的文件发送到合法服务端避免把敏感信息交由来源不明的第三方接口处理。7. 高频问题排查与避坑清单7.1 面试现场常见问题怎么应对面试过程中经常出现“问题听懂了但不知道怎么组织语言”的情况。下面整理几个真实场景和应对思路。面试现象可能原因应对策略被问到完全没听过的概念知识盲区先坦白不了解再尝试根据字面意思分析给出推测手写题一开始写不出来紧张或思路不清先写简单版再做边界补充边写边讲思路项目讲得过于零散缺少结构用“背景、方案、成果、难点”四段式描述面试官连环追问回答不够深入主动补充原理和场景展示知识深度回答不会的问题时最忌讳的是沉默或不懂装懂。可以这样说“这个概念我之前接触不多但根据我的理解它可能跟 XX 有关。我的尝试思路是 XX。”这种回答至少展示了分析和学习能力。7.2 复习阶段最常见的误区只背八股文不写代码。面试到最后一定会考手写题或代码设计只看不练等于没掌握。只看结论不看原理。比如只知道 Vue 3 用 Proxy却不知道和 Object.defineProperty 的差异很容易被追问卡住。忽视项目经历。面试中八股文可能只占 30 分钟剩下时间都在聊项目和解决方案项目讲不好会非常减分。没有做模拟面试。对着镜子或录音自己复述和真实面试的感觉完全不同建议找朋友或线上伙伴做一次完整的模拟。只看新题不复习旧题。三天时间很紧张但每天复盘比刷更多新题更重要。如果你发现自己复习到第二天还是记不住第一天的问题不要慌。这是正常现象说明你还没有形成知识网络。可以尝试用思维导图把知识点串起来或者把高频题按“基础、框架、工程化、性能、安全”分类回答时不断关联同一方向的题目。8. 总结与后续学习建议前端八股文的本质是帮助你在短时间内把零散知识点连成体系。它不能替代真实的项目经验但能把你的基础“下限”拉高让你在面试中更稳、更敢表达。通过 3 天计划你应该至少掌握 JavaScript 核心机制、浏览器缓存与渲染、网络协议基础、Vue 或 React 常见原理、工程化与性能优化、前端安全、TypeScript 基础以及一组高频手写题。面试结束后真正的学习才刚刚开始。建议接下来继续做三件事把简历里每一个项目都写清楚“背景、方案、难点、成果”把面试中没答上来的问题整理成错题集每周至少阅读一篇官方文档或源码分析保持对底层原理的敏感度。最后提一点个人建议不要为了背题而背题。面试是一场沟通面试官想看到的是你如何思考、如何解决问题。每次回答前先停一秒想清楚结论再展开解释。如果你觉得本文内容对你有用可以先收藏把第 6 章的手写题逐行敲一遍再试着用录音录下自己对事件循环和 Vue 响应式的讲解看看能不能讲得流畅。祝正在准备前端面试的你早日拿到满意的 offer。
返回列表