尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

前端春招实习面经:高频考点与面试实战技巧复盘

前端春招实习面经:高频考点与面试实战技巧复盘 前端菜鸟的春招实习面经第二弹说好的“附答案”来了。上一篇我写的是简历和项目经历怎么准备这一篇聚焦真正坐到面试官对面之后的问题前端面试里到底是哪些题在反复出现哪些“送分题”其实暗藏陷阱以及我踩过坑之后总结出来的回答思路。文章里的每一道题都是我在春招实习面试过程中真实遇到并复盘过的答案不是标准背诵版而是能让你在面试现场“接得住、往下聊”的话术和推导逻辑。如果你的目标也是暑期实习或春招补录这篇文章可以直接当模拟题清单用。1. 春招实习面试的认知差先把“面试官在问什么”这个问题解决掉很多同学面完出来抱怨“面试官问的八股文我都会为什么还是挂了”我第一轮面试也是这个状态后来复盘才发现我把“知道答案”当成了“会面试”但面试官看的从来不是你知道什么而是你怎么组织答案、怎么暴露思路、怎么在对话中体现工程感。春招实习面试比秋招更看重潜力和学习速度所以面试官普遍会出一些“跳一跳够得着”的问题目的不是考倒你而是观察你在未知问题面前的应对方式。1.1 第一类面试官“八股流”这类面试官的风格是密集问基础从变量提升、闭包、原型链一路追问到 Promise、事件循环、浏览器缓存节奏很快几乎不给你喘息。我一开始遇到这种面试官容易慌因为每道题之间没有逻辑关联答完一道马上被问到下一个知识点思维一直在跳。后来我总结出一个应对策略把面试当成一次“结构化输出”训练。不管问题多散我都按同一套框架回答——“是什么 解决什么问题 使用场景/代码表现 局限/注意点”。比如被问到闭包时我不会只回答“函数嵌套函数、内部函数引用外部变量”而是继续补一句“闭包的核心价值是让变量在函数执行完之后仍然存活所以它常用于缓存、柯里化、私有变量封装但它也会带来内存不释放的问题常见的优化方式是在函数结束前把引用置空”。这段话只要多花二十秒面试官就会觉得你不只是背了定义而是真的理解它的应用边界。1.2 第二类面试官“场景流”场景流面试官不会直接问“什么是 Vuex”而是说“你现在做一个购物车模块多个页面需要共享已选商品数量你会怎么做”。这种问题没有固定答案考察的是你面对真实需求时的技术选型能力和权衡能力。我的经验是这类题千万别急着写代码先把业务背景问清楚。我一般会先反问几个问题购物车的状态是否需要持久化页面之间有没有其他交互团队里是不是已经有统一的状态管理库不需要每一个都问但至少要让面试官看到你有“业务复杂度评估”的意识。然后再分情况回答如果只是页面内传参用 props 和事件就够了如果涉及全局且有一定复杂度选用 Pinia 或 Vuex如果还要跨应用同步才会考虑 localStorage 加自定义事件或者微前端方案。这样答完整个答案的层次感就出来了。1.3 第三类面试官“简历深挖流”这种面试官最“麻烦”他们会从你简历里的任何一行小字开始问你这个项目里用了防抖为什么用防抖和节流的区别是什么如果用户疯狂点击防抖会有什么体验问题你怎么办项目里的权限是怎么控制的如果后端返回的权限字段不符合预期前端应该怎么兜底简历深挖流本质上是在验证一件事项目是不是你自己做的。所以最好的应对方式不是背项目描述而是把项目从需求到实现完整过一遍尤其是“当初为什么选这个方案”和“后来踩过什么坑”这两类故事性内容。我真实的体会是凡是自己一步步调出来的问题聊起来会非常自然甚至会有“终于有人问我这个了”的舒畅感凡是背的、抄的、一知半解的面试官只要连续追问三次就会露出破绽。1.4 拿不稳时先确认题目再开始答第二弹最想分享的认知是“确认题目本身就是一种能力”。实习面试里经常会遇到题干里带模糊概念的情况比如面试官说“你觉得前端性能优化可以从哪些方面入手”这时候如果我直接开答大概率会漏重点。更好的回应是“您说的是项目上线后针对用户的性能优化还是针对开发阶段的构建优化如果以首屏加载为主我会从网络层、渲染层、代码层三个方向梳理。”这段话一出来面试官通常会默认你至少有分层思考的底子哪怕后续回答深度不够印象分也会比“直接从缓存开始背”要高。面试不怕问得多怕的是答跑偏——确认题目的过程本身就是在展示你的沟通能力。2. JavaScript 高频考点的变形问法闭包、this 与事件循环的临场反应JavaScript 基础是实习面试躲不掉的必考区但面试官基本不会问“什么是闭包”这种教科书题。我遇到的更多是“这道题输出什么”“这段代码有什么问题”“改成这段代码会发生什么”以及各种组合式考察。下面这几类是我在春招面试里出现频率最高的。2.1 闭包不背定义要会推断输出结果和内存问题面试官拿出一段很常见的代码for (var i 0; i 5; i) { setTimeout(function () { console.log(i); }, 1000); }问输出结果是什么。答案是连续打印 5 个 5这个大多数人都知道但面试官更在意你解释“为什么”和“怎么改”。我当时的回答思路是因为 var 声明的 i 属于函数作用域for 循环结束后 i 已经变成了 5而 setTimeout 的回调函数在这个时刻才会读取 i所以拿到的都是同一个变量 5。改成 let 可以解决因为 let 是块级作用域每一次循环都会创建一个新的绑定所以闭包捕获的是不同的 i。面试官追问“除了 let 还有没有别的方案”时我补充了两个一是用 IIFE 包裹一层把当前 i 作为参数传入二是把 setTimeout 提取成一个独立函数每次调用传入 i。这两种改法本质上都是“创建新的作用域来保存当前值”。在这个基础上还能继续展开闭包的内存问题。闭包会持有外部函数的变量引用如果这个引用是一个很大的对象而闭包本身又被长期持有就会造成内存无法回收。比如在 Vue 组件里如果给 element 绑定了带闭包的事件监听组件销毁时没有移除监听闭包里的数据就会一直留在内存里。我遇到过的追问是“你怎么验证内存泄漏”我当时答的是“用 Chrome DevTools 的 Memory 面板录制堆快照对比操作前后的 Retained Size或者用 Performance Monitor 看 JS heap size 是否持续上升”面试官比较认可这个回答。2.2 this 指向一套能 cover 住多数场景的判断顺序this 指向问题是实习面试的“送命题”因为它硬背很难背全。我后来总结出一套判断顺序帮助自己在现场快速找到答案看函数是怎么被调用的如果是obj.fn()this 就是 obj如果是普通调用fn()在非严格模式下是 window严格模式下是 undefined。看有没有 new有 new 时 this 指向新创建的对象且优先级最高。看有没有 bind / apply / call有的话 this 被显式指定其中 bind 的优先级高于 apply 和 call。如果是箭头函数以上规则全部失效this 来自定义时所在的外层作用域。实际面试里最常考的两个场景是事件处理和定时器。比如const obj { name: frontend, getName() { console.log(this.name); } }; const fn obj.getName; fn(); // undefined 或报错取决于是否严格模式这里的关键是把方法赋值给变量之后再调用调用位置变成了全局作用域所以 this 不再是 obj。这个问题的延伸点是“那怎么让 this 保持为 obj”我的回复思路是用fn obj.getName.bind(obj)或者在事件回调里用() obj.getName()通过箭头函数锁定外层 this。2.3 事件循环Promise 输出顺序题的现场推演事件循环是春招面试的高频题而且几乎逢面必问。面试官通常让我说下面这段代码的输出顺序console.log(start); setTimeout(() { console.log(timeout); }, 0); Promise.resolve().then(() { console.log(promise1); }); async function foo() { console.log(foo); await Promise.resolve(); console.log(foo-after); } foo(); console.log(end);正确答案是start - foo - end - promise1 - foo-after - timeout。这里有两个关键点一是await后面的代码相当于.then()里的回调会被放入微任务队列二是微任务队列会清空后才执行宏任务所以两个微任务都排在timeout前面。面试官还会问一个很经典的问题“为什么微任务的优先级高于宏任务”我当时回答的角度是微任务主要用来处理 Promise 回调、MutationObserver 这类需要尽快执行的任务如果微任务被宏任务阻塞那么 Promise 的链式回调就会被延迟开发者体验会下降。所以浏览器在执行完一个宏任务后会立刻把当前微任务队列清空再进入下一次宏任务循环。到了这一层我还会主动补一句“实际上不同环境对任务队列的实现并不完全一致比如 Node.js 里的 process.nextTick 优先级比 Promise 更高所以在浏览器和 Node 环境里跑同样的代码输出顺序可能不同”。这句话看起来是补充知识其实是在向面试官传递一个信号我不是死记输出顺序而是理解了事件循环在不同宿主环境下的差异。2.4 必会手写题带并发限制的异步调度器实习面试里的手写题一般不会考太偏的数据结构反而是业务上经常遇到的“异步并发控制”出现频率很高。我遇到的原题是实现一个Scheduler保证同时最多两个任务在执行任务依次输出。class Scheduler { constructor(limit 2) { this.limit limit; this.running 0; this.queue []; } add(task) { return new Promise((resolve) { const run async () { this.running; try { await task(); resolve(); } finally { this.running--; this.next(); } }; this.queue.push(run); this.next(); }); } next() { while (this.running this.limit this.queue.length) { const task this.queue.shift(); task(); } } }我当时先写了一个简化版本把核心逻辑跑通然后主动跟面试官说“我补一个任务失败也能继续执行的版本”于是加上了 try/finally。面试官接着问“如果任务超时怎么办”我答可以用Promise.race包一层超时控制并解释这样做的风险是任务本身没有取消只是主流程不再等待它。这类问题其实是考察异步编程的边界意识答出来就是加分项。3. Vue 面试题真正想考的响应式、组件通信、diff 与业务场景的结合如果你的简历里写了 Vue 项目那 Vue 相关的追问基本是逃不掉的。2026 年这个时间点面试官大概率不会一上来就问你“Vue2 和 Vue3 有什么区别”而是会把问题放到具体场景里考察你的理解深度。3.1 响应式原理从数据劫持讲到一个“为什么 Vue3 换成了 Proxy”这道题的经典问法是“Vue 的响应式原理是什么”很多人的回答止步于“Vue2 用 Object.definePropertyVue3 用 Proxy”。但面试官如果只是想听这句话根本不用约面。我面了多轮之后发现真正好的回答结构是四层第一层Vue2 的数据劫持。核心是Object.defineProperty遍历 data 的每个属性把它转成 getter/setter。组件渲染的时候render 函数会读取相关数据触发 getter进入依赖收集数据变更时触发 setter通知订阅者执行更新。第二层依赖收集和派发更新的对象关系。每个响应式属性有一个 DepDep 里装着若干 Watcher组件渲染会创建 Render Watchercomputed 会创建 Computed Watcher用户自定义的 watch 本质上是创建一个 User Watcher。第三层Vue2 的局限。数组下标更新和新增对象属性无法被劫持所以 Vue2 提供了Vue.set和重写数组方法的方案来弥补。这个局限是Object.defineProperty本身的能力边界导致的因为它在属性层面工作而不是在对象层面。第四层Vue3 为什么换成 Proxy。Proxy 可以代理整个对象包括新增属性、删除属性和数组下标变更同时惰性代理还能避免 Vue2 初始化时递归遍历对象带来的性能开销。面试官如果继续问“Proxy 有没有代价”我一般会补一句Proxy 的兼容性不如 defineProperty而且它无法被 polyfill 到老浏览器同时代理对象带来的额外复杂度和性能损耗在超大对象上仍然需要关注所以 Vue3 内部对嵌套对象也会采用惰性拦截。这样一个递进式回答基本能把大多数 Vue 响应式追问给包住。3.2 组件通信props 之外的选择其实是在考设计取舍“组件通信方式有哪些”也是必问题。我一开始就是背概念props、$emit、vuex、provide/inject、$refs、event bus。但是这样答完面试官马上会追问“到底什么时候用哪一种”。后来我就把回答改成了“按场景选型”的方式父子组件紧密耦合、数据只在局部使用直接用 props 和 emit。多个不相关组件共享全局状态比如用户信息、权限、购物车用 Pinia 或者 Vuex。祖先组件向深层后代传递数据且中间层不需要感知用 provide/inject。父组件要获取子组件的实例或方法用 ref但这不是首选因为会形成组件间的隐式依赖。举一个我在项目里遇到的实际案例一个工单列表页有筛选条件、列表、分页三个组件筛选条件变化后列表要重新请求数据。如果全部用 props/emit 层层传列表和筛选之间隔着父组件每增加一个联动关系父组件就要新增一个方法代码会越来越乱。我当时用 Pinia 存了筛选状态筛选组件触发 action 更新状态列表组件直接 watch 状态变化请求数据分页组件只读取分页字段。这个方案导致需要额外学习 Pinia但换来的是后续需求迭代时不用频繁改父组件。面试时原原本本把这个决策过程讲清楚会比背十个通信方式有用。3.3 虚拟 DOM 与 keydiff 算法只要讲清这三点就够了关于 diff 算法面试官问得最多的是“为什么列表渲染需要 key”。我的回答思路是先讲清楚 diff 的流程新旧 VNode 进行对比时如果同一位置节点的标签名或 key 不同就直接替换如果相同则进入 patch 更新属性并递归对比子节点。然后讲 key 的作用key 是给每个节点一个稳定标识让 diff 算法能够识别“同一个节点在不同渲染中的位置变化”。没有 key 时Vue 默认按索引进行“就地复用”如果列表顺序变了diff 会用错误的内容去复用导致组件状态错乱最常见的例子是输入框内容跟着列表项一起“串位”。最后可以补一个边界场景如果列表项是纯展示文本且不会重排用 index 当 key 也不会出问题。但是一旦列表支持删除、排序、动态插入或者列表项里有表单状态就必须用唯一 id。这个“什么场景不能用 index”的主动性回答能明显拉开和其他候选人的差距。3.4 Composition API复用逻辑不是“换语法”而是重新组织逻辑Vue3 的 Composition API 是高频考点但面试官不会问你“setup 里有什么”而是会问“你项目里为什么要用 Composition API”。我的回答是这样的Option API 里一个功能的代码被拆分到 data、methods、watch 等多个区块功能一多就出现“一个功能分散在多个位置或者一个位置混着多个功能”的问题。Composition API 允许我按照功能组织代码把某个业务逻辑相关的状态、计算属性、方法放一起再用自定义 hook 抽取复用的逻辑。更具体一点我在项目里写过一个useTableList的 hook封装了 loading、data、paginations、fetchList 和 refresh 方法同一个项目里两个列表页直接复用。以前如果用 mixins虽然也能抽取但是数据来源不清晰项目里出现同名属性还会互相覆盖。Composition API 的“显式返回 命名空间”天然规避了这个问题。面试官继续追问“Composition API 有什么坑”时我强调过两个一是不要把所有代码都塞进一个 setup 函数里否则跟 Option API 里的大杂烩没有本质区别二是响应式丢失问题——解构 reactive 对象时会导致失去响应性所以需要用toRefs或直接保持reactive对象引用。这些都是真实开发中踩过的坑聊出来比背概念真实得多。4. 浏览器、网络与性能优化别让“背过结论”成为面试现场的水平线浏览器与网络这一块很多实习生在准备时容易掉进“背八股”的陷阱知道缓存有强缓存和协商缓存知道 TCP 三次握手但一被问“实际项目里你怎么验证缓存生效”就卡住了。春招面试里这一块也是最容易从“考察知识”滑向“考察实战”的区域。4.1 URL 到页面展示怎么答才能展示工程经验“浏览器输入一个 URL 到页面展示中间发生了什么”是经典题几乎每一轮面试都会遇到。我用一条主线把答案串起来网络请求、页面解析、渲染流程、资源加载优化。先讲网络请求浏览器解析 URL进行 DNS 解析拿到 IP 后建立 TCP 连接如果要走 HTTPS 还要加上 TLS 握手然后发送 HTTP 请求服务器返回 HTML 和相关资源浏览器再逐层解析。接着讲页面解析HTML 解析器把 HTML 转为 DOM 树CSS 解析器把 CSS 转为 CSSOM 树两者合成渲染树然后经过布局、绘制、合成最终把像素显示到屏幕上。需要注意JavaScript 的执行会阻塞 HTML 解析所以脚本标签放在 body 底部或者使用 defer/async 来避免阻塞首屏CSS 的加载会阻塞渲染所以 CSS 放在 head 里尽早加载但过大的 CSS 会延长首屏时间。最后一次我会主动提到“我在实际项目里遇到过字体文件阻塞渲染的问题”这类细节。前端加载字体时如果字体文件体积很大在字体下载完成前是看不到文字内容的也就是 FOUT 换 FOIT 的问题。面试官听到这种细节会觉得你真的做过页面而不是只会背面试题。4.2 浏览器缓存从强缓存到协商缓存的完整链路缓存是实习面试的高频题。比较好的回答思路是先给一个“速度排序”内存缓存、Disk Cache、强缓存、协商缓存、网络请求。强缓存的实现方式是后端在响应头里返回Cache-Control或Expires如果命中强缓存浏览器直接用本地副本不会发请求。Cache-Control: max-age3600这类字段优先级高于 Expires因为 Expires 依赖本地时间本地时间被改了结果就不稳定。协商缓存则是在强缓存过期后浏览器带一些验证字段去问服务器“资源变没变”服务器返回 304 就继续用本地副本返回 200 就下载新资源。验证字段主要有两类Last-Modified / If-Modified-Since基于时间粒度可能为秒级可能有误差和ETag / If-None-Match基于资源指纹更精确优先级更高。面试官如果继续问“那你怎么给项目里的静态资源配置缓存”我会分两层说对于带指纹的打包产物文件名里有 hash可以用Cache-Control: max-age31536000, immutable因为内容一变文件名就变缓存一年没问题对于 HTML 文件不用长缓存通常no-cache让它每次走协商缓存避免老页面引用旧资源。这个“带 hash 的资源可以放心长缓存”的判断是区分有没有实际部署经验的试金石。4.3 登录态、跨域与安全把实习项目里踩过的坑直接变成回答素材实习面试里登录态问题也算常见尤其是做过真实项目的同学基本都会被问到“你的 token 存在哪里为什么”。存储 token 有两种常见方式localStorage 和 cookie其实都有利有弊。localStorage 的优点是纯前端可控不受 cookie 路径限制也被更容易被 XSS 攻击窃取因为任何能执行脚本的攻击者都可以直接localStorage.getItem(token)。HttpOnly cookie 则无法被脚本读取XSS 拿不到天然降低了风险但会面临 CSRF 等跨站请求伪造问题。所以现代项目里Access Token 放内存刷新用的 Refresh Token 放 HttpOnly Cookie是常见做法。面试官还会顺带问“什么是 XSS怎么防御”。我的回答方向是XSS 的核心是“把不可信数据当成代码执行了”。防御手段有输入过滤、输出转义特别是在 v-html 场景里以及设置 CSP 白名单。当时我还补充了一个项目里遇到的例子评论区用户输入了img srcx onerroralert(1)如果不做转义就会在所有人浏览器里执行脚本。这个例子一讲面试官就明白你是真的处理过安全问题。4.4 首屏性能优化面试官只要一深入就进入你的主场性能优化这个话题在实习面试里属于“加分题”因为很多候选人只会背指标名说不清具体怎么优化。我整理了一套自己的回答框架按首屏时间拆分网络层开启 CDN 加速静态资源分发资源合并与压缩图片使用 WebP 或 AVIF 格式并用懒加载避免首屏外图片阻塞。代码层路由懒加载拆 chunk首屏只加载当前页面需要的代码合理拆分 vendor避免第三方库全部打进首屏 bundle。渲染层关键 CSS 内联或尽早加载减少 DOM 嵌套层级避免长列表一次性渲染用虚拟列表注意在 mounted 里不要做太重的工作。指标监控用 PerformanceObserver 监听 LCP把数据上报到监控平台持续观察优化效果。面试官如果问“你怎么判断哪个方向优先”我会说“先测量再优化”。用 Lighthouse 跑分用 Performance 面板看网络瀑布图和 long task优先处理耗时最长、收益最明显的环节而不是一上来就做各种花式优化。这个“先量后优”的思路放到任何项目里都适用。5. 面经不是面完就结束复盘方法和心态节奏是第二弹翻盘的关键最后一节的含金量不在于知识本身而在于“如何把一场面试变成下一场的燃料”。我前两轮面试结束后明显感觉到同样是面完有些人只是离开会议室有些人却带走了下一轮获胜的资本。5.1 面试结束后的 24 小时复盘法面试结束后的 24 小时内是记忆最鲜活的窗口期一定要趁热记录。我的方法是记三个清单被完整答出来的问题标记“已掌握”。部分答出但不够深入的问题标记“需补全”。比如我知道 Vue.use 的原理但没解释清楚 install 方法怎么被调用这种就属于“半懂”。完全不会的问题标记“盲区”。盲区清单才是复盘的最大价值因为下一次面试大概率还会以不同方式问到同一个知识点。我通常会在笔记本里建一个表格列“问题 / 我的回答 / 面试官的反应 / 更优答案 / 关联知识点”五列。不要只记答案要把面试官听到回答后有没有继续追问也记下来——追问往往才是真正的考点。5.2 把“不会的问题”转化为下一轮的知识增量“不会”不可怕可怕的是不会之后不去补。我在一次面试里被问到“Vue 中为什么 v-for 和 v-if 不建议同时使用”当时没答好回来之后专门去看了 Vue 官方文档和编译源码分析。结论是v-for 的优先级高于 v-if每个循环项都会进行一次 v-if 判断导致渲染了多余的无用节点。我用这段复盘知识在下一轮面试同类问题里不仅答出了优先级顺序还把“filter 后再渲染”的替代方案一并给了出来面试官明显更满意。所以建议各位每次面完把不会的问题当作“新知识点清单”一个一个啃掉。春招实习面试不需要你什么都会但需要你每一次都有明显增量。5.3 如何坦诚说“我不会”又不丢分面试里难免遇到完全不会的题怎么处理很关键。我试过两种错误方式一是硬编编一个听起来合理的答案结果面试官追问两句就露馅二是直接说“我没学过”然后就沉默把场面弄得很尴尬。后来我总结出比较自然的公式表达边界 给出思路 展示学习意愿。比如面试官问“你知道如何在 Web Worker 里使用 WebAssembly 吗”我如果不会会这样回答“这块我目前没有实际经验但我理解 Worker 里可以加载 wasm 模块并通过共享内存与主线程通信。如果项目里有这个需求我会先去查一下 assemblyscript 或者 Rust 编译到 wasm 的调用方式再用示例项目快速验证可行性。”这样回答的潜台词是我不会完整方案但我了解解决路径也具备快速学习的能力。实习面试本质上看的也是这个而不是你已经会了多少。5.4 从投递节奏到 Offer 选择给菜鸟的三条参考关于春招实习的投递节奏我的建议是“先小厂练手再目标厂冲刺”。直接去面最想去的公司容易因为没有面试经验而发挥失常而且春招时间窗口有限浪费一次机会就少一次。先把一两个非目标公司作为模拟面试场熟悉对话节奏、问题类型和临场状态再去面目标公司会更稳。拿到多个 Offer 之后不要只看薪资和公司名重点看三件事团队技术栈是否与你的方向匹配、是否有带教机制、业务是否真实且可接触核心功能。实习的核心目的是成长我身边有同学去了大公司边缘业务结果三个月都在写活动页也有同学去了中小厂核心前端团队直接参与了组件库建设和工程化改造后者的成长更快、简历素材也更丰富。最后说一个玄学但真实有效的点面试是双向选择你也在面试这家公司。遇到让我感觉沟通不畅、技术判断模糊、没有收获的面试就算通过了我也要慎重考虑。因为实习只有几个月找一个能让你“每周都有成长感”的团队比单纯拿一个 Offer 重要得多。希望第二弹能在你春招之路的某个节点帮上忙我们下一篇见。
返回列表