发布时间:2026/8/29 22:33:26
B站2020前端校招笔试题解析:闭包、手写代码与框架原理 1. 题目全景B站2020校招前端笔试卷到底在考什么1.1 试卷结构与考察方向拆解做前端校招这几年我经手过不少大厂的笔试卷子B站这套2020前端笔试卷一算是比较有代表性的。整张卷子想考察的方向非常明确不再考你背了多少API而是看你在真实场景下能不能把基础原理吃透、能不能手写出工程可用的代码。从题型分布来看基本可以分成四块。第一块是基础语法与数据类型题主要围绕typeof、instanceof、闭包、原型链这些JS核心概念展开第二块是手写代码题常见的有防抖节流、深拷贝、数组去重、Promise封装第三块是CSS布局与浏览器机制题比如flex布局、BFC、事件循环、渲染原理第四块是框架原理题Vue和React双线并重尤其爱考响应式原理、setState机制、虚拟DOM diff这些。这套题最值得研究的不是题目本身而是命题逻辑。你会发现它基本都是“启动条件简单、延伸深度大”的题型一句话描述场景然后让你写实现或者让你判断输出结果。这种出题方式的优势在于不给考生“背答案”的机会每一种写法背后都能反映你真实的理解深度。比如一个简单的防抖函数应届生可能只能写出300字的初版但真正理解闭包和this指向的人会在一版里就解决掉所有边界情况。这就是大厂筛人的核心逻辑。我的建议是做这套题不要只追求“写出来”要追求“为什么这么写”后面我会逐个题拆解。1.2 命题风格背后的人才画像看完B站这套笔试题我最大的感受是它们不是在招一个“会写页面的人”而是在招一个“能自己解决不确定问题的人”。整个岗位画像的核心词就两个扎实和灵活。“扎实”体现在对基础知识的追问方式上。比如列出null undefined和null undefined的输出结果这种题表面上是判断相等实际上考验你对JS隐式转换规范的掌握程度。而typeof NaN、typeof []这类输出题更是直接检验你有没有真正理解JS的数据类型系统。这些东西不背个三五遍现场很容易在细节上翻车。“灵活”体现在手写题和场景题上。卷子里会出现类似“实现一个带最大执行次数的防抖函数”“封装一个支持取消的Promise”这类变体题拼的就是你在标准答案之外能不能拓展出工程经验。笔试阶段还好到了面试环节面试官会顺着你的代码往下追问比如“为什么这里要用apply而不是call”“如果并发请求要怎么做边界控制”。这次复盘我会把每一类题都往这个深度去讲保证你看完不只能“过笔试”还能应对后续的追问。2. 手写题核心闭包、防抖节流与深拷贝的“工程级”写法2.1 闭包与作用域一道输出题背后的执行机制B站这套笔试卷子里的闭包输出题几乎是所有面试题的“开胃菜”。比如经典的for (var i 0; i 5; i) { setTimeout(function () { console.log(i); }, 1000); }这道题输出的是5 5 5 5 5而不是0 1 2 3 4核心原因在于var声明的变量是函数级作用域循环结束后i已经变为5而setTimeout的回调是在循环结束后的宏任务阶段才执行的此时访问的i自然指向同一个变量。很多同学答错这道题不是因为不知道异步而是没有把“作用域、变量提升、事件循环”三个知识点串联起来。正确的改法也不止一种。第一是用let声明利用块级作用域为每次循环创建独立的绑定第二是用 setTimeout 的第三个参数透传局部变量第三是用立即执行函数IIFE包裹形成闭包。我推荐第三种的变体因为你能顺带回答面试官的追问“如果我偏要用var你还有哪些办法”for (var i 0; i 5; i) { (function (j) { setTimeout(function () { console.log(j); }, 1000); })(i); }这里的关键是理解IIFE的入参i在每轮循环时就被“快照”到参数j上闭包记住的是参数j而不是外部变量i。这种题没有太多花哨技巧靠的是你对作用域链和闭包原理的底层理解。2.2 防抖与节流从“能跑”到“好用”的边界处理B站笔试卷里的防抖节流题通常不只是“写出来就行”它会限定场景。我见过最典型的版本是这样的实现一个防抖函数要求首次触发时立即执行且支持取消。这个版本的考点就比普通防抖多了一层。普通防抖的核心是在事件触发后延迟执行如果在延迟期间再次触发则重新计时。标准写法如下function debounce(fn, delay) { let timer null; return function (...args) { const context this; if (timer) clearTimeout(timer); timer setTimeout(() { fn.apply(context, args); }, delay); }; }但“首次立即执行”意味着要在开头加一个判断如果timer为null立刻调用否则才启动新的定时器。而“支持取消”就需要在返回值上挂一个cancel方法清空定时器并重置状态。完整的工程版本我习惯这么写function debounce(fn, delay, immediate false) { let timer null; const debounced function (...args) { const context this; if (immediate !timer) { fn.apply(context, args); } if (timer) clearTimeout(timer); timer setTimeout(() { fn.apply(context, args); timer null; }, delay); }; debounced.cancel function () { clearTimeout(timer); timer null; }; return debounced; }节流的工程版本也同理核心是控制执行频率。需要提醒的是笔试时切记不要把防抖和节流的定义搞混防抖是“只执行最后一次”节流是“固定间隔执行一次”。面试官大概率会让你用自己的话说出两者的区别和适用场景比如搜索框输入用防抖滚动加载和按钮点击频率限制用节流。2.3 深拷贝完整方案必须考虑到这四层深拷贝是B站这类校招笔试卷里最稳的一道手写题但这道题的上限极高。普通的浅层复制写法function deepClone(obj) { return JSON.parse(JSON.stringify(obj)); }这个版本在笔试中只能算基础分。JSON.stringify会忽略undefined、function、Symbol并且无法处理循环引用也无法处理Date、RegExp、Map、Set这类特殊对象。笔试想拿高分我的建议是至少实现到一个支持循环引用、能区分数据类型的版本。推荐一个能应对笔试和日常开发的深拷贝模板function deepClone(obj, hash 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 (hash.has(obj)) return hash.get(obj); const target Array.isArray(obj) ? [] : {}; hash.set(obj, target); Reflect.ownKeys(obj).forEach((key) { if (typeof obj[key] object obj[key] ! null) { target[key] deepClone(obj[key], hash); } else { target[key] obj[key]; } }); return target; }这里有两个细节需要展开。第一用WeakMap作为缓存目的是解决循环引用问题否则遇到a.self a会直接栈溢出。第二用Reflect.ownKeys而不是Object.keys是因为前者能拿到不可枚举属性和Symbol属性这在工程中很关键。笔试时即使不要求写到这个完整度也可以在注释里写出“这里还可以处理Symbol属性”让面试官知道你有这个意识。3. 框架与原理题从B站考法看Vue和React的核心区别3.1 Vue响应式原理从Object.defineProperty到Proxy的演进B站这套卷子里Vue相关题目主要围绕响应式原理展开。最典型的问法是“对data中的一个数组执行push操作页面会更新吗”。如果对Vue 2的响应式实现不了解很容易答错。Vue 2 的响应式重写了数组的七个方法push、pop、shift、unshift、splice、sort、reverse所以push后页面会更新但直接通过索引修改数组元素则不会触发。这就是为什么Vue 2 文档里强调要用Vue.set或splice来修改数组。Vue 3 则换成了Proxy这张卷子如果放在2020年之后考Vue 3的概率会更大。const reactive (obj) { return new Proxy(obj, { get(target, key, receiver) { // 依赖收集 track(target, key); return Reflect.get(target, key, receiver); }, set(target, key, value, receiver) { const result Reflect.set(target, key, value, receiver); // 触发更新 trigger(target, key); return result; } }); };对比两者最大的差异在于Object.defineProperty只能劫持已有属性新增属性需要额外处理而Proxy可以对整个对象进行代理新增、删除操作都能被监听。笔试时建议从“对象是否被整体代理”“数组是否要特殊处理”“新增属性是否需要额外API”三个维度来对比回答这样逻辑清晰也方便面试官顺着往下问。3.2 React setState同步还是异步取决于谁在调用React相关题目里B站比较偏爱考察setState的执行时机。这道题的细节非常多在React 18之前setState在事件处理函数中是异步的在setTimeout、原生事件监听器、Promise回调中是同步的。到React 18之后自动批处理机制会让所有场景默认执行异步批处理同步执行的场景需要显式使用flushSync。笔试时如果遇到“点击按钮后连续调用三次setState(count count 1)最终count是多少”这类题答案是3而不是1。因为传入的是更新函数React会把多个更新合并按顺序依次执行。如果传入的是普通值比如setState(count 1)三次最终只会加1因为React的批处理机制会用最后一次赋值覆盖前面的更新。能区分这一点基本就能证明你对React状态更新机制有真实理解。4. 浏览器机制与网络基础事件循环、渲染与跨域问题4.1 事件循环与宏任务微任务输出顺序题的通解思路前端面试绕不开的必考题B站笔试卷里也有不少“写出下列代码的输出顺序”题。核心逻辑并不复杂只要你记住同步代码先执行微任务先于宏任务宏任务按先后顺序执行。来看一道典型题目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。原因在于回调队列里微任务的优先级高于宏任务而setTimeout即使延时为0也要先进入宏任务队列。动手做这类题时我习惯先在草稿纸上列出“同步任务”“微任务”“宏任务”三个队列再把每个代码块依次入队顺序就一目了然了。4.2 跨域方案不必求全但要会“对比差异”跨域是试卷里的常客B站这边也不例外。最常见的出题方式是让考生回答“如果要向另一个域名的接口发送请求有哪些方案分别有什么优劣”。我建议从以下四个主流方案讲起JSONP、CORS、代理转发、postMessage。JSONP利用script标签不受同源策略限制的原理只能支持GET请求适合老项目对接。CORS后端在响应头设置Access-Control-Allow-Origin可以支持所有HTTP方法是当前的主流方案。代理转发在开发环境用webpack的devServer.proxy生产环境用Nginx反向代理本质是让同源的服务器去请求跨域接口再返回给前端。postMessage适用于iframe和window.open打开的页面之间通信。回答时不需要每个方案都背得滚瓜烂熟但一定要能说出“为什么JSONP不支持POST”“CORS的预检请求触发条件是什么”这两个追问点。5. CSS与工程化布局、选择器优先级和前端构建5.1 布局题flex三栏布局的几种写法CSS布局题在B站这套卷子里也占一定比重尤其是flex布局。最经典的题是“左右固定宽度中间自适应”的三栏布局。答案其实不止一种.container { display: flex; } .left { width: 200px; } .right { width: 200px; } .center { flex: 1; }这里有个容易被忽略的细节flex子项的默认min-width: auto会导致内容过长时中间栏被撑破所以通常需要给中间栏加上min-width: 0或overflow: hidden。这类小坑在笔试时不容易暴露但面试官一旦让你“说一个flex布局的坑”你回答这个就非常加分。5.2 工程化题模块化规范与性能优化2020年的前端校招试卷工程化相关内容已经相当普及。B站这套卷子里出现过“CommonJS与ES Module的区别”“如何做首屏性能优化”这类题目。CommonJS和ES Module的区别建议从三个角度展开加载时机、静态分析能力、循环依赖处理。CommonJS是运行时加载模块导出的是值的拷贝ES Module是编译时输出接口模块间是值的引用。这个区别延伸出来的问题就是:ES Module能进行tree shaking而CommonJS很难做到。性能优化题这块可以从网络、渲染、代码层面各说一条。网络层做HTTP缓存、CDN、接口合并渲染层做图片懒加载、骨架屏、减少重排重绘代码层做路由懒加载、第三方库按需引入、长列表虚拟滚动。“代码分割”容易答但“为什么分包可以提升首屏速度”的回答最关键浏览器只需要下载当前路由所需的代码把非首屏代码拆出去首屏JS体积变小加载和解析自然变快。笔试时我习惯列一个“优化手段实现思路收益说明”的结构表格一目了然。6. 笔试复盘考场上的常见失分点与冲刺建议6.1 那些年我们在笔试题上踩过的坑第一类常见失分点是“手写题能跑通但不考虑边界”。防抖函数里不处理this指向、深拷贝里不考虑循环引用、节流函数里不处理最后一次触发这些都会让面试官认为你停留在“能写Hello World”的阶段。第二类是“输出题凭感觉不写推导过程”。事件循环题里如果只写答案不写步骤丢分很可惜。即使是笔试我建议也要在代码旁边简短写上“为什么”的推导因为很多在线笔试题会要求提交解释。第三类是“框架题只背结论不解释原因”。比如知道Object.defineProperty无法监听新增属性但说不清新增属性为什么不会触发响应式更新这涉及Vue初始化时递归遍历的机制也是分水岭所在。6.2 冲刺阶段的准备思路结合B站2020这套笔试题我给正在准备校招的同学三个建议。第一刷题不能只刷“简单版”。像防抖、节流、深拷贝这类题网上到处都是基础答案你要做的是主动给自己“加条件”模拟面试官会提出的实际场景限制。第二建立自己的笔记体系。每道错题不只是记录答案而是记录知识点之间的关联。比如闭包输出题关联到事件循环再关联到防抖节流和函数柯里化。这种网状结构比零散刷题有效得多。第三把“手写题”真正写到肌肉记忆的程度。考场上时间紧张手写题如果还需要现场思考思路通常写不出完整版本。建议在笔试前把高频手写题至少默写三遍一直到不需要犹豫就能写完整。从我个人经历来看B站这套笔试题的难度在当年校招里属于中上水平但它考察的知识点都非常“正”没有什么偏题怪题。认真把基础原理搞懂把经典手写题练到顺手通过笔试并没有想象中那么难。最后再分享一个小技巧在线笔试前把本地编辑器的自动补全关掉练几轮手写等上了考场你会发现真正的做题速度比你想象中要快得多。

相关新闻

2026/8/29 22:28:26

Pygame贪吃蛇游戏开发:从零搭建静态界面与网格化设计

1. 项目概述:为什么从界面开始?很多朋友学编程,第一个想做的游戏就是贪吃蛇。它规则简单,逻辑清晰,是理解游戏循环、事件处理和图形绘制的绝佳入门项目。但不少教程一上来就讲蛇的移动、食物的生成,把一堆代…

2026/8/29 22:48:28

前端面试高频考点全解析:基于牛客面经的实战指南

最近我把牛客上前端相关的面经翻了个遍,刷完最大的感受是:前端面试真不是靠背八股能过的,但它也没有想象中那么玄。现在网上关于前端面试题的资料满天飞,但真正高质量、带完整解析、又能说清楚“面试官为什么这么问”的内容其实很…

2026/8/29 22:48:27

Hello-Agents 智能体教程:16 章完整指南

Hello-Agents 智能体教程:16 章完整指南 【免费下载链接】hello-agents 📚 《从零开始构建智能体》——从零开始的智能体原理与实践教程 项目地址: https://gitcode.com/GitHub_Trending/he/hello-agents Hello-Agents 是 Datawhale 开源的《从零…

2026/8/29 22:48:27

微表情识别中的自适应关键帧技术原理与实现

简介:微表情识别是一种基于面部肌肉细微运动分析的情绪感知技术,其核心挑战在于从高冗余视频流中精准捕获毫秒级动态事件。传统固定采样方法因忽略微表情的物理运动学特性(如加速度突变、三阶段时序结构),导致有效信息…

2026/8/29 22:48:27

Android+Flutter面试进阶:简历编排与混合开发实战要点

做了这么多年Android,又带着团队做Flutter跨端改造,我筛过的简历少说也有上千份,现场面过的人没有两百也有一百五。有个现象特别明显:纯Android背景的候选人写Flutter项目经历时,十有八九写得像在凑字数;而…

2026/8/29 22:48:27

ComfyUI与Wan2.2工作流:从零构建AI二次元视频生成平台

简介:在AIGC领域,Stable Diffusion等扩散模型通过去噪过程从文本生成高质量图像,其核心原理在于理解潜空间表征与提示词的映射关系。这项技术的工程价值在于将复杂的AI生成过程模块化、可视化,极大地提升了创作的可控性与可重复性…

2026/8/29 21:30:11

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/28 16:16:21

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/28 16:16:22

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/29 0:01:10

etc目录下的profile.d文件目录设置环境变量和全局脚本shell

一、设置环境变量etc目录下的profile.d文件目录 /etc/profile.d1、编写 vi test.sh文件内容# jdk变量 export ZHK_HOME/root export PATH$PATH:$ZHK_HOME/test # 可以取出来ZHK_HOME变量给ZZZ_HOME赋值 export ZZZ_HOME${ZHK_HOME}/test2、刷新 执行source /etc/profile 命令使…

2026/8/29 0:01:10

【JavaScript】内存管理-垃圾回收机制-内存泄露

内存管理 C 语言这样的底层语言一般都有底层的内存管理接口,比如 malloc()和free()。 而 JavaScript 是在创建变量(对象,字符串等)时自动进行了分配内存,并且在不使用它们时“自动”释放。释放的过程称为垃圾回收。 整…

2026/8/29 0:01:10

Labgrid-MCP:为嵌入式硬件实验室接入AI Agent操控能力

Labgrid-MCP 的目标是把 MCP(Model Context Protocol)能力延伸到真实嵌入式硬件实验室:AI Agent 通过一个标准化的 MCP Server,就能查看目标板状态、控制上电断电、复位开发板、读取串口日志,甚至执行镜像刷写。对于经…

2026/8/28 16:16:48

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/28 16:16:50

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/28 11:06:45

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…