
我是2022年参加秋招的那年前端岗位的竞争有多激烈不用多说小米的笔试属于筛人比较狠的那类。做完卷2出来最大的感受是网上那些“背八股”的备考思路真的行不通它的题目不会直接问你“闭包是什么”而是给一段代码让你猜输出或者给你一个业务场景让你用JS实现。它也不会直接问你“Flex布局有哪些属性”而是让你手写一个两栏自适应布局还得考虑各种边角情况。这篇就当作一份复盘我把这场笔试涉及的考点、答题思路和踩过的坑都整理出来给接下来准备前端笔试的同学做个参照。尤其是那些处于“看得懂概念、写不出代码”阶段的同学这篇文章应该对你有帮助。1. 秋招前端笔试到底在考什么1.1 笔试筛选的本质逻辑先把话挑明大厂秋招笔试不是用来选拔“天才”的而是用来快速过滤“基础不扎实”的候选人。每天有上万份简历单纯看简历很难判断真实水平一份标准化试卷就变成性价比最高的筛选工具。前端岗位的笔试尤其如此因为前端开发的“入门门槛低、精通门槛高”会写几个页面的人和能独立负责复杂项目的人写出来的代码完全是两个层次。小米这类公司的笔试题目核心考察三件事。第一你是否真的理解JavaScript这门语言的核心机制而不是只会调用API第二你是否有工程化思维能不能写出可维护、高性能的代码第三你在面对未知问题时有没有一套自己的分析框架。这三点对应到试卷上就是基础选择题、手写代码题和业务场景题。还有一个容易被忽略的点笔试也是公司文化的一次筛选。题目难度大、时间紧本身就带着压力测试的性质。很多人考完觉得自己“被针对了”其实大家拿到的题都一样拼的就是平时积累和考场心态。1.2 前端知识体系与题型分布经历过几次大厂笔试之后我总结出一个结论前端笔试的题型虽然千变万化但知识框架是固定的。以小米秋招卷2为参照大致可以分成四个模块这里我把它列成一张表方便你对照自查。知识模块典型考察形式占比预估说明JavaScript基础代码输出、原型链、this指向、异步编程30%-35%最核心拉开差距的地方CSS与浏览器布局实现、盒模型、渲染机制、性能优化20%-25%考察是否只停留在“会用”层面框架与工程化Vue/React原理、构建工具、模块化20%-25%考察项目经验的深度算法与场景题手写实现、编程题、设计题20%左右考察代码基本功和临场思维从这张表里能看到一个趋势纯背诵型题目比重在下降理解型和应用型题目比重在上升。以前面试喜欢问“Vue的v-model是怎么实现的”现在笔试直接给你一段自定义组件代码让你分析它是怎么实现双向绑定的。这种出题方式就是逼你把底层原理吃透而不是背几句面经。接下来我按照实际做题的顺序逐个模块拆解考点和答题技巧。2. JavaScript 核心考点拆解2.1 原型链与继承机制原型链这个考点小米的笔试题出得很有代表性。它不是直接问你“原型链是什么”而是给出一段构造函数和实例的代码然后让你判断obj.__proto__、Fn.prototype、Object.prototype之间的关系或者分析一段继承代码的缺陷。我记得卷2里有一道选择问的是一个对象经过多层继承之后某个属性是否能被访问到。这种题的关键是画图。我从大学开始就养成了一个习惯遇到原型链题先在草稿纸上画出关系链再用“属性查找规则”去验证——实例自身没有的属性就沿着__proto__一直向上找直到Object.prototype再往上就是null。手写继承方式也是一个高频出题点。组合式继承、寄生组合式继承、ES6 class 继承三者的区别至少要把原理说清楚。我建议不要死记代码而是理解核心思路// 寄生组合式继承的核心子类原型指向父类原型的副本 function inherit(Child, Parent) { Child.prototype Object.create(Parent.prototype); Child.prototype.constructor Child; }Object.create()相当于做了一层隔离避免子类修改原型时污染父类。这个细节经常被当成隐藏考点。如果你在笔试里写“我用 class”面试官也不会觉得有问题但如果你能说出“class 语法本质还是寄生组合式继承只是语法糖”那就能体现出深度。2.2 this 指向、作用域与闭包this 指向的题目几乎每套笔试都有。小米卷2里有一道题我现在还记得它把对象方法、解构赋值、箭头函数混在一起让你判断最终输出。这种题的解题逻辑其实很朴素谁调用this 就指向谁箭头函数除外。有一个坑我踩过这里单独提一下。对象方法里的置函数const obj { a: 1, fn() { setTimeout(function() { console.log(this.a); }, 0); } }; obj.fn();这个输出是undefined因为setTimeout的回调函数在全局作用域下执行非严格模式下this指向window。如果换成箭头函数输出才是1。很多人在笔试时做错是因为没有区分“定义时所在作用域”和“运行时调用方式”这两个概念。闭包这块重点不是背定义而是会用。笔试里最常见的闭包应用就是防抖和节流。这里我给出一个我当时手写的防抖版本供你参考function debounce(fn, delay) { let timer null; return function(...args) { if (timer) clearTimeout(timer); timer setTimeout(() { fn.apply(this, args); }, delay); }; }注意两点第一返回的函数要用普通函数而不是箭头函数否则外层this被固化apply就没意义了第二要保留参数传递能力。这些小细节往往是阅卷时给不给满分的关键。2.3 事件循环与 Promise 异步关卡异步编程是前端笔试的“必考压轴题”之一。常见的出题形式是给出一段混合了setTimeout、Promise、async/await的代码让你写出输出顺序。我见过太多人在这种题上丢分原因不是不懂概念而是没有形成一套固定分析方法。我的分析步骤是这样的第一把宏任务和微任务区分开Promise.then、MutationObserver属于微任务setTimeout、setInterval、I/O 属于宏任务第二每个同步代码执行完毕后清空微任务队列再取一个宏任务执行第三async函数内部遇到await会先把await后面的表达式执行掉然后后面代码作为微任务入队。看一道经典例子async function test() { console.log(1); await console.log(2); console.log(3); } test(); setTimeout(() console.log(4), 0); new Promise(resolve { console.log(5); resolve(); }).then(() console.log(6)); console.log(7);输出顺序是1 2 5 7 6 3 4。我当时用这套逻辑很快就算出来了。核心心法就一句话微任务永远比宏任务先执行而await右边的代码会立即执行后面的代码等同于.then()。平时训练时可以在浏览器控制台里反复跑这类题目自己的判断错了就停下来分析原因比盲刷十套卷子都管用。3. CSS 布局与浏览器原理考点解析3.1 盒模型与 BFC 的底层理解很多人觉得 CSS 简单笔试里遇到盒模型相关的题目才发现自己只是“会用”。那年卷2里有一道关于box-sizing的选择题如果把content-box切换成border-box一个width: 200px; padding: 20px; border: 5px的元素实际占用宽度怎么算。答案是内容区宽度会变成 150px总宽度保持 200px。这里考的是有没有真正理解两种盒模型的区别。BFC块级格式化上下文也是高频考点。笔试不会直接问“什么是BFC”而是给你一段代码问为什么高度塌陷了或者为什么两个相邻元素发生了外边距合并。这些问题的底层答案都是同一个因为没有创建 BFC 或者用错了创建方式。创建 BFC 的常见方式包括float值不为noneposition为absolute或fixeddisplay为inline-block、flex、grid等overflow不为visible有一个小技巧我到现在还在用优先用overflow: hidden或者display: flow-root创建 BFC。因为float会带来布局影响position会脱离文档流而后两种方式的副作用最小。笔试时如果把这一层考虑进去你的答案就和普通“背书型”选手拉开了差距。3.2 布局高频题水平垂直居中如果要给前端笔试的高频题排名水平垂直居中一定进前三。小米卷2里有一道手写题要求实现一个宽高未知的元素在容器内水平垂直居中并写出两种以上方案。这道题看着简单但考察的知识点很密集position定位、transform、flex、grid、margin: auto每个方案背后都是一套现代布局体系。我推荐的解题顺序是这样的首先从flex方案入手一行代码display: flex; align-items: center; justify-content: center;就能解决而且适用于动态宽高然后写absolute transform方案注意transform: translate(-50%, -50%)的偏移量是相对于元素自身尺寸的所以不需要知道宽高最后写上grid方案place-items: center简单且语义清晰。这里说一个容易踩的坑老式教程里的margin: 0 auto只能实现水平居中垂直居中的场景下必须用position: absolute配合四边0和固定宽高否则垂直方向根本不会居中。如果笔试时你画蛇添足写上这个方案阅卷人会认为你基础不牢。3.3 浏览器渲染流程与性能优化浏览器渲染过程这块属于“知道的人觉得简单不知道的人只能乱编”的知识点。我建议按照以下链路去记HTML 解析成 DOM 树CSS 解析成 CSSOM 树两者合成渲染树Render Tree然后进行布局Layout计算每个节点的几何位置再绘制Paint到屏幕上最后通过合成Composite展示给用户。笔试里围绕这个链路经常出的题目是下面哪些操作会引起重排哪些只会引起重绘修改color只触发重绘修改width或height触发重排。重排一定会触发重绘重绘不一定触发重排。还有一个优化点是批量修改样式用class而不是逐条修改style因为后者可能触发多次重排。关于性能优化我印象最深的一道题是“如何优化一个包含几千个 DOM 节点的长列表”。我的回答思路分三层第一层从渲染层面讲用DocumentFragment批量插入节点减少重排次数第二层从数据层面讲用虚拟滚动只渲染可视区域的内容。能把这两层讲出来这道题基本就拿下了。如果能再补一句“可以用content-visibility: auto让浏览器跳过屏幕外元素的渲染”那就更亮眼了。4. 框架应用与工程化能力考察4.1 Vue 与 React 的原理级问题小米这种体量的公司框架题不会停留在“你用过哪些 API”的层面而是会问“响应式原理是什么”或者“虚拟 DOM 的 diff 算法怎么优化”。我记得有一道题是让分析 Vue2 和 Vue3 响应式系统的差异考察的重点其实是Object.defineProperty与Proxy的对比。我用一个表格来整理这个考点笔试时可以直接参考对比维度Vue2definePropertyVue3Proxy监听方式遍历对象属性逐一劫持直接代理整个对象新增属性无法自动响应需 Vue.set自动响应数组操作需要重写数组方法原生支持性能数据量大时初始化较慢惰性代理性能更优兼容性支持 IE 更友好不支持 IE如果你只答“Proxy 比 defineProperty 强”那就是 60 分水平。加一句“Vue2 无法检测数组索引变化所以需要重写 push、pop 等方法”再加一句“Vue3 的响应式是惰性的不会递归代理整个对象而是在 get 时才进行依赖收集”分数立马就不一样了。这里有“性能”两个字阅卷人会立刻把你的水平划分到“有真实项目经验”那一档。虚拟 DOM 的考点也同样如此。不要只说“React 用虚拟 DOM 提升性能”要补充说明虚拟 DOM 减少的是“直接操作真实 DOM 带来的重排重绘成本”并非完全避免。还要能说出 diff 的核心优化策略同层比较、key 值复用、双端指针。能指出 “key 不要用 index” 并解释原因也是加分项。4.2 工程化、模块化与构建工具工程化是笔试里特别容易拉开差距的地方。很多自学前端的同学只写过单页面项目对 webpack、vite、模块化规范这些只停留在“用过”阶段一旦笔试问到底层概念就露馅了。卷2里有一道题大概是问 loader 和 plugin 的区别。这个必须答清楚loader 负责将文件转换为模块在模块加载阶段工作比如babel-loader把 ES6 转成 ES5plugin 负责在构建生命周期中执行更广泛的任务比如代码压缩、资源管理、环境变量注入。用一句话总结就是“loader 处理文件内容plugin 监听构建过程并干预结果”。模块化的考察也很常见。ESMES Module和 CommonJS 的差异我列几条方便记忆语法上ESM 用import/exportCommonJS 用require/module.exports加载时机ESM 是编译时静态解析CommonJS 是运行时加载输出方式ESM 输出的是值的引用CommonJS 输出的是值的拷贝浏览器支持ESM 原生支持CommonJS 需要打包器处理如果你还能说出“ESM 可以做 tree-shakingCommonJS 不行因为静态分析无法确定 require 的结果”那这道题就答得很漂亮了。tree-shaking 是近年非常高频的词要理解它是因为 ES 模块导入导出是静态的所以构建工具可以删掉那些被 export 但从未 import 的代码。4.3 代码组织与设计模式框架层面的题目有时候会延伸到设计模式。比如“如何实现一个全局状态管理器”、“如何封装一个可复用的拖拽组件”。这类题看似开放其实考察的就是你是否有“分层意识”。我的答题框架是先讲职责划分再讲接口设计最后讲扩展性。以拖拽组件为例第一层是拖动逻辑mousedown、mousemove、mouseup第二层是位置计算的纯函数第三层是对外暴露的 APIoptions、事件回调。这样写完代码清晰、易测试、可复用。笔试的时候写代码前花 30 秒理一下结构比直接上手写要稳得多。设计模式里面“发布订阅”是前端笔试出场率最高的一个。手写一个简单的事件总线是很有价值的练手题因为它的实现非常短但能一次性考察闭包、对象操作、高阶函数三个知识点。建议考前能默写出来。5. 手写代码题与算法实战5.1 高频手写题清单到了笔试后半程就是真正的代码硬功夫展示环节。这部分字面叫“编程题”实际考察的是你在不借助任何工具的情况下能不能写出正确、健壮、可读的代码。我根据自己的经历把前端笔试里出现频率最高的几道手写题整理出来手写防抖debounce和节流throttle手写深拷贝考虑数组、对象、循环引用手写Promise.all或Promise.race手写new操作符的执行过程手写call、apply、bind手写数组去重至少四种思路手写instanceof原理手写一个简单的EventEmitter以深拷贝为例完整版本要处理循环引用。我当时用的方案是WeakMap记录已被拷贝的对象遇到同一对象直接返回已有拷贝既解决循环引用也不会造成内存泄漏。核心代码如下function deepClone(target, map new WeakMap()) { if (typeof target ! object || target null) { return target; } if (map.has(target)) { return map.get(target); } const result Array.isArray(target) ? [] : {}; map.set(target, result); for (const key in target) { result[key] deepClone(target[key], map); } return result; }这里用WeakMap而不是Map是加分点。能解释出“WeakMap 是弱引用不会阻止垃圾回收”这句话说明你不仅会写还懂背后的内存机制。5.2 场景题的答题框架除了纯代码题笔试里还有一类“场景题”比如“如何实现大文件上传”“如何设计一个图片懒加载方案”“如何减少首屏白屏时间”。这类题没有标准答案但阅卷人一眼就能看出你是“有经验地在分析”还是“没思路地在乱写”。我的建议是用“目标-方案-优化”三段式来组织回答。以大文件上传为例目标是把大文件从客户端传到服务端避免在传输过程中超时方案是文件分片前端用File.slice()切分客户端在每个切片上计算 MD5然后逐个上传或并发上传优化则是断点续传、并发控制、进度条展示。这样答出来逻辑完整关键术语也全都在。还有一类是“设计题”比如“请设计一个前端字典管理模块”。这种题目要从使用场景出发字典是全局状态需要在不同页面共享分类管理比如枚举、请求地址、公共选项需要考虑更新和持久化。关键是展现出“我能从需求出发拆解出完整的功能点”而不是一上来就写代码。5.3 算法的准备策略关于算法题我的态度是“战略性放弃难题保底中档题”。前端笔试中的算法难度一般不会超过 LeetCode 中等题而且更偏向字符串处理、数组操作、链表和简单树遍历。动态规划和贪心算法在大厂前端笔试中出场率不高如果真遇到了很多人也会跳过所以没必要在偏题上花太多时间。刷题时要有针对性。优先掌握以下十类题型数组去重、字符串反转、括号匹配、两数之和、数组扁平化、单词反转、排序手写快排/归并、二分查找、链表反转、二叉树层序遍历。这些题目几乎可以覆盖市面上 80% 的前端笔试算法题。我用两个月时间把这些题型刷熟之后再遇到没见过的算法题也能用已有思路去拆解。6. 笔试中的失分点与避坑指南6.1 最容易丢分的低级错误很多人考完觉得自己答得不错结果分数惨不忍睹问题往往出在一些低级细节上。我把这些年在笔试中观察到的高频失分点列出来属于不上考场很难自己发现的那种第一手写代码时没有考虑边界情况。比如循环里对数组进行splice操作忘记索引会变或者arr[i]访问了越界下标。笔试环境不会像 IDE 那样给你报错提示代码一旦跑不过测试用例整个题目得分就会大打折扣。第二代码格式混乱。缩进不整齐、变量命名用a、b、c、没有空行分组这些看起来不是大问题但在阅卷人眼里等于在说“这个人平时代码习惯很差”。笔试的本质是模拟真实开发代码可读性本身也是评分项。第三答案写错位置。有些在线笔试系统要求把代码写在特定区域答完才发现写在了注释里白丢分。虽然听起来很蠢但每年都有人犯。第四审题不清导致答非所问。比如题目问“请说明两种实现方案并比较优劣”你写了三种方案但没有比较也没说各自的适用场景这种答案只能算答了一半。6.2 时间分配与做题顺序笔试的时间一般都比较紧张我那时候的规定动作是先花两分钟浏览全部题目给每一道题标记难易程度。然后按照“先易后难、先短后长”的顺序做题先做选择题和填空题再做手写题最后做算法题。为什么选择题投入时间少、产出确定先拿分能稳住心态。手写题需要集中注意力趁大脑清醒时完成。每道题都设心理时间上限。如果一道题思考超过五分钟还没有思路果断跳过最后有时间再回来补。这里有个细节填空题千万不要留白蒙一个都比空着强编程题即使写不出完整代码也要把解题思路和关键代码片段写上去不少阅卷系统会通过关键词和步骤给过程分。还有一个小建议是要先学会用在线笔试环境。很多同学平时在本地 IDE 里写得很顺畅一上笔试系统连代码高亮都没有、快捷键也不习惯导致效率骤降。我建议提前用牛客网或者其他 vjudge 平台模拟几次在线答题熟悉那种空白的编辑器和严格的时间倒计时。6.3 阅卷人视角什么样的答案才能拿高分这个部分我想从阅卷人的角度跟你聊聊。很多人以为阅卷就是跑测试用例对结果不对就不得分。实际上大多数前端笔试的编程题都是人工加机器结合评判的。机器只能判断几个基础用例是否通过最终的主观分还得靠人工看。人工看代码的时候第一眼是格式是否规范第二眼是答案是否展示了清晰的思路第三眼才是功能是否正确。即使最终代码存在小 bug但你能在注释里写清楚自己的思路、把关键步骤用函数拆分出来阅卷人也会认为“这个人虽然有失误但具备基本的开发素养”。相反代码一团乱麻即使跑通了也很容易被扣分。所以我非常鼓励在笔试代码里加上适当的注释。不需要多每个函数一行说明、关键逻辑一行注释就够了。这一点在阅卷人眼里是“这个人有团队协作意识”的表现。我当年在写防抖函数时顺手加了一句注释“保存上一次定时器ID用于取消”结果面试时面试官专门提到了这句注释。6.4 笔试后的复盘方法论笔试结束不代表事情就完了。我见过很多同学笔试结束后不复盘接着海投下一家公司结果每次都栽在同一类题型上。这个习惯非常亏。笔试其实是免费的模拟测试题目质量很高做完一套卷子的价值远大于盲目刷五道同类题。我建议每次笔试结束后趁记忆还新鲜时立刻写一篇“题目复盘”。不要只记录正确答案要记录自己当时的思路和卡点。我当时用的是 Obsidian 做知识库每种题型一个页面把考场上的分析过程和事后查到的知识点都贴进去。两三个月积累下来到秋招末期这个知识库基本覆盖了前端面试的所有高频考点。还有一个技巧把做错的题目拿去问身边的朋友或者发到社区里。很多时候你以为自己理解的概念在别人一句话的追问下就暴露了漏洞。我当年就是通过跟几个同学反复讨论 Promise 的执行顺序才真正搞懂了微任务队列的细节而那个知识点后来果然又出现在下一家公司的笔试里。写在最后的个人建议回过头来看2022年小米这套前端卷2它并不是用偏题怪题来刁难人而是非常精准地考察了一个前端开发者在日常工作中真正用得到的能力。那些题目里没有一道是“背下来就能得分”的但它们每一个都可以通过扎扎实实做项目、写代码来获得。如果你现在还在准备阶段我的建议是少收藏面经多写代码少看“XX天精通前端”多读官方文档少追求题目数量多总结题型规律。把这些基本功练扎实了不管笔试题目怎么变你都能稳住。