校招笔试刷题这件事,我一直觉得比面试更考验“基本功的成色”。面试可以靠表达和项目经验撑场子,但笔试就是白纸黑字,会就是会,不会就是不会。前几天整理电脑,翻出了当年做过的欢聚时代2018校招笔试题-web前端 A卷【成都场】,看着那些题目还挺有感触。今天不打算照着题目念答案,而是借着这套题,聊聊前端校招笔试到底在考什么、怎么准备、有哪些坑是后来人完全可以避开的。
先说下背景。欢聚时代(YY)那几年校招规模不小,成都场的A卷属于前端岗位的通用笔试题,整体难度偏中上,不是那种“背背八股文就能过”的程度,它很看重你对前端基础概念的理解深度,以及对代码细节的敏感度。题型分布大概是选择题、简答题和编程题三块,覆盖了JS基础、浏览器机制、网络协议、CSS布局、框架理解、手写代码这些方面。现在回头看,这套题的出题思路其实很典型,也很有代表性,非常适合用来做校招前端的备考复盘。
1. 内容整体设计与思路拆解
1.1 校招笔试题的定位:不是刁难,是筛选
先说一个很多同学容易误解的点:校招笔试题不是为了把你考倒,而是为了在几千份简历里快速筛出“基础扎实、有潜力、能干活”的人。校招不像社招,社招看的是你做过什么项目、解决过什么问题,校招候选人基本都是白纸,项目经验也多是课程设计或实习打杂,所以笔试只能考基础、考原理、考思维。
正因为这样,欢聚这套A卷的题目设计有个很明显的特点:它不会出那种“偏难怪”的题,但会把常见知识点往深了挖。比如同样考闭包,它不会问你“闭包是什么”,而是给你一段代码,让你说出输出结果,并解释为什么。这种题考的不是记忆,是理解。如果你只是背过“闭包就是函数里面返回函数”这种定义,遇到变量提升、异步执行顺序混合在一起的题,基本就懵了。
另外一个特点是题目之间的关联性很强。选择题里涉及的DOM操作、事件循环、作用域链,会在后面的简答题和编程题里以另一种形式再次出现。这说明出题人希望你不仅知道“是什么”,还能在不同场景里认出“它还是那个东西”。所以备考的时候,别把知识点割裂开背,要尝试建立知识网络。
1.2 题量设置与时间分配的隐藏信息
据我回忆,A卷的时间大概是90到120分钟,题量在30到40道之间,包含选择题、填空题、简答题、编程题。这个题量放在今天来看不算大,但当时很多人觉得时间不够用,原因不是题多,而是“想太久”。选择题里有些题目明显是故意设置了干扰项,如果你对某个概念的理解不够透彻,就会在两个选项之间来回纠结,时间就这么耗掉了。
这里有一个很实用的经验:拿到试卷先花两分钟把整张卷子扫一遍,把编程题先看个大概。因为编程题通常是最后两道,占分最重,如果你前面选择题耗费太多时间,编程题就没时间写了,或者只能草草写个大概,得分很低。我当年就吃过这个亏,前面简答题写得太详细,最后一道编程题差点没写完,最后只能在草稿纸上补了个思路,也不知道阅卷老师给没给分。
所以这种校招笔试,时间分配的优先级应该是:编程题 > 简答题 > 选择题。选择题分值再高也是单个知识点,编程题一道题可能抵得上五六道选择题。先把大分拿到手,再去扣细节。
1.3 成都场的特殊性:城市和岗位的关系
成都场和北上广深的场次有没有区别?从我了解的情况来看,题目核心内容是一致的,但成都场的互联网公司密度和岗位竞争烈度不同。成都当时处于互联网产业上升期,很多大厂在成都设了研发中心,但校招名额相对总部会少一些,所以笔试的筛选标准并不会因为城市而降低,反而因为名额少,面试官对笔试成绩的把控会更严。
这也意味着,如果你是在成都场参加这类笔试,不要抱着“竞争小一点、题目简单一点”的侥幸心理。题目难度和一线城市是同一套标准,甚至因为面试官更看重基础功底,简答题的评分可能更严格。准备的时候不要偷懒,该拿的分一定要稳拿。
2. 核心细节解析与实操要点
2.1 JS基础:闭包、作用域、this是永远的主线
不管哪家公司的前端笔试题,JS基础永远是占比最大的一块,欢聚这套A卷也不例外。JS基础里最常考的有几个点:闭包、作用域链、this指向、原型链、事件循环、变量提升。这几个点单独看都不难,但组合在一起就能出出很多花样。
以闭包为例,笔试里最经典的一种考法是:
for (var i = 0; i < 5; i++) { setTimeout(function() { console.log(i); }, 1000); }这段代码的输出结果是什么?答案是5个5,而不是0、1、2、3、4。如果你能清楚地解释为什么,说明你真的理解了闭包和异步执行的关系。如果你只是背过“循环里用闭包会出问题”,而不知道为什么、怎么解决,那面试官再追问“用let怎么改?用IIFE怎么改?”你就容易卡壳。
这种题目在A卷里出现得很自然,而且它不只是考你输出结果,还会让你写出改进方案。改进方案至少有三种:
- 用
let声明变量,利用块级作用域; - 用 IIFE 包裹,每次循环生成独立作用域;
- 用
bind绑定参数。
每种方案的原理都要能说清楚,因为面试官很可能在笔试之后追问原理。
再说this指向。笔试里常用的考法是通过构造函数的调用方式来考:
function Foo() { this.name = 'bar'; return { name: 'baz' }; } var foo = new Foo(); console.log(foo.name);这里考的是构造函数如果显式返回一个对象,new出来的实例会拿返回值。这个知识点比较细,很多人只记得“构造函数里this指向新对象”,却忘了成员返回对象这个例外。类似这种细节点,就是靠平时刷题积累,临时抱佛脚很难记住。
2.2 浏览器机制与网络协议:不背题,要理解链路
前端er经常被说“不就是写写页面吗”,但校招笔试题就是要打破这个偏见。欢聚A卷里浏览器机制和网络协议的题目占比不低,主要涉及浏览器渲染流程、HTTP缓存、TCP连接、跨域解决方案这些。这类题目背后的逻辑其实是:你写的代码最终是在浏览器里跑的,如果你不知道浏览器怎么工作,很多性能问题和bug你就无从排查。
HTTP缓存是笔试题里的常客。它问的不是简单的“强缓存和协商缓存的区别”,而是给你一个场景:某个静态资源更新了,但用户浏览器里还是旧版本,问你怎么解决。这时候你需要知道Cache-Control和ETag的关系,知道max-age和no-cache的区别,知道为什么很多前端工程化工具会给文件名加hash。理解了这些,你才会明白为什么打包工具要生成app.8f3k2.js这种带hash的文件名。
浏览器渲染流程也经常考,特别是CSS和JS的加载位置对渲染的影响。这类题有个很生活化的类比:浏览器渲染页面就像装修房子。HTML是房屋结构,CSS是刷墙和铺地板,JS是安装家电和智能系统。如果你让家电在墙刷完之前就进场(脚本放在 head 里阻塞渲染),那整个装修流程就乱套了。理解了这层关系,script标签为什么放body底部、为什么用defer和async就都顺理成章了。
2.3 CSS布局:Flex和BFC两手都要硬
CSS布局在笔试题里属于“送分题”,但同时也属于“送命题”。送分是因为它不难,送命是因为很多前端er在平时开发里过度依赖框架和组件库,手写布局能力退化严重。欢聚A卷里CSS布局相关的题一般是两种:一种是给一个需求,让你写出对应的CSS;一种是给一段CSS,让你说出布局结果。
Flex布局基本上是必考的。考法比如“实现一个元素水平垂直居中”,这题有很多种写法,但用Flex是最简洁的:
.parent { display: flex; justify-content: center; align-items: center; }这题不难,但如果你想拿高分,最好写出两三种方案,并对比它们的优缺点。比如 Flex 方案、 Grid 方案、绝对定位 + transform 方案,各自适用的场景是什么。这种对比式的回答,在笔试简答题里会显得你的知识体系很完整,阅卷老师给的分数也会更高。
BFC(块级格式化上下文)也是高频考点。我记得有类似这样的题:父元素高度塌陷了,怎么解决?如果你能说出“创建BFC的几种方式:overflow: hidden、display: flow-root、float、position: absolute”并且解释原理,那么这道题基本就稳了。注意,不要只背方案,BFC的触发条件、BFC对浮动兄弟元素的影响,都应该理解清楚。
2.4 框架题目:不追新,追的是核心原理
欢聚这套A卷出题那年,Vue和React已经开始在前端圈普及,但校招笔试题里不会问“Vue3和Vue2的响应式原理区别”这种过于新潮的问题,而是会考“组件通信方式有哪些”“虚拟DOM是什么”“key的作用是什么”这类核心原理问题。这个思想到现在依然适用:校招笔试不追版本,追的是核心原理。
以key为例,笔试题里经常给一段v-for循环渲染的代码,问添加key和不加key有什么区别。这个问题的本质是考察你对diff算法的理解。key的作用是帮助diff算法判断节点是否复用了,如果不加key,列表的顺序发生变化时,框架可能无法准确判断哪些节点是新增的、哪些是移动的,从而产生错误的状态复用。如果你能把这个场景说清楚,比背一百遍“key是唯一标识”都有用。
另外,组件通信方式也是必考题,包括props/events、事件总线、Vuex/Redux、provide/inject、$refs等等。这种题考察的不是你会不会用某个API,而是你有没有在实践中碰到过“这个数据到底应该放哪个组件”这种问题。建议备考时把每种通信方式的适用场景整理出来,不要只知道写法。
3. 实操过程与核心环节实现
3.1 编程题实战:手写一个防抖和节流函数
编程题里有一类非常经典的“手写题”:防抖和节流。这个题在欢聚A卷里出现完全在意料之中,因为它在实际开发中太常用了。搜索框输入联想、window resize 事件、滚动加载图片,都会用到防抖或节流。笔试考这个,既能考察基础编码能力,又能考察你是否理解实际场景。
防抖的本质是:事件触发后,等待一段时间,如果这段时间内没有再次触发,才执行函数。如果期间再次触发,就重新计时。用生活类比就是电梯关门:电梯门快要关的时候,有人进来了,门就重新开,等人进完了再关。
防抖的经典实现:
function debounce(fn, delay) { let timer = null; return function(...args) { if (timer) clearTimeout(timer); timer = setTimeout(() => { fn.apply(this, args); }, delay); }; }有几个细节要注意:一是要保存this指向,因为事件处理函数里的this是有实际意义的;二是要透传参数;三是返回的函数要保持原函数的签名,这样在移除事件监听的时候才能对应得上。
节流的本质是:在一段时间内,不管触发多少次,只执行一次。生活类比就是地铁安检:不管同时来多少人,安检机传送带的运转速度是固定的,漏不过去也超不了速。
节流的经典实现:
function throttle(fn, interval) { let last = 0; return function(...args) { const now = Date.now(); if (now - last >= interval) { last = now; fn.apply(this, args); } }; }这个实现是时间戳版本,第一次触发会立即执行,因为last初始是0,now - last肯定大于interval。如果想让第一次不立即执行,可以用定时器版本:
function throttle(fn, interval) { let timer = null; return function(...args) { if (timer) return; timer = setTimeout(() => { fn.apply(this, args); timer = null; }, interval); }; }建议备考时把两种写法都写熟练,笔试时再根据题目要求选择。
3.2 编程题实战:手写深拷贝,别只写JSON.parse
手写深拷贝也是当年笔试题的常客,现在依然很常见。这题看起来简单,但想拿满分不容易。很多人第一反应是:
const newObj = JSON.parse(JSON.stringify(obj));这个写法在笔试里能拿一部分分,但如果你就这么交上去,那基本和满分无缘了。因为面试官马上会追问:JSON.stringify会丢失什么?答案是:函数、undefined、Symbol、RegExp、Date等特殊类型会被处理掉或丢失。一个真正可用的深拷贝函数,需要考虑这些边界情况。
下面是一个可以在笔试里直接用的深拷贝实现:
function deepClone(obj, map = new WeakMap()) { if (obj === null || typeof obj !== 'object') { return obj; } if (obj instanceof Date) { return new Date(obj); } if (obj instanceof RegExp) { return new RegExp(obj); } if (map.has(obj)) { return map.get(obj); } const result = Array.isArray(obj) ? [] : {}; map.set(obj, result); for (let key of Object.keys(obj)) { result[key] = deepClone(obj[key], map); } return result; }注意这里用了一个WeakMap来记录已经拷贝过的对象,这是为了处理循环引用的问题。什么是循环引用?就是a.self = a这种。如果没有WeakMap做缓存,深拷贝会陷入无限递归,直接栈溢出。
这个细节在笔试里属于加分项,写上去会让阅卷老师觉得你的工程经验很扎实。备考的时候建议把这段代码练熟,同时理解每一行的作用,因为面试官大概率会顺着这道题问“为什么用WeakMap不用Map”。
3.3 简答题实战:如何描述一个知识点才算高分
简答题是很多人容易忽略的拿分点。它不要求你写代码,但很考验你“能不能把一件事说清楚”。举个例子,题目如果是“谈谈你对CSS中BFC的理解”,你以为只要写出“BFC是块级格式化上下文”就完了?太天真了。一个高分的回答应该包含四个层次:
第一层,是什么。BFC是块级格式化上下文,是页面盒模型布局中的一种CSS渲染模式,它决定了元素如何对其内容进行定位,以及和其他元素的关系和相互作用。
第二层,怎么触发。触发BFC的条件包括:根元素、float不为none、position为absolute或fixed、display为inline-block、table-cell、flow-root等、overflow不为visible。
第三层,解决什么问题。常见应用场景是:解决浮动元素造成的父元素高度塌陷、防止垂直margin合并、实现自适应两栏布局。
第四层,用代码或例子佐证。简单写一段DEMO,说明塌陷问题和解决后的效果。
如果你能按这个层次来回答,阅卷老师一眼就能看出你的知识是成体系的,而不是零散记忆。记住一个原则:笔试简答题的评分标准不是“有没有提到关键词”,而是“知识体系是否完整”。
3.4 网络题实战:从URL输入到页面展示,这道题怎么答才出彩
“在浏览器地址栏输入URL并回车,到页面展示出来,中间发生了什么?”这几乎是一道必考题,欢聚A卷里大概率也有。这个题的难度在于,它考察的知识跨度极大,从网络协议到浏览器渲染全都要覆盖。很多人备考时背答案,但如果你理解了每一层在干什么,就能写得比别人更有逻辑。
一个比较完整的回答链路是这样的:输入URL后,浏览器先解析URL,判断是搜索关键词还是合法网址;然后浏览器查找缓存,看这个域名有没有缓存过DNS解析结果;如果没有,就发起DNS解析请求,把域名解析成IP;拿到IP后,浏览器与服务器建立TCP连接,这个过程中涉及三次握手;如果协议是HTTPS,还要进行TLS握手,协商加密密钥;建立连接后,浏览器发送HTTP请求;服务器处理请求,返回HTTP响应,包括状态码、响应头和响应体;浏览器收到响应后,开始解析HTML、CSS、JS,构建DOM树和CSSOM树,然后合并成渲染树,进行布局和绘制;最后,页面呈现在用户眼前。
这只是主干,如果你想拿高分,还有一些细节可以补充。比如,在解析HTML时遇到<script>标签,会阻塞DOM解析;遇到<img>标签,会异步加载图片;在绘制阶段,如果JS修改了样式,可能会触发回流(reflow)和重绘(repaint),影响性能。
答题的时候建议分层展示,先讲网络层,再讲渲染层,最后讲优化点。这样既能体现广度,也能体现深度。
4. 常见问题与排查技巧实录
4.1 选择题纠结半天,最后还选错怎么办
这是最常见的问题。我当年做选择题,最怕的就是那种“以下说法错误的是”和“以下哪些选项会导致xxx”的题。这种题会设置多个迷惑选项,如果你对知识点的记忆是模糊的,很容易选错。
我的经验是:先排除绝对正确的选项,再排除语法上就不对或明显违背常识的选项,最后在自己纠结的两个选项里,选择那个“描述得更保守”的。因为出题人往往会把错误选项描述得过于绝对,比如“一定会”“必须”“所有”这类词出现时,要格外小心。相反,正确选项里经常会有“可能”“通常”“在某些情况下”这类限定词。
这个方法不是百分百准确,但它能帮你把正确率从50%提升到70%左右,在时间不够的时候很管用。
4.2 编程题写不出来,怎么“骗”过程分
笔试阅卷和考试阅卷一样,是按点给分的。如果你编程题只写了个开头,后面不会了,不要在原地发呆,把你会的部分全都写上去。比如,看到题目要求手写防抖函数,你至少要把函数的声明写出来,把参数写上,把timer变量定义写上,能写多少写多少。这样阅卷老师至少知道你审题了、知道基本语法,不会给你零分。
还有一个小技巧是写注释。假设你不会写具体的逻辑,但你把思路写成了中文注释,比如“定义一个计时器变量”“如果已有计时器则清除并重新计时”,阅卷老师能看出你有思路,只是代码能力还没跟上。这在笔试中确实能拿到一定的过程分。不要小看这些分数,笔试过不过线,往往就差这么几分。
4.3 时间不够用,先放弃哪些题
校招笔试的时间通常是紧巴巴的,你需要有取舍。我的建议是:选择题和填空题如果一道题卡了超过两分钟,先跳过,在题号上做个标记,后面有时间再回来。简答题写要点就行,不要长篇大论,每个要点两三句话讲清楚,不用展开太多。编程题一定要留足时间,至少要保证写出一版能运行的个人能编译通过的版本,哪怕有bug也比空白强。
另外,编程题如果第一道不会,可以先看第二道。有时候第一道卡住你的知识点,第二道反而简单,先把能拿的分都拿到,回头再啃硬骨头。
4.4 准备期应该刷什么题才有效
很多同学备考时喜欢刷各种大厂题库,这个方向没错,但要注意方法。刷题不是背题,而是通过题目检验自己对知识点的理解程度。我建议按照“知识点-例题-变体”的方式来刷。比如今天集中刷闭包的题,把各种闭包的考题都看一遍,再自己改一改条件,看看输出结果会不会变化。如果变了,说明你只记住了答案,没理解原理;如果没变,但你能说清为什么没变,才说明真的懂了。
推荐去翻一翻牛客网上的题库,那里有很多公司校招的回忆版题目,覆盖面很广。但注意,这些回忆版不一定准确,部分题目的选项和原题有差异,不要太依赖原题,重点是掌握题背后考察的知识点。
5. 笔试之后:从“做题”思维切换到“工程”思维
5.1 笔试只是门槛,面试才是决胜局
说句实话,校招笔试成绩只要过线,面试官并不会太在意你考了90分还是75分。笔试真正的价值是帮你拿到面试资格。所以笔试题里暴露出来的薄弱点,一定要在面试前补上,因为面试官手里通常拿着你的笔试答卷,他会在面试时专门追问你答错的题。
如果你笔试里有一道BFC的题答得不好,面试前一定要把BFC重新搞明白,并且准备一个实际开发中使用BFC的例子。这样当面试官问“你笔试里BFC答得不太好,现在再聊聊你对它的理解”时,你能从容应对,反而会把劣势变成加分项。
所以笔试结束后,不要对答案、不要纠结分数,赶紧把每一道题考察的知识点记录下来,逐项复习。
5.2 笔试暴露的知识盲区,就是你接下来的学习方向
当年笔试结束,我把自己答错的题整理了一遍,发现主要集中在HTTP缓存和事件循环这两块。这两个知识点很多日常开发中也会用到,但之前从没有系统地梳理过。于是笔试后的两周里,我集中看了很多相关文章,画了很多脑图,把每个知识点都串成了链路。
这个方法很笨,但从结果来看非常有效。笔试的题目质量比市面上很多练习题的都高,它帮你指出了真正该学的东西。如果你只把笔试当成一个门槛,考完就忘,那你浪费了最好的学习素材。
5.3 关于校招前端岗位的一点个人看法
现在前端领域的竞争越来越激烈,校招笔试的内容也在不断变化。几年前考的是jQuery、BFC、闭包,现在可能还会考TypeScript、工程化、性能优化。但无论如何变化,核心的东西没变:你对基础知识的理解深度、你排查问题的思路、你写代码的规范性和可维护性。这些能力在笔试里都能体现出来。
我觉得准备校招笔试题,不要抱着“考完就结束”的心态。它其实是一次很好的自我体检,让你在正式进入职场之前,清楚地知道自己哪里会、哪里不会。把这个心态摆正了,刷题的过程就不会那么痛苦,反而会觉得每天都在变强。
如果你现在正在准备校招,或者打算转行做前端,我建议你找几套像这样的往年笔试题,老老实实做一遍,然后再针对错题去补知识。这个过程坚持一个月,效果绝对比你看半年视频课要好。笔试考的是输出能力,而输出能力只能靠输出训练来提升。