2019年春招那阵子,我前前后后折腾了差不多两个月,最后拿到了字节跳动、网易、美团三家的前端offer。这篇面经一直想写,但总想着再沉淀一下、再复盘一下,结果就拖到了现在。当时准备面试的时候,我把网上能找到的2019春招前端面经几乎翻了个遍,一边看一边整理自己的知识盲区,说实话帮助很大。所以现在轮到自己了,也想把这些东西如实记录下来,给准备走前端这条路的朋友做个参照。
这不是一篇只罗列面试题的流水账。我会把每一轮的考察逻辑、我当时怎么答的、事后复盘哪里没答好、以及三家公司风格上的差异都聊一遍。如果你正在准备前端面试,或者打算在接下来几个月投简历,这篇内容应该能帮你把准备重心放对。
1. 春节前后的准备阶段
在开始聊面试题之前,先把准备阶段的事情说清楚。我的原则是:面经是查漏补缺用的,不是临时抱佛脚用的。所以春节前我花了大概三周把知识体系过了一遍,春节后才开始集中刷题和投简历。
1.1 核心知识板块怎么梳理
我身边有不少朋友准备面试的时候容易慌,今天看框架、明天看算法、后天又觉得CSS不太行,结果哪块都没吃透。我的做法是先列一个知识地图,把前端面试会涉及的板块全部列出来,然后逐个击破。
以我当时的划分,主要分成了这几块:
- JavaScript语言基础:原型链、闭包、作用域、this指向、事件循环、ES6+新特性
- 浏览器和网络:渲染原理、回流重绘、HTTP缓存、HTTPS握手、跨域方案
- CSS和布局:盒模型、flex、grid、BFC、居中方案、响应式
- 框架:Vue的响应式原理、vdom和diff、生命周期;React的fiber、hooks、setState机制
- 工程化:webpack打包流程、loader和plugin区别、代码分割、性能优化
- 算法和数据结构:数组/字符串操作、链表、二叉树、排序、动态规划入门
- 项目复盘:简历上每个项目都能讲清楚技术选型、难点、优化指标
这个清单看着挺多,但每一块其实都有对应的经典问题。我当时是给自己定了个目标,每个板块至少要能脱稿讲出三个核心知识点,并且能现场手写一段代码,不然不算过关。
1.2 简历和项目准备的坑
简历这件事,我踩过一个大坑。最初我把自己参与过的所有项目都写上去了,觉得项目多显得厉害,结果面试官一深挖就问穿了。后来我把简历精简到两个项目,一个偏重业务、一个偏重技术深度,每个项目都提前准备了如下问题:
- 这个项目解决的核心问题是什么,为什么要用你选的那个方案?
- 你在里面负责哪些模块,最有技术含量的部分是哪里?
- 有没有做过性能优化,具体数据是多少?
- 如果重新做一遍,哪里会改成什么方案?
这些问题如果没有提前想清楚,面试现场很容易卡壳。尤其第二个问题,面试官几乎是必问的。我记得我在准备项目复盘的时候,把自己写过的代码重新翻了一遍,把一些当时模糊的决策点全部想明白了,后来面试时被问到项目细节基本都能接住。
1.3 刷题策略和时间安排
刷题这件事,我的策略是"先分类、再限时、最后复盘"。分类的意思是不要今天刷一道链表、明天刷一道动态规划,而是按专题集中刷,比如这一周全是二叉树,下一周全是动态规划,这样知识迁移效率高。
我给自己定的节奏是工作日每天保证2小时:1小时算法题 + 1小时基础知识背诵和手写。周末半天做一次完整的模拟面试,自己给自己出题,然后对着镜子讲或者录音下来听。这个方法挺推荐的,因为很多知识点你觉得会了,但真让你口头表达出来,你会发现说话逻辑是乱的。
基础知识的背诵不是死记硬背,而是要把每个知识点背后的"为什么"想清楚。比如事件循环,你不能只背"微任务先于宏任务",你得理解为什么要有微任务、哪些api会进入微任务、浏览器和Node的事件循环有什么区别。面试官只要顺着你的回答追问两三句,你是真懂还是背的,立马就能试出来。
2. 字节跳动:四轮面试全记录
字节跳动是我春招面的第一家,也是整体流程最长、考察最全面的一家。我投的是北京的前端岗位,从一面到offer大概用了两周时间,中间每轮面试间隔大概2-3天。整体感觉是:字节非常看重基础功底和代码能力,问题不绕弯子,上来就是硬核问题。
2.1 面试流程回顾
字节的流程是一共四轮,前三轮是技术面,最后一轮是HR面。
一面主要聊基础,JavaScript、CSS、网络都会涉及,中间穿插手写代码。面试官让我做自我介绍的时候,我就简单说了一下学校、实习经历和主要技术栈,大概一分钟左右。然后他就开始问问题了。
二面会深挖项目和框架原理,同时会有一道中等难度的算法题。这一轮明显感觉到面试官更关注你思考问题的过程,而不是答案本身。
三面是综合面,除了技术问题之外,还会问一些开放性的场景设计题,比如"如果让你从零设计一个前端监控系统,你会怎么设计",考察的是你的知识广度和系统设计能力。
HR面就相对轻松了,聊的主要是职业规划、为什么选择字节、对加班的看法、目前的offer情况之类的问题。
2.2 高频题目深度解析
我按记忆把字节面试中比较有代表性的题目列出来,然后说下我当时是怎么答的,以及哪些地方值得注意。
第一道是手写Promise.all。这道题我建议所有准备前端面试的人都应该重点准备。Promise.all的核心逻辑是接收一个promise数组,返回一个新的promise,所有promise都成功则返回结果数组,任何一个失败则reject。我在实现的时候先用一个计数器记录已完成的数量,然后用一个数组按顺序存结果。这里有个细节要注意:结果数组的顺序要和传入的promise顺序一致,不能因为哪个先resolve就放在前面。我当时把这个点讲出来了,面试官明显比较认可。
第二道是事件循环相关的题。面试官给了一段代码,问输出顺序。大概是:
console.log('script start') setTimeout(() => { console.log('setTimeout') }, 0) Promise.resolve().then(() => { console.log('promise1') }).then(() => { console.log('promise2') }) console.log('script end')输出顺序是:script start、script end、promise1、promise2、setTimeout。这道题我答得比较快,因为准备的时候专门把微任务和宏任务的执行顺序捋过一遍。这里要特别注意,Promise的then回调属于微任务,会在当前宏任务结束前执行,而setTimeout属于宏任务,要等本轮所有微任务执行完之后才会执行。
第三道是算法题,反转链表。这道题有两个解法,迭代和递归,我建议两个都掌握。我当时先讲了思路,说用三个指针pre、cur、next来迭代处理,然后把代码写出来了。面试官又追问了递归写法,我也写了一遍。这类经典题的要点是:先说自己用什么方法、时间复杂度是多少,再动手写,这样显得思路清晰。
2.3 字节面试避坑心得
字节的面试强度和节奏是真的快,一面就可能直接上算法题,而且手写代码的时候面试官会盯着你写。我总结了几个心得:
手写代码之前一定先讲思路。哪怕思路很简单,也要说清楚,既能让面试官知道你在想什么,也能给自己理清逻辑。最怕的是闷头就写,写到一半发现思路错了,那就很难圆回来了。
遇到不会的题,千万不要直接说"不会"。我当时的做法是,先把自己能想到的切入点说出来,哪怕这些点不一定对。比如问我一个没接触过的api,我就说"这个api我不太熟悉,但根据命名,我猜它大概是做什么用的,我平时处理类似需求的时候会用xxx方案"。面试官一般不会因为你不会一道题就否定你,反而会看你面对未知问题时有没有解决思路。
字节的算法题难度整体是中等偏上的,如果平时没有刷题习惯会吃大亏。我建议至少把leetcode上链表、二叉树、字符串处理、动态规划入门这四类题刷够50道再去。刷题真的没有捷径,唯手熟尔。不过也不要盲目追求数量,每道题做完之后要总结思路,下次遇到类似的能反应过来才行。
3. 网易:面试最温和但也最抠细节
网易这边体验很好,整体流程走下来,给人的感觉是面试官非常耐心,不太会打断你说话,问的问题也比较体系化。网易的面试只有两面技术面加一轮HR面,效率挺高的。
3.1 面试流程回顾
网易一面是远程视频面的,面试官先问了一些项目相关的问题,然后沿着我提到的技术点往下深挖。比如我在项目里提到了做过首屏加载优化,他就顺着问"你是怎么定位性能瓶颈的""用了哪些手段""效果怎么样",每个问题都问得很细。
二面更偏向原理,Vue响应式原理、虚拟DOM、diff算法都有涉及。还问了一些工程化相关的问题,比如webpack打包流程、如何做项目构建优化。
HR面主要聊了期望薪资、base地点偏好、手上的其他offer情况,以及有没有考研的打算。整体氛围比较轻松。
3.2 高频题目深度解析
网易面试比较有代表性的题目第一个是Vue响应式原理。我在2019年那阵子Vue 2.x还是主流,所以这道题的标准回答是围绕Object.defineProperty展开的:数据被observe之后,每个属性都有一个Dep依赖收集器,组件渲染时会把对应的Watcher收集进来,数据更新时触发setter,Dep通知所有Watcher去更新。这里我额外提了一句Object.defineProperty无法监听新增属性,所以Vue 2提供了Vue.set来解决这个问题,面试官觉得这个点提到位了。
第二个是HTTP缓存机制。这道题值得把每一个细节都搞清楚。强缓存是通过Expires和Cache-Control实现的,Expires是HTTP/1.0的东西,有客户端时间不准的问题,所以HTTP/1.1引入了Cache-Control,用max-age来做相对时间。协商缓存有两种验证方式:一种是Last-Modified配合If-Modified-Since,另一种是ETag配合If-None-Match。我当时把这些对比着讲了一遍,还说了为什么有了Last-Modified还要有ETag,因为Last-Modified最小粒度是秒,同一秒内多次修改文件是没法感知的。
第三个是实现深拷贝。这道题我踩过坑,所以多说一句。很多人在面试时写深拷贝就直接用JSON.parse(JSON.stringify()),但面试官一定会追问:这个方法有什么问题?当时就问了,我说它没法处理undefined、函数、Symbol,而且循环引用会直接报错。然后面试官让我写一个能处理循环引用的深拷贝。我的思路是用WeakMap记录已经拷贝过的对象,如果碰到相同的引用就直接返回复制过的对象。这样既能解决循环引用的问题,也可以复用已经拷贝的对象。
3.3 网易面试避坑心得
网易的面试官很喜欢顺着你的回答一路追问,所以你在回答每个问题之前,要想清楚自己说的每句话会不会被追问。这个很考验对知识掌握的完整度。我建议在准备阶段,每复习一个知识点,都要自己问自己"如果我是面试官,我会顺着这个知识点追问什么",然后把可能的追问问题也准备一遍。
另外,网易面试明显对项目的完整度要求比较高。我建议简历上每个项目都要有明确的"背景-方案-数据"结构。背景是为什么要做这件事,方案是你的技术选型和具体实现,数据是做完之后的效果,比如页面加载时间从多少降到多少、线上问题减少了多少。数据不需要多华丽,但一定要真实,因为面试官真的会追问数据是怎么测出来的。
4. 美团:三轮面下来最看工程落地
美团这边同样也是三轮技术面加一轮HR面。整体感觉是美团的面试官非常务实,问题基本都是围绕真实业务场景展开的,不太喜欢问八股文式的概念题,更看重你能不能解决实际问题。
4.1 面试流程回顾
美团一面也是先过基础,但和字节不一样,美团的基础题更多是穿插在场景里问的。比如它不会直接问"跨域有哪些方案",而是问"如果你们项目前后端分离,接口跨域了你会怎么处理",需要你结合实际场景来回答。
二面偏向工程化,问了很多webpack配置和优化相关的问题,还让设计一个前端通用组件库的架构方案。
三面是leader面,聊得比较深,包含系统设计题、团队协作经验、遇到技术难题时的处理方式等。
4.2 高频题目深度解析
美团让我印象最深的一道题是:如何设计一个前端通用组件库。这道题开放性很强,考察的是你的架构能力。我当时从四个层面来回答:组件层、样式层、工具层、文档和示例代码。组件层要明确组件之间的层级关系和通信方式;样式层要考虑主题定制能力,我提了CSS变量和BEM命名规范;工具层包含表单校验、请求封装等公共能力;文档层要支持组件展示、API说明和在线调试。回答完这些之后,面试官又追问了组件库的版本发布策略和兼容性处理,我就说了用semver语义化版本、按需加载要考虑babel-plugin-import这种方案。
第二个是webpack构建优化。美团比较关注优化,所以我答的时候专门提了三个方向:一是通过happyPack或thread-loader开启多线程构建,把耗时的loader处理并行化;二是用DllPlugin把不常变动的第三方库预先打包,从而减少二次构建时间;三是合理配置splitChunks做代码分割,把公共模块单独抽出来,避免重复打包、减少首屏加载JS体积。另外我还提了一句,优化之前一定要先做构建耗时分析,用speed-measure-webpack-plugin定位真正的瓶颈,不要盲目优化。
第三个是ES6模块和CommonJS的区别。这道题看起来基础,但美团问得挺细。我说CommonJS是运行时加载,因为require是在代码执行到那一步才去加载模块的;ES Module是编译时加载,import语句会被提升到文件顶部,所以可以做静态分析和tree shaking。此外ES Module的export是引用拷贝,而CommonJS的module.exports是值拷贝。最后还提了一句,ES Module是严格模式下运行的,所以顶层this是undefined,而CommonJS环境下模块顶层的this指向module.exports。
4.3 美团面试避坑心得
美团的场景题比重很大,所以你在准备的时候不能只背概念,还要能把概念落到真实场景里。我建议平时多留个心眼,想想自己做过的项目里哪些地方用到了某个技术点,如果面试官问起来,能不能用自己项目的例子来说明白。比如你简历里写了用webpack做过构建优化,那就要把当时的配置项、优化前后的时间对比都准备好。
另外美团对工程化这块的考察比另外两家更细。如果你对webpack还停留在会配脚手架的阶段,建议把webpack的核心概念系统过一遍:入口、输出、loader、plugin、devServer、source map、tree shaking、scope hoisting这些都要能说清楚。特别是loader和plugin的区别要弄清楚,loader是让webpack能处理非JS文件,plugin则是用来扩展webpack自身功能,两者定位完全不同。
5. 三家公司横向对比与复盘
三家公司面完之后,我花了很长时间做复盘。面试是一个双向选择的过程,不仅是公司在评估你,你也要通过面试过程判断这家公司适不适合自己。
5.1 面试风格与考察侧重点对比
我把三家的差异整理成了一个表格,方便对照看:
| 公司 | 考察侧重点 | 算法题难度 | 项目追问深度 | 流程节奏 |
|---|---|---|---|---|
| 字节跳动 | 基础功底、代码能力 | 中等偏上 | 中等 | 快,四面两周走完 |
| 网易 | 原理理解、项目完整度 | 中等 | 深,逐层追问 | 适中,两面+HR |
| 美团 | 场景设计、工程落地 | 中等 | 中等偏上 | 稳,三轮+HR |
字节推荐算法基础扎实、喜欢硬核题目的候选人;网易更适合能沉下心把原理讲透、项目细节扎实的人;美团则偏爱有工程sense、能解决实际问题的工程师。这些特点没有高下之分,关键看你自己是什么类型的选手。
5.2 常见问题速查与避坑清单
根据整个春招周期里我自己和身边同学的面试情况,我整理了一个高频问题速查表,大家准备的时候可以对照着自查:
| 分类 | 常见问题 | 回答要点 |
|---|---|---|
| JS基础 | 手写new、bind、call/apply | 注意new要创建新对象、修改原型、绑定this |
| JS基础 | 事件循环输出顺序题 | 先宏任务再微任务的细粒度逻辑 |
| 框架 | Vue父子组件生命周期顺序 | 父created、子created、子mounted、父mounted |
| 框架 | React setState同步还是异步 | 合成事件中是异步,原生事件和定时器里是同步 |
| 网络 | 输入URL到页面渲染全过程 | 从DNS、TCP、HTTP到渲染树,分阶段说 |
| 网络 | HTTPS握手过程 | 证书验证、密钥交换、加密通信三步 |
| CSS | 水平垂直居中方案 | 至少说出flex、position+transform、grid三种 |
| 工程化 | webpack构建流程 | 从入口解析依赖图、loader处理、plugin介入、输出 |
| 性能 | 首屏加载优化方案 | 代码分割、路由懒加载、图片压缩、资源预加载 |
5.3 关于心态、谈offer和选择的个人建议
面试过程中心态起伏是很正常的。我记得面字节三面之前,我一度紧张得睡不着,因为前面每一轮都聊得不错,反而怕最后搞砸。后来我想明白了一个道理:面试就是一次技术交流,对面坐的面试官也是从你这个阶段过来的,答不上来不丢人,不懂装懂才丢人。抱着这种心态之后,后面几场面试反而越聊越放松。
关于offer选择,我自己的经验是不要只盯着薪资。我当时对比了三家的技术栈、业务方向、团队氛围和地理位置,最后选了最适合自己职业规划的那家。薪资固然重要,但第一份工作更关键的是能不能让你在技术上快速增长,有没有靠谱的导师带你,业务是不是有足够的成长空间。这些因素你可以在面试过程中去感受,也可以在HR面的时候直接问清楚。
聊聊这套准备方法能不能复用
现在回头再看2019年春招这段经历,我个人最大的感受是:面试准备的本质不是背题,而是搭建一个完整的知识网络。你会发现很多题目表面上看是独立的,但实际上都指向同一个底层能力,比如手写Promise是在考察你对异步流程的控制能力,事件循环输出题考察的是你对JS运行时机制的理解,HTTP缓存则是在考察你对浏览器资源加载过程的认识。这些能力是相通的。
所以如果你想复现这套方法,我建议不要只盯着题库刷,而是先花时间把我在第一节列的知识地图过一遍,确保每个板块都能讲出核心原理,然后再结合面经去验证自己的掌握程度。面经的价值在于告诉你某家公司喜欢考什么方向的题,让你有的放矢地补强,但如果你本身基础不牢,看再多面经也是空中楼阁。
最后再分享一个小技巧:每次面试结束后,当天晚上就把所有能回忆起来的题目记录下来,然后逐题标注自己答得好不好、缺漏在哪里。这个复盘习惯坚持下来,你会发现第二场面试比第一场明显更稳。我整个春招大概整理了四十多道题目,每一道都写了解题思路和当时的回答版本,这才是这套面经整理下来最值钱的东西。