
前两天整理电脑资料翻到了一沓2020年校招季存的笔记其中一份就是小红书前端校招的笔试题卷三。当时很多同学被这张卷子问住考完出来直呼“前端怎么还能这么考”。后来我带实习生、做面试官的时候也经常拿这套题改吧改吧当模拟卷用因为它的考点覆盖和出题思路放在今天来看依然很有参考价值。这篇文章不是单纯把题贴出来而是我当时做完之后一道一道复盘过的版本题型分布、考点解析、踩坑点、最优解思路以及备考时该往哪个方向使劲。适合正在准备前端校招的应届生也适合刚入行想补基本功的前端新人。不管你是照着刷题还是想了解大厂笔试都考什么这份复盘都能帮上忙。1. 这份卷子考什么题型、时长和出题逻辑先说整体体感。卷三的题量中等偏上一共十六道题左右答题时间60分钟分成了单选、多选、手写编程题和简答题四块。前面十道左右是选择题穿插两道左右的手写题最后两三道是偏问答和设计类的。很多第一次参加校招笔试的同学容易犯一个认知错误以为前端笔试就是考背概念。实际上这卷子里几乎没有“直接背能拿分”的题目所有选择题都给了代码片段让你推结果。这说明出题人真正想考察的不是“你知不知道”而是“你想不想得清楚”。同样一个知识点背定义只能拿基础分能写出运行结果、说出为什么才是他们筛选人的标准。从考点分布来看卷三覆盖得比较均衡考察方向大致题数占比感觉HTML/CSS基础3-4题20%左右JavaScript核心类型、作用域、闭包、事件循环5-6题35%左右手写代码防抖节流、深拷贝等2题左右20%左右框架/工程化/网络React、webpack、HTTP缓存3-4题25%左右这套比例和大多数中大厂校招笔试题是接近的核心权重在JavaScript和手写代码上。CSS也考但不会考什么特别炫酷的布局奇技淫巧而是真正常用的、写页面一定会遇到的东西。所以备考阶段如果你时间有限先把JS啃透再回头补CSS细节优先级会高很多。60分钟的时长拆到十六道题上平均每题只有3-4分钟。这意味着前面选择填空如果卡太久后面的手写题会非常被动。我后面会专门聊时间分配的问题这里先提醒一句校招笔试不是“每道题都要完美答完”而是“在有限时间内拿到最大总分”。2. 基础考点逐题拆解HTML/CSS/JS易错题详解2.1 HTML语义化标签的坑section和article到底怎么选第一道选择题问的是语义化标签的用法给了四个选项中关于section、article、div使用场景的判断题。我猜不少人会在这道题上犹豫。section和article都是HTML5用来表示“一块内容区域”的标签很多同学背了定义但一落到具体场景就分不清。这里有我后来整理出的判定方法article表示的是一个独立完整的、可单独分发或复用的内容单元比如一篇帖子、一条评论、一个产品卡片section表示的是一个有主题的内容分组它通常自带一个标题h1-h6。如果一块内容拆开之后本身没有意义、只是单纯为了样式方便包一层那就用div。当时有不少人误以为“section里必须有article”或者“article里不能套section”这俩都是错的。正确的嵌套逻辑是article之间可以并列article内部可以有多个section来描述不同部分section内部也可以再套section。一道选择题考到这个深度其实是在提醒你标签不是记住了名字就行而是要看它对应的语义模型。2.2 Flex布局居中方案三行代码的边界情况选择题里有一道问“如何让一个不定宽高的子元素在父容器中水平垂直居中”选项给了几个Flex写法。这道题按说很基础但错误率意外地高主要出在对align-items属性的记忆混淆上。水平居中用的是justify-content: center垂直居中用的是align-items: center这俩是主轴和交叉轴的关系。父容器加了display: flex之后默认主轴是水平方向所以justify-content控制的是左右方向的分布align-items控制的是垂直方向的分布。我见过有同学把这两个写反还说“明明没问题”。如果有这种困惑试着把flex-direction改成column主轴就变成垂直方向两个属性的效果也交换了。这么在脑子里过一遍就不容易再混。这道题的结论很简单给父容器加display: flex、align-items: center、justify-content: center子元素不管宽高是定值还是由内容撑开都能居中。核心是理解主轴概念而不是背那三行代码。2.3 CSS选择器优先级为什么写了一大堆类名还是覆盖不了CSS优先级这道题我印象很深给了一个嵌套了好几层类名的HTML结构然后要求判断最终文字颜色。选项里故意放了好几种看似“写得越多越有效”的迷惑项。优先级规则说穿了就一句话权值相加。!important 行内样式1000 id选择器100 类/属性/伪类10 标签/伪元素1 通配符0。两个选择器作用在同一元素上时谁的权值大听谁的权值相同后面的覆盖前面的。但这道题的陷阱不在这里而在于很多人把“选择器写得更具体”和“选择器数量更多”混为一谈。比如.container .item .text这种三个类名相加的权值是30而#app .text的权值是110后者虽然只写了两个选择器但优先级反超。我当时就在旁边备注了一句“面试爱考的不是你会不会数权值而是你会不会处理嵌套关系”想表达的核心是写CSS的时候尽量不要靠堆选择器来解决优先级问题而是在命名层面就用BEM这类规范解决问题这是工程化的基本功。2.4 类型转换[] ![] 到底是不是true这张卷子的第一道JS选择题绝对是全卷最劝退的题之一。它问的是[] ![]的结果是多少。很多同学看到[]和![]就懵了。实际推理过程并不复杂![]的优先级高于所以先算![]。空数组也是个对象转布尔是true取反后是false。原式就变成了 [] false。等式两边有一个是布尔值按规则先把false转成数字0等式变成 [] 0。然后对象和数字比较把[]转成原始值先试valueOf返回的还是空数组不是原始值再调toString得到空字符串等式变成 0。然后字符串再转成数字空字符串转成0最后0 0是true。整个链条走完要经过四步转化每步都不能漏。这是典型的“JavaScript隐式类型转换”考点也是笔试出题人最喜欢拿来制造区分度的题。想在这类题上不丢分没捷径把ToPrimitive和ToNumber的规则整理一张表再找二三十道类似的题目练到能默写推导过程基本就稳了。2.5 作用域和闭包经典计数器背后是执行上下文的销毁与保留有一道填空题给了这样的代码for (var i 0; i 5; i) { setTimeout(function() { console.log(i); }, 100); }问输出什么以及怎么改才能输出0、1、2、3、4。输出全部是5这个结论大部分同学能答对。但第二问的改法就各显神通了。最简单的就是把var改成let让每一轮循环都生成独立的块级作用域绑定。另一个思路是包一层立即执行函数把i显式传进去。这道题背后真正考察的是闭包的本质内部函数引用了外部变量当外部函数执行结束、执行上下文销毁时被引用的变量不会跟着销毁而是被内部函数的引用捕获。用let和用IIFE两种方案都能解决但出题人其实更期待你顺手讲出它们各自的原理差异let是语言层面新语义IIFE是模拟块级作用域的经典做法。笔试时直接写答案就好面试如果追问能说清这层区别会加分不少。2.6 事件循环与输出顺序宏任务、微任务的执行时机事件循环是前端笔试的高频题卷三里自然也没落下。给了一段混有Promise、setTimeout的代码要求写出输出顺序。这类题我就说一个最重要的心得先画两个队列一个是宏任务队列一个是微任务队列。每执行完一个宏任务就把当前微任务队列里所有任务全部清空然后再从宏任务队列里取下一个。代码从头到尾按顺序推演一遍推完再对照答案比死记硬背结论靠谱得多。有个细节值得单独说Promise构造函数里的代码是同步执行的resolve之后回调进的是微任务队列。很多人一看到Promise就默认“都是异步的”结果把构造函数那部分的同步输出顺序搞错了一道题直接白给。我当时复盘时在旁边写了句话提醒自己同步代码、微任务、宏任务三种级别顺序永远是从上到下先同步再微任务再宏任务每次宏任务结束后都要再检查一次微任务队列。这题丢分不是不会而是把同步和异步的判断搞混了。3. 手写题怎么拿分防抖、深拷贝和现场思路3.1 防抖和节流别光背代码说清楚适用场景卷三的手写题第一道是“手写一个防抖函数”。这道题乍一看很基础但拿满分并不容易。我当时的写法是function debounce(fn, wait) { let timer null; return function(...args) { if (timer) clearTimeout(timer); timer setTimeout(() { fn.apply(this, args); }, wait); }; }这里最容易被忽略的有两个点。第一个是this的绑定如果不用箭头函数直接写setTimeout(function() { fn.apply(this, args) })this就会丢失用箭头函数可以保证回调里的this就是外层return的那个函数的this也就是调用方。第二个是args的透传得把事件对象e传给fn不然防抖出来的函数监听器里拿不到事件对象。如果能顺手提一句防抖和节流的区别这道题会显得更完整。防抖是“停止触发后才执行”适合搜索框输入、窗口resize这种操作节流是“固定时间内最多执行一次”适合滚动监听、按钮频率限制。在笔试题旁边用一行注释写清楚适用场景面试官看到的就不只是一段代码而是工程判断能力。3.2 深拷贝循环引用这个坎当场拦住多少人卷三另一道手写题是深拷贝。如果只要求基础版很多人能写出来function deepClone(obj) { if (obj null || typeof obj ! object) return obj; const result Array.isArray(obj) ? [] : {}; for (let key in obj) { result[key] deepClone(obj[key]); } return result; }但这道题后面还附了一问对象里存在循环引用怎么办。比如a.self a如果直接用上面这个递归版本会无限递归最终栈溢出。我当时用的解法是加一个缓存容器WeakMap每次拷贝前先检查缓存里有没有这个对象有就直接返回之前拷贝的结果没有就存进去再递归。这样一个循环引用对象只会被处理一次后续引用直接复用。后来这道题在面试环节也经常被翻出来追问还会继续问到Date、RegExp、Symbol这类特殊类型要怎么处理所以如果笔试时间宽裕尽量把基础版写完再写一点特殊类型判断比最后留一个半成品要好。3.3 手写题的现场策略先保正确再补优雅手写题是整个笔试最考验心态的部分。很多人一看到代码题就紧张担心写得不够优雅担心变量命名不好看结果越写越乱。我的建议是手写题按“正确优先、结构其次、优雅最后”的顺序推进。先写出一个能跑通的版本哪怕是一层浅拷贝加递归先保证主流程正确然后再补循环引用、补特殊类型顺手把解构、展开这些语法用上有富余时间再优化代码风格和注释。笔试是按点给分的代码跑通比代码优雅值钱得多。如果写不出完美版也要把思路用注释写下来比如“这里用WeakMap存储已拷贝对象防止循环引用”不会完整写出来但让评分人看到你的思路也能挽回不少分。4. 框架与网络题从会用到会答为什么4.1 setState到底是同步还是异步场景决定答案卷三有一道React相关的题问setState之后能不能立刻拿到最新的state值。答案是在React合成事件和生命周期函数里是异步的在setTimeout、原生事件监听器里是同步的。这个题坑就坑在“非黑即白”。很多同学背了一句“setState是异步的”就去答题结果忽略了React18之前不同调用场景的表现并不完全一致。我当时做这道题的时候不只在选项上纠结还在旁边把原因捋了一遍setState之所以设计成异步是为了把同一事件循环里的多次更新合并成一次重新渲染减少不必要的渲染开销。到了下一轮面试这道题还会升级成“React18自动批处理有什么变化”所以在笔试复盘时把React从15到18的更新机制变化整理一遍性价比很高。至少你要知道React18之后即使是在setTimeout、Promise回调里setState也会被自动批处理只有在需要强制同步读取最新状态时才用flushSync之类的方案。4.2 虚拟DOM的key为什么不能用index卷三的问答题里有一道关于key的“列表渲染时为什么key不建议用index”。这道题看起来简单但很多人回答停留在“如果用index删除某个元素后后面的元素会错位”。其实这只是表象。真正本质的原因是key的作用是让React能识别每个列表项的身份在diff过程中判断哪些元素是新增、删除、还是只改了位置。如果拿index当key当数组头部被插入或删除了一个元素后面所有元素的index都变了React会认为它们是不同的元素于是把整列节点都卸载重建这既浪费性能也可能导致有状态子组件状态错乱。我在面试里追问过候选人“错乱的具体场景是什么”能答出“输入框在移动位置后内容被清空”的基本就说明他是真遇到过类似问题。如果你现在刷题刷到这里建议自己写个简单demo试一遍点按钮从数组头部插入一条看看带输入框的列表项表现一跑便知。4.3 HTTP缓存强缓存和协商缓存谁先谁后不能反网络题在卷三里占了两道左右其中一道是HTTP缓存机制的填空强缓存、协商缓存、ETag、If-None-Match之间的关系。我见过的最大误区是把强缓存和协商缓存当成两个平级概念觉得“强缓存不行就走协商缓存”顺序倒是没错但没说明白判断标准。完整的过程是浏览器发请求时先查强缓存如果命中了且没过期直接用本地缓存不发请求如果过期了就带上协商缓存的标识If-None-Match对应ETagIf-Modified-Since对应Last-Modified去问服务器服务器根据标识判断资源有没有变化没变化就返回304浏览器重定向到本地缓存有变化就返回200和新资源。这道题的答题关键是把“过期”和“变化”两个词分开。强缓存关心的是“有没有过期”协商缓存关心的是“有没有变化”。这两个维度完全不同理清之后再背Cache-Control和Expires的区别、ETag和Last-Modified的优先级就会顺很多。4.4 跨域问题CORS预检请求到底怎么触发关于跨域卷三有一道选择题给了一个POST请求场景问什么时候会触发CORS的预检请求。选项有“请求带自定义header”“请求Content-Type是application/x-www-form-urlencoded”“请求用GET方法”等等。按CORS规则满足下面任一条件就会触发预检请求方法不是GET/HEAD/POST请求方法是POST但Content-Type不是表单三种之一比如application/json请求带了自定义header这是简单请求和复杂请求的分界点核心判断标准是“会不会对服务端数据产生副作用”。这道题很多同学失误在选项设置上。Content-Type是application/x-www-form-urlencoded和multipart/form-data都不触发预检一旦变成application/json就要预检。我当时在试卷上把这个点单独圈出来因为这是日常开发最常踩的坑前后端联调前端把请求体格式换成了JSON突然多出一个OPTIONS请求后端没处理直接报错。这种情况在工作里太常见了笔试考这个不是没事找事是真实开发场景的映射。5. 时间分配复盘笔试现场我是怎么取舍的笔试做完后我复盘了这次答题的时间分配发现顺序对分数的影响非常大。我的实际时间分配是这样的题型用时我的策略选择题前5题HTML/CSS/JS基础12分钟快速扫题能确定的直接选模棱两可的先标记不恋战选择题后5题事件循环、React等15分钟稍微放慢在草稿纸上推演代码输出手写题防抖、深拷贝20分钟先写能跑通的基础版再写进阶点简答题和设计题10分钟按要点分条写写满但不啰嗦检查复核3-5分钟只检查标记过的题目和手写题有没有低级语法错误这里想多说一句标记不确认的题这个习惯很关键。很多人做选择题遇到不确定的靠直觉选完就走后面根本不会再回来想。我的做法是一眼能确定的直接选有点模糊的在旁边画个问号完全不会的先填一个最可能的然后继续往下走。等简单题都拿完了再回头啃不确定的题。这样能保证“会的题不因为时间不够而丢分”。时间分配还能顺带检验一个东西你对某个知识点的熟练度。如果一道题你一眼就知道考什么并且能在30秒内算出来说明这个点你掌握到位了如果一道题你反复读了三遍还没抓住考点大概率不是题目难而是这个知识点本身没学透。复盘的时候把这些“没学透”的点全部标记出来一条一条查漏补缺比盲目刷五十套题都管用。6. 备考提醒常见误区与刷题路线建议6.1 盲目刷面试题和八股文不如做题后认真复盘一套真题我到今天都记得一个数据2020年很多同学备考前端校招刷了小几百道面试题背了一堆结论结果做这套小红书卷三时选择题还是错了一半。原因很简单面试题背的是“某道题的答案”而笔试考的是“知识点的推导过程”。你把结论背得再熟出题人换个代码片段条件一变你就废了。我建议的刷题方式是拿到一套真题先不看答案做一遍做完后花同样的时间逐题复盘。复盘内容很具体这道题考察的是什么知识点我是怎么得出答案的要是换个条件还能不能应对我写错的题错在哪个步骤。把复盘写到自己的错题本里比刷题本身更重要。错题本是拿来反复翻的不是写完就扔的。我在带教的时候就一直和新人强调会做一道题不厉害能把同类题讲明白才算真会。6.2 动手写demo和只刷题差距有多大有一个让我印象特别深的例子。当时我和一个同学一起准备笔试他刷了三百多道题我看他每天刷得也很认真。但有一次我拿同一个React key相关的问题去问他他忽然卡住了因为他从来没在真实浏览器里跑过那些代码片段。纸面刷题有一个致命短板你永远是在“代码运行之前”判断结果而不会看到代码运行之后到底发生了什么。前端这个领域是离运行时最近的工程领域浏览器、网络、渲染都是真实存在的。很多问题你在浏览器里跑一遍效果瞬间直观比背十道题都管用。所以我一直建议准备校招的同学每周至少花一天时间把这一周刷题里涉及到的代码片段在本地起一个最小demo跑一遍。防抖就写个输入框看效果深拷贝就打印一下循环引用对象会不会报错HTTP缓存就开DevTools看Network面板里的状态码。只看纸面的话很多东西你永远理解不到位。6.3 简历上写“精通”笔试却翻车问题出在哪经常在笔试复盘群里看到一些同学说“我简历上写了熟悉React和webpack结果笔试考的webpack我完全不会。”简历和笔试对不上是2020年校招季很常见的现象近几年也依然存在。问题背后其实是技能分层意识不够。简历上写“熟悉”和“了解”标准完全不一样。熟悉意味着你能独立解决这个方向的问题笔试里出现的相关题目必须能做对了解意味着你知道有这个方案给你时间查资料能解决笔试里遇到不会也很正常。不少同学把两者混着写结果面试官按最高标准去考你自然翻车。我当时给自己定了一个标准简历上的每一项技术至少要能回答出“它解决了什么问题、核心技术思路是什么、我实际用过哪个场景、有什么坑”这四个问题。用这个标准过一遍简历再决定哪些写“熟悉”哪些写“了解”笔试和面试都会踏实得多。6.4 一套知识点查漏补缺清单结合小红书卷三和我后来经历的校招真题我整理了一份前端校招笔试的高频知识点检查清单大家备考时可以对着自查HTML语义化标签、块级元素和行内元素的区别Flex和Grid布局主轴和交叉轴常用居中方案CSS优先级计算BFC/IFC概念JS数据类型、隐式类型转换、深浅拷贝作用域、闭包、this指向、原型链事件循环、宏任务微任务防抖节流、手写Promise、手写数组方法浏览器渲染过程、重排重绘HTTP缓存、跨域、HTTPS握手React/Vue生命周期、setState、diff、key、Hooks打包工具webpack基本配置和构建优化这份清单不是背一遍就行而是要求每一条都能“讲出原理写出代码说明应用场景”。能做到这个程度前端笔试基本就稳了。写在最后的一次复盘这张卷子做完给我最大的触动不是哪道题特别难而是它让我意识到校招笔试筛选的从来不只是知识的储备量而是你在有限时间内调用知识解决问题的能力。一道选择题背后是对原理的理解一道手写题考验的是对代码的掌控力和临场心态。我后来在带新人的时候也经常建议大家不要只囤面经、刷题集最好把做过的每一套真题都做一次深度复盘把错题背后的知识点一一补齐。这比泛泛地刷几十套题更有用。前端这个行业变化很快工具链一两年就换一批但底层的JavaScript、浏览器原理、工程思维这些东西是穿越周期的硬通货。希望这篇复盘能帮你在准备校招的路上少走一点弯路。