ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

哔哩哔哩2023前端校招笔试题解析:核心考点与实战准备

哔哩哔哩2023前端校招笔试题解析:核心考点与实战准备 1. 这份笔试卷到底在考什么说句实在话前端校招笔试圈里各家大厂的出题风格差异真的很大。有的喜欢考偏门API有的喜欢堆算法题有的干脆上来就是一套工程场景题。而哔哩哔哩2023校园招聘前端开发方向笔试卷A整体出题思路还是比较典型的“大厂规范风”——既不炫技也不偏门核心就一句话考察你到底有没有真正写过前端而不只是看过前端教程。为什么这么说因为这份卷子里的很多题目表面上看是在考知识点实际上是在考“你在真实项目里踩过坑没有”。比如事件循环的输出顺序、Promise的链式调用、HTTP缓存的命中条件这些内容如果你只是背过八股文很可能在选择题里能蒙对一两道但一旦遇到“给一段代码写出运行结果”或者“让你设计一个方案”这类题型就非常容易暴露出理解深度不够的问题。和B站的业务场景结合起来看就更清楚了。B站的前端业务覆盖了视频播放页、直播互动、弹幕系统、动态信息流、个人中心、创作中心等大量高并发、强交互的复杂场景。视频播放页要处理播放器状态同步、弹幕渲染性能、清晰度切换逻辑直播业务要面对WebSocket消息推送、礼物动画、实时聊天动态流要处理无限滚动、虚拟列表、图片懒加载。这些业务场景决定了B站前端团队对候选人的要求不是看你会不会调接口而是看你能不能把一个页面的性能优化到极致能不能在复杂交互下保证状态管理的清晰能不能对浏览器原理有足够深的理解来排查线上问题。笔试就是这道门槛。卷子A的整体难度对标的是“有一定的项目经验并且对前端基础知识有体系化理解”的候选人。如果你只是刷过一两百道LeetCode但没怎么真正写过完整的项目这份卷子做起来会有些吃力。反过来如果认认真真写过两三个项目并且对项目里的性能优化、组件设计、工程化配置有过深入思考那这套卷子其实是一个很好的“知识体检”。对我个人而言看这种校招笔试卷其实特别有意思因为透过题目能感受到出题团队想要什么样的人。这份卷子给我的感觉是B站前端团队很看重基础、看重实战、而且希望候选人是一个“自己能排查问题”的人而不是一个“等别人给答案”的人。2. 前端校招笔试题的四大核心考点拆解把哔哩哔哩2023校园招聘前端开发方向笔试卷A做一次整体拆解之后我发现核心考点基本集中在四个方面。这四个方面几乎是所有大厂前端校招的“必修课”但每家的侧重点和考察深度略有不同。下面我逐一展开说。2.1 JavaScript语言基础不只是背语法要能“运行时推演”JavaScript是前端的地基这份卷子在语言基础部分花了不少笔墨而且考察方式非常灵活。除了常规的变量提升、作用域链、闭包、原型链这些经典考点之外更值得注意的是对“运行时行为”的考察——比如setTimeout、Promise、async/await混合场景下的执行顺序这类题目不是死记硬背能解决的需要你在脑子里真的能“跑一遍代码”。我见过很多候选人问“什么是闭包”能背得滚瓜烂熟但给你一段实际代码让他说输出结果反而说不清楚。这就是典型的“知识点记忆”和“运行时理解”之间的差距。B站的笔试题特别看重后者本质上是因为实际开发中你天天都在跟异步打交道——接口请求、定时器、事件监听、动画帧回调如果你对事件循环没有直觉性的理解排查问题的时候会非常痛苦。还有一个容易忽略的点是this绑定规则。这个知识点在笔试题里通常不会单独出一道“什么是this”而是放到一个对象方法调用的场景里混着箭头函数和普通函数来考。这里有个提醒普通函数的this取决于调用方式箭头函数的this取决于定义位置这个区别如果没吃透遇到嵌套函数里的this指向问题特别容易翻车。2.2 浏览器与网络原理知道“发生了什么”还不够要懂“为什么”这一块是前端校招笔试的“分水岭”。很多候选人在JavaScript部分能拿高分但一到浏览器渲染原理、HTTP缓存、跨域方案这些内容就露馅了。B站作为视频和直播平台对网络层面的要求相当高——视频加载策略、流媒体传输优化、弱网环境下的降级方案这些都需要对HTTP和浏览器机制有深入理解。我印象中这类考点通常包括从输入URL到页面展示的完整过程每一步发生了什么HTTP缓存中强缓存与协商缓存的区别特别是Cache-Control和ETag的配合逻辑跨域问题的成因与常见解决方案比如CORS、JSONP、代理转发浏览器渲染流程特别是回流和重绘的触发条件与性能影响资源加载优先级与defer、async的差异以HTTP缓存为例笔试题不会只问你“强缓存和协商缓存有什么区别”更可能会给一个实际场景某个JS文件更新了版本但用户浏览器还是加载的旧文件让你分析原因并给出解决方案。这种题目就是在考察你有没有真的处理过线上缓存问题而不是仅仅看过缓存机制的博客。2.3 框架与工程化Vue和React至少有一个能“深入底层”在框架考察部分B站显然对齐了自身的业务技术栈。从招聘JD和笔试内容来看Vue和React都有涉及但整体趋势是不考“API怎么用”考“API为什么这么设计”以及“底层怎么实现”。这就意味着你不能停留在“会用v-if和v-for”的阶段而是要去理解响应式原理、虚拟DOM、diff算法、组件通信机制等底层逻辑。一个非常典型的考察方向是Vue的响应式原理。初级考法会问你“Vue2和Vue3的响应式实现有什么区别”高级考法则是让你读一段代码分析某个数据修改之后视图会不会更新以及为什么。比如通过索引直接修改数组元素在Vue2中不会触发视图更新但同样的操作在Vue3中就可以。如果你不理解Object.defineProperty和Proxy的本质差异这种题目基本只能靠蒙。工程化方面的考察则更偏向实际应用能力。比如Webpack的构建流程、Loader和Plugin的区别、Tree Shaking的工作原理、代码分割的配置方式等。有些题目还会给出一段webpack配置让你指出其中的问题或优化空间。这类题目对“只写过Vite脚手架项目”的候选人来说有一定难度因为Vite的配置太简单了很多底层细节都被封装掉了你必须真正看过Webpack的配置文件、手动配过打包过程才能对这些概念有具体认知。2.4 算法与数据结构不卷难题但“够用”需要什么水平算法部分可能是很多前端候选人最头疼的。B站2023校招前端卷A的算法题难度整体上属于“中等偏基础”没有那种让人无从下手的ACM风格的难题更偏向于“在业务场景中能用到的基础算法和数据结构”。常见的考察方向包括数组与字符串处理、链表操作、栈与队列的应用以及一道需要综合运用哈希表的题目。这里我多说一句前端岗位的算法考察目的不是招一个算法竞赛选手而是考察候选人的逻辑思维能力和代码实现能力。实际前端开发中你确实不太会天天手写红黑树但你一定会遇到需要处理嵌套数据结构、需要去重排序、需要高效查找的场景。所以算法题的本质是面试官想看看你在面对一个具体问题时能不能快速想出思路并用干净的代码实现出来。对于算法准备我的看法是不需要死磕难题但简单和中等难度的题目要达到“秒杀”的水平。因为笔试时间有限如果一道简单的数组题你都要想十分钟才能动手写那后面的题肯定做不完。你需要把常见题型和基础数据结构的操作练到肌肉记忆的程度这样才能在笔试中从容不迫。3. 典型真题解析与解题思路还原接下来我结合常见的校招笔试模式挑几类高频考点还原一下解题思路和代码写法。这里不保证是卷子A的原始题目但考点和题型高度一致算是给准备参加校招的同学一个参考方向。3.1 事件循环与异步输出顺序题这道题几乎是前端笔试的“必考题”B站卷A果然也考了。这类题目的核心是考察你对事件循环机制、宏任务与微任务的理解。一道典型题目如下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解题思路可以这样拆解首先明确JavaScript是单线程的代码按顺序执行。遇到setTimeout它会把回调注册为宏任务放到任务队列里不会立即执行。遇到Promise.then它会把回调注册为微任务。当前宏任务也就是这段主代码执行完毕之后会优先清空微任务队列然后再取下一个宏任务执行。所以promise1和promise2会排在setTimeout之前。笔试中这道题的进阶版本通常是添加async/await例如async function test() { console.log(async start) await Promise.resolve() console.log(async end) } console.log(outer start) test() console.log(outer end)这里有个关键点await后面的代码会被放到微任务队列中执行。所以正确的输出顺序是outer start、async start、outer end、async end。很多候选人第一次做的时候会误以为await会阻塞后面的代码导致把outer end和async end的顺序搞反。给一个实操建议平时用的浏览器DevTools里其实有事件循环的可视化工具比如Performance面板录制一段代码的执行过程能非常直观地看到宏任务和微任务的调度顺序。我用这个方法给不少新人讲过事件循环理解速度比光看文档快得多。3.2 手写防抖与节流防抖和节流是前端笔试的“常青树”而且在真实业务中确实非常常用。B站笔试卷A里也出现了这类题但没有只要求“写出来”而是进一步要求说明两者的区别和适用场景。防抖的实现思路是在事件被连续触发时只有当最后一次触发后等待一段时间没有再次触发才执行目标函数。典型实现代码如下function debounce(fn, delay 300) { let timer null return function (...args) { if (timer) clearTimeout(timer) timer setTimeout(() { fn.apply(this, args) }, delay) } }节流的实现思路则不同在一段时间内无论事件触发多少次目标函数最多只执行一次。常见实现有两种方式——时间戳方式和定时器方式。时间戳方式的优点是立即执行缺点是停止触发后不会再执行定时器方式的优点是停止触发后会再执行一次缺点是第一次触发不会立即执行。最稳妥的方案是两者结合function throttle(fn, interval 300) { let lastTime 0 let timer null return function (...args) { const now Date.now() const remain interval - (now - lastTime) if (remain 0) { if (timer) { clearTimeout(timer) timer null } fn.apply(this, args) lastTime now } else if (!timer) { timer setTimeout(() { fn.apply(this, args) lastTime Date.now() timer null }, remain) } } }笔试中除了写代码还要能说清楚适用场景。防抖适合搜索输入框的自动补全、窗口resize结束后再重新计算等场景节流适合滚动事件中要做懒加载或滚动位置监听等高频触发场景。B站的弹幕发送频率控制也可以用节流来做——防止用户在短时间内连续发送多条弹幕刷屏。3.3 深拷贝的手写实现深拷贝也是前端笔试的高频题很少有不考的。这道题的难点不在于“递归复制对象”而在于处理各种边界情况数组与对象的区分、循环引用、特殊类型Date、RegExp、Map、Set、Symbol属性等。一个相对完整的版本是function deepClone(target, map new WeakMap()) { if (target null || typeof target ! object) return target if (map.has(target)) return map.get(target) const type Object.prototype.toString.call(target) if (type [object Date]) return new Date(target) if (type [object RegExp]) return new RegExp(target) if (type [object Map]) { const result new Map() map.set(target, result) target.forEach((value, key) result.set(key, deepClone(value, map))) return result } if (type [object Set]) { const result new Set() map.set(target, result) target.forEach(value result.add(deepClone(value, map))) return result } const result Array.isArray(target) ? [] : {} map.set(target, result) Reflect.ownKeys(target).forEach(key { result[key] deepClone(target[key], map) }) return result }这里有个非常重要的隐蔽知识点为什么用WeakMap而不是普通的Map来存储循环引用因为WeakMap的键是弱引用不会阻止垃圾回收机制清除那些已经“不再需要”的对象。如果用Map当原对象被置空之后Map里仍然持有引用会导致内存泄漏。这个细节如果在笔试的答案解析里看到了一定不要忽略——它就是考官想考察的“深入程度”所在。3.4 数组API的手写实现map、filter、reduce数组API的手写实现是笔试卷中出现频率极高的一类题。原因很简单它能综合考察你对函数式编程的理解、对回调函数的掌握以及代码的简洁度。其中reduce的考点最密集。比如用reduce实现数组扁平化是一道经典题目const arr [1, [2, 3], [4, [5, 6]]] function flatDeep(arr, depth 1) { return arr.reduce((result, item) { if (Array.isArray(item) depth 0) { result.push(...flatDeep(item, depth - 1)) } else { result.push(item) } return result }, []) } console.log(flatDeep(arr, Infinity))这类题的考察重点不只是“能不能写出来”还包括你对边界条件的处理能力比如深度参数的控制、空数组处理、非数组元素等。说白了面试官就是要看你有没有工程思维能不能想到那些“极端情况”。3.5 HTTP缓存方案设计题这是一道更贴近业务的题目。题目大致是这样的你负责的视频网站播放页上的一个推荐列表接口数据需要缓存请问你会如何设计缓存方案要求考虑到用户刷新页面时的体验、接口数据更新的及时性以及服务端资源的消耗。这道题没有标准答案但需要你展示的知识结构是完整的首先要区分强制缓存和协商缓存说明你选择的缓存策略其次要给出具体的响应头设置建议比如Cache-Control的max-age值、ETag或Last-Modified的配合方式最后要结合业务场景讨论动态接口的缓存粒度以及如何在前端层面做数据的二次缓存我给出的思路是对于推荐列表这种“实时性要求不高、数据量中等”的接口可以设置Cache-Control: max-age60让浏览器在60秒内直接使用本地缓存。超过60秒后浏览器会带上协商缓存的请求头If-None-Match或If-Modified-Since去服务端验证如果数据没有变化服务端返回304状态码浏览器继续使用本地缓存如果数据有变化服务端返回200和最新数据。这样既减少了请求体量也保证了数据不会过期太久。这道题其实考察的是你有没有真正思考过“页面如何更快加载”的问题。B站的视频页里推荐列表、热门榜单这种辅助信息的接口完全可以采取这种方式来提升二次访问速度把宽带资源留给真正重要的视频流数据。4. 刷题之外的实战准备建议笔试虽然考的是知识但准备方式不能只靠刷题。我给准备校招的同学的建议是以“做项目”为主线以“刷题”为辅线两条腿走路。4.1 从一个完整项目开始建立知识地图没有项目经验的同学最好花四到六周认真做一个小型项目。注意这里的“认真”不是把网上的教程代码抄一遍而是从头到尾自己设计、开发、上线。比如做一个极简版的视频弹幕网站就比做一百道笔试题更有价值。在这个项目里你自然会遇到并解决这些问题如何设计组件层级与状态管理对应框架与工程化考点如何处理异步数据加载和竞态条件对应JavaScript基础考点如何优化首屏渲染性能对应浏览器原理考点如何配置打包工具对应工程化考点项目做完之后你对知识点的理解深度会完全不同。很多人刷题时背“防抖和节流”的区别背得滚瓜烂熟但当自己在项目里真的实现一个“搜索框输入防抖”时才会深刻理解为什么需要这个函数、为什么this的绑定方式这么重要、为什么要用apply来传递参数。4.2 用“三遍法”刷前端核心题库如果时间有限我推荐的刷题方法是“三遍法”。第一遍按知识点分类刷不求速度但要求把每道题的知识盲区都搞清楚比如考察的是原型链、事件循环还是CSS布局第二遍打乱顺序限时刷模拟笔试的紧张感每道题控制在十分钟以内第三遍只看错题和难题并且在白纸上手写代码不依赖编辑器的自动补全功能。特别强调“手写代码”这个点。很多候选人在IDE里写代码写得飞快但一到笔试的在线编辑器里就各种拼写错误、括号不匹配。这是因为平时太依赖编辑器的智能提示了。建议从准备笔试的第一天起就有意识地练习在无补全情况下写代码这对笔试和面试的手写代码环节都有很大帮助。4.3 吃透一个框架的源码级原理框架方面的准备我的观点很明确Vue和React不必都精通但至少要有一个做到“源码级理解”。不是要你把源码全背下来而是核心机制必须说清楚。以Vue 3为例至少要能回答清楚这几个问题Vue 3的响应式是如何通过Proxy实现的和Vue 2的Object.defineProperty相比解决了哪些问题虚拟DOM是什么为什么需要它diff算法的基本流程是怎样的computed和watch的区别本质是什么各自的实现原理是什么Vue组件的更新流程是怎样的从数据变化到DOM更新之间发生了什么为了做到这一点我建议去读Vue 3的源码——不需要全部读完但reactivity模块和runtime-core模块中的核心文件一定要精读几遍。这个过程确实比较费力但对于通过笔试和后续的面试收益是非常大的。4.4 做一次全真模拟笔试很多同学忽略了这个步骤直接上场考试结果在时间分配、心态调整上吃了大亏。建议在正式笔试前至少做一到两次全真模拟找一个安静的时段设定和真实考试相同的时间限制用在线编辑器答题按照真实的题目类型和数量来模拟。做完之后认真复盘重点关注哪类题目耗时最长是算法题还是框架题有没有出现“会做但没时间做”的情况代码在无智能提示条件下有没有出现低级错误时间分配是否合理是先做简单题还是先做分值高的题模拟完之后就能根据自己的实际情况调整答题策略。以我个人经验来说比较推荐的答题顺序是先快速浏览全部题目判断难易程度然后先做简单题和中等题最后死磕难题。这样能保证基础分不丢同时把时间用在最有可能拿到的分数上。5. 我在面试官角度看到的高频丢分点最后这个部分我想换一个视角从“阅卷人”或“面试官”的角度来聊聊一份笔试卷交上来最让人可惜的丢分点是什么。新人在准备时如果能避开这几个坑至少能挽回10%到15%的分数。5.1 基础概念不扎实关键词满天飞但答不到点上笔试中常见的情况是候选人能写出“闭包就是函数里面返回函数”这样的描述但解释不清楚闭包的作用和典型应用场景能写出“事件冒泡”这个词但说不完整捕获和冒泡的完整流程以及如何阻止。这种“名词党”在阅卷时特别容易被识别出来因为答案里全是术语却缺少逻辑链条。解决方案很简单在准备每一个知识点时都用“是什么—为什么—怎么用”三段式来检验自己是否真正理解。如果任何一个部分说不清楚就说明这个知识点还没有完全掌握需要回头再学。5.2 代码风格和规范不规范笔试的代码题评判标准通常不只看“能不能跑通”还包括代码风格、可读性和健壮性。我见过不少候选人代码逻辑是对的但细节处理很粗糙变量命名是a、b、c没有处理边界条件和空值判断函数体超过四十行没有拆分没有任何注释。在真实工程中这样的代码是会被Code Review打回去的所以笔试中它自然也是减分项。改善建议平时写代码时就养成良好习惯变量名要能表达语义函数尽量保持单一职责关键逻辑补充必要的注释每个函数都考虑一下入参为null或undefined时会发生什么。5.3 算法题的“暴力解法”和“无解法”是两个极端算法题的丢分情况比较两极分化。一部分候选人面对题目直接“死磕暴力解法”完全不考虑时间复杂度和优化空间另一部分候选人一看到算法题就慌了写了两行就放弃甚至直接交白卷。其实前端笔试的算法题通常不会要求极致的优化但至少你的解法要能体现基本的复杂度意识。比如遇到一道“找出数组中第K大的元素”的题你可能会想到先排序再取第K个时间复杂度是O(nlogn)。这个解法本身能拿到一部分分数但如果你能进一步分析在K很小的情况下可以用最小堆将复杂度优化到O(nlogK)甚至提到快速选择算法的思想那你的得分就会明显高于“只会排序”的候选人。5.4 忽略题目中的业务场景信息这份卷子有不少题目是带有业务场景描述的比如“视频播放页出现白屏”“弹幕发送延迟高”“动态列表在快速滚动时出现闪烁”等。有些候选人只关注了问题的技术层面忽略了题目给出的场景上下文导致方案设计得“技术正确但与实际不匹配”。举个例子如果题目描述“B站视频播放页在弱网环境下加载很慢请设计优化方案”一个只懂技术的回答可能是“开启HTTP压缩、优化图片体积”但更贴合B站场景的回答应该先分析弱网环境下优先保证什么应该是首帧能播、拖动能响应而不是页面全部资源都加载完。所以方案里要考虑分片传输、清晰度自动降级、播放器预加载策略、关键资源优先加载等这些都是基于业务场景的考量。能在答题时体现出这种“业务意识”是很加分的。6. 一条省力的笔试准备时间线有些同学问过我如果距离笔试只有两到三周时间该怎么分配这里我给出一条亲测有效的“冲刺时间线”供参考。第一周主攻基础。把JavaScript核心知识点过一遍重点复习事件循环、作用域链、原型链、闭包、异步编程。配合刷题每天至少做二十道基础题保持手感。这周的目标是确保基础部分不丢分。第二周主攻框架与工程化。选择自己最熟悉的框架Vue或React把响应式原理、虚拟DOM、组件通信、生命周期这些核心机制吃透。工程化方面重点理解Webpack的核心概念特别是Loader、Plugin、Tree Shaking和代码分割以及Vite和Webpack的核心差异。第三周以真题模拟和查漏补缺为主。找两三套不同类型的前端笔试卷来做全真模拟模拟后认真复盘错题把薄弱知识点逐一击破。这周不用再大规模刷题重点是把已经掌握的知识用得更熟练。这条时间线比较紧凑适合有一定基础的同学。如果是从零开始准备建议至少预留六到八周前两三周用来补项目和基础中间两三周刷题和深入框架最后两周做模拟和复盘。我自己的经验是前端笔试准备的效率高低很大程度上取决于“能不能坚持复盘”。刷题一百道不复盘效果可能不如刷题五十道加五次深度复盘。每次做错的题目都值得花十分钟去思考为什么错是知识点盲区还是思路方向错了正确解法有没有更简洁的写法背后有没有系列相关的知识点需要一起复习把这些想清楚了一道错题吃透的知识量可能比闷头做十道题还多。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进