ARTICLE DETAIL

资讯详情

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

小米秋招前端笔试题解析:从JS原理到工程实践

小米秋招前端笔试题解析:从JS原理到工程实践 2022年小米秋招笔试-前端-卷2是我当年准备秋招时印象很深的一套题。先说结论它不玩奇技淫巧也不靠超纲题劝退人但考察面铺得很开从JS基础、框架原理到算法和工程场景都有涉及真正拉开差距的是“你答得够不够快、够不够准”。很多前端应届生在牛客上搜面经往往只会搜到一句“题量超大做到最后手都是抖的”但很少看到有人把考点拆开讲透。这篇就当一份前端面经解析同时也是一张备考地图我会按卷2的实际题型结构把每块考了什么、为什么这么考、应该怎么复习完整过一遍。1. 卷2拿到手第一感受基础题占比远超预期1.1 选择题里的“送命题”与“命门题”这套卷子单选多选加起来大概占了三分之一以上考察范围非常典型变量提升、闭包输出、this指向、事件循环、数组方法返回值、HTTP缓存。你如果平时只写业务代码、不专门刷前端面试八股文这部分会非常难受因为很多题看起来见过但选项里埋着细节。举个例子有一道大概是这样的var a 1; function test() { console.log(a); var a 2; } test();答案是undefined不是1。因为var声明会提升到函数作用域顶部赋值不提升。这种题放在笔试里考的不是你知不知道“变量提升”这四个字而是你是不是真的理解JS的执行上下文。如果你只背了结论没看原理很容易在第二个空踩坑。还有一类数组题特别容易丢分比如const arr [1, 2, 3]; const newArr arr.map(item item 1);很多人第一反应是“返回[false, true, true]”但选项里可能还藏着[1, true, true]这种干扰项。如果你对map的回调返回值理解不深看到箭头函数里用了就以为会返回原值那就错了。这类题考察的就是你在日常编码里有没有真正用过这些高阶函数。1.2 填空题不是死记硬背而是手写推导除了选择题卷2还有不少填空题而且不是让你填一个名词而是填代码输出结果。比如给你一小段异步请求的流程让你写明打印顺序。这种题没有选项可猜会就是会不会就只能空着。我印象最深的一道是async function async1() { console.log(async1 start); await async2(); console.log(async1 end); } async function async2() { console.log(async2); } console.log(script start); setTimeout(() { console.log(setTimeout); }, 0); async1(); new Promise(resolve { console.log(promise); resolve(); }).then(() { console.log(promise then); }); console.log(script end);这道题的输出顺序很多人在浏览器里的第一反应是错的。正确顺序是script start、async1 start、async2、promise、script end、promise then、async1 end、setTimeout。注意await后面的代码相当于Promise.then所以async1 end要排在promise then之后。这里容易错的关键是很多人误以为async/await是同步执行到await之后立刻继续其实不是。我们从这套题能看出小米对“基础是否够硬”非常看重。笔试阶段不筛项目经历不筛学历就看你对JS的底层理解是不是真的到位。这不是刷一个月题就能补起来的而是长期写代码时积累的习惯。2. JS核心考点闭包、原型链与异步每一题都能延伸出三个追问2.1 经典闭包输出题答案和解释卷2里闭包几乎是必考而且考法很直接。有一道题大概是for (var i 0; i 5; i) { setTimeout(() { console.log(i); }, i * 100); }输出是5 5 5 5 5不是0 1 2 3 4。这个大家都知道。但真正的加分点在于第二问会让你改成输出0 1 2 3 4并且要求写出三种方式。我当时写的是用let声明i用IIFE每次传入当前值把setTimeout包在函数里通过参数传值。三种方式背后本质一样让回调函数引用到一个“每次迭代创建新变量”的作用域。如果只是直接写var所有回调共享同一个i所以最终输出5。这种题在面经里常见但到了笔试里往往不只是考你写不写得出答案而是考你有没有理解“闭包保存的是变量引用而不是值”这一层。2.2 手写 new / apply / 防抖怎么答才能拿满分卷2的编程题和简答题里手写实现是大头。我有印象的包括手写new、手写Function.prototype.apply、手写防抖函数。这类题写出来不难但想拿满分要注意细节。手写new的常规解法function myNew(Constructor, ...args) { // 1. 创建空对象原型指向构造函数的 prototype const obj Object.create(Constructor.prototype); // 2. 将构造函数内部的 this 绑定到新对象上并执行 const result Constructor.apply(obj, args); // 3. 如果构造函数返回了对象类型则返回那个对象否则返回新对象 return result ! null (typeof result object || typeof result function) ? result : obj; }很多人会漏掉第三步的判断如果构造函数里return { custom: true }那么new应该返回这个对象而不是你创建的obj。这种细节就是笔试里的区分点平时写业务代码很少碰但面试官就是靠这个筛人的。手写防抖也有进阶要求。基础版function debounce(fn, delay) { let timer null; return function(...args) { if (timer) clearTimeout(timer); timer setTimeout(() { fn.apply(this, args); }, delay); }; }好一点的版本会考虑this绑定、考虑是否需要立即执行还有返回Promise的版本。如果你只写出一个最基础版本能过但如果你能在注释里写清“通过apply保留this指向避免回调内部拿不到上下文”这在阅卷时很加分。2.3 异步执行顺序事件循环的优先级事件循环这道题卷2里不只出现在填空还会在简答题里让你描述macrotask和microtask的区别。这里有个常见误区很多人以为Promise.then和MutationObserver都属于微任务就以为微任务的执行优先级一定高于宏任务但实际上在每一轮事件循环中微任务队列会被清空而宏任务队列只取一个任务执行。所以那道经典题里的setTimeout会被排到最后就是因为在第一轮事件循环的宏任务中遇到setTimeout会把它放进宏任务队列但当前脚本还没结束微任务队列里还有promise then和async1 end要执行。微任务队列清空后主线程才会去宏任务队列里取下一个任务也就是setTimeout。这块如果理解不到位写异步代码时很容易出现顺序错乱尤其在做接口请求串行、依赖前一个请求结果之类的场景时会埋下很深的bug。3. Vue/React框架题小米更看重“原理理解”而非“API背诵”3.1 v-if 与 v-show 的选择不只是显示隐藏框架题在卷2里占比也很高主要围绕Vue偶尔也带一点React。最基础的一道v-if和v-show的区别和适用场景。这题看似简单但答得深入的人不多。v-if是真正的条件渲染不进入条件时不会渲染DOM节点切换时会触发组件销毁和重建v-show是控制CSS的display属性元素始终渲染只是切换显示状态频繁切换时用v-show初始化渲染量大但不会频繁操作DOM运行时条件很少改变、或者需要懒渲染时用v-if。但笔试里有时还会进一步问“为什么不推荐用v-if和v-for同时使用在一个元素上”。在Vue2里v-for的优先级高于v-if这意味着即使某次遍历中绝大多数元素都会被过滤掉v-if仍然会对每个元素执行一次判断。在Vue3里优先级调转了v-if优先但通常仍不推荐这样写更好的做法是外层用template包一层或提前过滤计算好列表。这背后的逻辑是框架不能替你优化所有场景你需要理解指令的底层处理顺序才能写有性能意识的代码。小米考这个还是想筛掉那些只会套模板写页面的人。3.2 组件通信题从父子到全局状态考察层级感组件通信也是高频考点。卷2里有一道问“组件通信方式有哪些”的简答题很常规但拿满分需要你有层级感。我在答题时会把通信场景分成四类父子组件props/$emit也可以用ref直接调用子组件方法兄弟组件事件总线Vue2的$bus或 mitt或者通过父组件中转跨层级组件provide/inject适合深层嵌套但不需要全局管理的场景全局共享Vuex / Pinia适合复杂业务状态。但光列出来不够还要答出“如何选择”。我当时的思路是能用props传递就尽量用props能局部提升状态就局部提升只有确实多个页面共享的数据才引入全局状态管理。笔试里如果能补充一句“事件总线容易造成数据流难以追踪项目里应谨慎使用”会显得你有实战经验而不是只会背API。3.3 手写响应式或虚拟DOM diff不会直接考但原理要会今年的模拟里很多同学觉得小米会考手写defineProperty或Proxy响应式但卷2其实没有要求完整实现而是用一道题让你描述“Vue3的响应式原理”。这道题的标准答题链路是Vue2使用Object.defineProperty只能劫持已有属性新增和删除属性需要额外处理Vue3使用Proxy可以直接代理对象整体能够监听到属性的新增、删除以及数组索引的变化effect作为副作用函数track收集依赖trigger触发更新Reflect.get和Reflect.set配合Proxy确保this指向正确。更进阶的答法是自己在卷子上写一个极简reactive实现function reactive(target) { return new Proxy(target, { get(obj, key) { track(obj, key); return Reflect.get(obj, key); }, set(obj, key, value) { const result Reflect.set(obj, key, value); trigger(obj, key); return result; } }); }这样写虽然不完整但会让阅卷人看到你不只是知道Proxy这个名词而是真的理解依赖收集和触发的机制。框架题最怕的就是“知道概念说不清流程”笔试递进式的追问就是想把这种模糊状态筛出来。4. 算法与手写题不刷题基本寸步难行4.1 两道印象最深的编程题卷2的编程题不多但分值很高。我记得有一道是“数组扁平化并去重排序”这道题算入门级但要处理细节也不容易。我当时的解法const arr [1, [2, [3, [4, 5]], 6], [7, 8], 9]; const flat arr.flat(Infinity); const uniqueSorted [...new Set(flat)].sort((a, b) a - b);其实笔试里可能要求不使用Array.prototype.flat那你就要手写递归function flatten(arr) { return arr.reduce((acc, item) { return acc.concat(Array.isArray(item) ? flatten(item) : item); }, []); }这题不复杂但能看出你有没有掌握递归和reduce的思路。排序时一定要传比较函数否则[1, 11, 2]会变成[1, 11, 2]这是JS默认字典序排序的坑。另一道题是“最长不重复子串”LeetCode 3题。这道题我在卷子上用了双指针加Set的思路function lengthOfLongestSubstring(s) { let left 0, max 0; const set new Set(); for (let right 0; right s.length; right) { while (set.has(s[right])) { set.delete(s[left]); left; } set.add(s[right]); max Math.max(max, right - left 1); } return max; }这类题如果你刷过LeetCode Hot 100基本是送分题。但如果没有系统刷过考试时很难在二十分钟内调试通过。小米的笔试时间比较紧张编程题没法给你太多思考时间所以“刷题手感”真的很重要。4.2 边界条件一错整题白算编程题还有一题是关于链表的我记得是“合并两个有序链表”的变种但增加了“如果是循环链表会怎样”的追问。这个追问其实就是考边界思维如果你没对空链表、长链表、相同节点等情况做校验很容易漏。合并有序链表的迭代解法function mergeTwoLists(l1, l2) { const dummy new ListNode(-1); let prev dummy; while (l1 l2) { if (l1.val l2.val) { prev.next l1; l1 l1.next; } else { prev.next l2; l2 l2.next; } prev prev.next; } prev.next l1 || l2; return dummy.next; }关键点是引入一个dummy头节点否则很容易处理不了空链表。笔试里很多人不是不会写主逻辑而是没校验边界条件比如一个链表为空时直接跑下去导致空指针异常。这类题考的不是智力而是工程习惯。你平时写代码有没有考虑异常分支、有没有用防御式编程都会在这几道题里体现。5. 性能优化与场景设计开放题的“标准答案”藏在你的项目里5.1 从URL输入到页面展示小米考的是CSS和JS的关系卷2有一道经典的开放题在浏览器地址栏输入URL并回车浏览器从加载到渲染发生了什么。这题从小听到大但想答好很难。因为它可以往网络层说可以往浏览器内核说也可以往渲染流程说。我当时从八个阶段答DNS解析域名得到服务器IP与服务器建立TCP连接发HTTP请求收到响应解析HTML构建DOM树解析CSS构建CSSOM树DOM树和CSSOM树合并生成渲染树计算布局确定节点坐标绘制页面合成图层显示。每个阶段其实都可以往下挖。比如“JS的加载会不会阻塞DOM解析”“CSS会不会阻塞渲染”“async/defer有什么区别”。小米在这个题里还配了一小问页面里引用一个大的外部script但放在head底部为什么页面会白屏很久答案是脚本会阻塞DOM解析所以即使CSS已经加载完成页面也不会渲染出来。正确做法是加defer或async或把脚本放到/body前。这题没有标准答案但你可以通过答题展示自己的知识体系是不是完整。如果你能主动提到“老版浏览器会在解析到script时暂停解析因为脚本可能修改DOM”那会留下很扎实的印象。5.2 大文件上传/长列表优化真实业务场景直接搬上来卷2的大题里有一道关于上传的场景题前端如何实现一个大文件上传支持断点续传。这道题相当贴近实际业务也是很多公司前端面试的常见题。我当时拆成了四步文件切片用Blob.prototype.slice把大文件切成固定大小如2MB的分片并发上传通过Promise.all或Promise.allSettled控制并发数量避免一次性塞几百个请求进度计算用已上传分片数除以总分片数前端展示整体进度断点续传先把每个分片的hash发给后端后端记录哪些分片已存在前端只上传缺失的分片。为了让笔试答案更完整我还会补充“使用spark-md5计算文件hash用来做秒传判断”“后端接口要支持分片合并”这两点。这题其实没有唯一答案但是如果你没有做过相关功能很难一口气说出这么多细节。所以我在备考时一直强调简历上写了“大文件上传”就一定要把手写实现从头到尾过一遍笔试不会只问你概念。长列表优化也是在卷2综合题里出现过的渲染1万条数据页面卡顿怎么办最简单的答案是windowed/virtual scrolling只渲染可视区域内的节点。用手写一个虚拟滚动通常不需要全部代码但你要说出几个关键参数scrollTop、viewportHeight、itemHeight、startIndex、endIndex以及为什么不建议一次性渲染所有节点。如果能提到用IntersectionObserver实现懒加载也是一个加分项。这些开放题背后的考察点其实是“你有没有真正的项目经验”。很多同学在面试前专门背了答案但一到实际问题就露馅因为不理解原理换个数字、换个场景就不会了。小米这套卷子很聪明它不高高在上考天马行空的想法而是把工作里最常见的性能优化问题搬到笔试里看你是“背过”还是“做过”。6. 复盘与建议秋招笔试不是考“你会什么”而是考“你答得多快”6.1 时间分配选择题快算法题稳开放题画框架做完卷2最大的感受是时间完全不够用。选择题和填空题一定要控制在四十分钟内解决遇到拿不准的凭第一直觉选不要反复纠结。算法题要留给足够时间调试至少留四十分钟。开放题不要求写完整代码但一定要把思路分条写清楚阅卷人按点给分你连答三个点都比闷头写一段残缺代码强。我当时的优先级是这样的前20分钟快速过选择题不会的标记后跳过中间40分钟编程题先写解题思路注释再实现代码最后30分钟开放题和填空题尽量多写框架和关键函数名剩10分钟回头补标记的选择题检查有没有低级错误。这个节奏不一定适合所有人但至少能避免“算法题没写完、开放题空着”的惨状。笔试最可惜的情况不是不会而是会但没时间写。6.2 八股文和项目经验到底谁更硬这个问题我翻来覆去想了很多遍。从卷2来看“八股文”占了大头但开放题考的都是项目里的真实场景。所以正确的备考策略不是二选一而是把八股文当成底层知识体系的骨架项目经验是血肉。举个例子你如果了解浏览器的渲染机制那么在项目里遇到首屏白屏问题你能下意识想到是不是某段JS阻塞了解析你如果了解事件循环就不会在写上传进度的时候用for循环包裹await导致进度条不走。八股文不是死记硬背它是你做项目决策时的“原理地图”。所以我在秋招复习时每复习一道题就会在脑子里问自己这个知识点我在哪个项目里用到过如果没用到过我就去找一个开源项目上的对应场景逼自己理解而不是背答案。用这种方式备考即使笔试里换一个问法你也能通过底层逻辑推理出答案。6.3 最后几句真心话卷2做完我最大的收获不是“我掌握了某个具体函数”而是确认了一件事大厂前端笔试看重的不是你会多少框架API而是你有没有形成自己的前端知识体系。从基础JS到框架原理从算法到工程优化它们不是孤立的点而是围绕“浏览器怎么运行前端代码”这张网展开的。如果你正在准备2026年的前端面试题建议先把这套卷2的考点当作自测清单闭包、事件循环、手写new、Vue响应式、虚拟滚动、大文件上传逐个过一遍。每个考点至少能做到给别人讲清楚再考虑去刷更冷门的题。希望这份卷2回顾能让你在刷题路上少走一点弯路。把时间花在理解原理上比盲目收集一堆面经有价值得多。
返回列表