行内人都清楚,笔试刷人最狠的往往是B卷。爱奇艺2019秋招这套前端B卷,放在当时是标准的大厂风格,放在现在看,很多题依然能打——它没有考什么花哨的新框架、新API,而是把JavaScript基础、异步机制、浏览器原理、框架底层这些“压箱底”的东西翻出来反复碾。准备这套题的过程,本质上就是把前端知识体系重新捋一遍。这篇文章我结合自身体会,把这套题涉及的考点拆开揉碎讲清楚,顺带聊聊面试官到底想从笔试里看到什么。
1. 从一套题反推大厂的出题逻辑
很多同学刷题有个误区:把笔试当成期末考试,背答案、记结论。但大厂笔试从来不是考“你知不知道这个知识点”,而是考“你在真实开发里遇到问题能不能兜住”。爱奇艺这套B卷的出题风格就是典型——题干不长,陷阱不少,每道题背后都藏着一两个实际开发中容易翻车的场景。
1.1 核心需求解析:笔试到底在筛什么人
我经常跟身边准备校招的朋友说,笔试是所有环节里最“冷血”的一关——它不看你的项目经历多牛,不看你的简历多漂亮,只看你脑子里沉淀了多少东西。爱奇艺作为视频行业头部玩家,前端团队要维护的是千万级DAU的页面,性能、稳定性、兼容性都是硬指标,所以笔试筛人最看重三点:
第一,JavaScript语言功底扎不扎实。像类型转换、作用域、闭包、原型链这些,不是背概念,而是能在代码里瞬间反应出结果。第二,异步编程的理解够不够深。视频站点的播放器逻辑、用户行为上报、弹幕渲染,全是异步场景,回调地狱、事件循环理解不到位,代码根本写不利索。第三,对工程化和常用框架的认知是不是停留在“会用”层面。B卷里涉及Vue或React的题目,考的不是API调用,而是底层原理和设计思想。
这三点对应到做题策略上,就是:基础题要快而准,原理题要写得够深,编程题要边界完整。很多人在笔试里挂掉,不是不会做,而是前面选择题磨太久,后面编程题没时间写,或者写出来一堆边界漏洞,一眼就被看穿代码功底。
1.2 这套题目标定的人群:不只是应届生
虽然标题写的是“2019秋招”,但我的看法是,这套题的价值完全不限于校招。如果你是社招1到3年的前端,想检验自己有没有吃透JavaScript核心,这套题同样值得拿来做一次自测。我在准备技术分享时也经常把它当作“内功体检题”推荐给组里的新人。
原因不复杂:行业里三年以内的前端,很多人日常工作就是写Vue页面、调接口、改样式,真正要跟复杂的异步逻辑、底层原理打交道的机会其实不多。这就导致一个现象——简历上写着“熟练掌握JavaScript”,一碰到[1,2,3] + {a: 1}这种题就懵。爱奇艺这套B卷恰恰就是把这类问题集中起来,逼你把模糊地带全部补齐。
2. 基础题型的考察重心与解析思路
这套卷子的选择题部分,覆盖面其实很典型。我按考点类别拆开说,每个类别我都会挑一道代表性题目展开,讲讲出题人想考什么,以及怎么快速做对。
2.1 JavaScript类型转换与运算符优先级
类型转换几乎是每家大厂笔试的保留项目。爱奇艺B卷里出现了一道关于数组转字符串后参与运算的题,大致形式是:
const a = [1, 2, 3]; const b = a + 1; console.log(typeof b, b);很多人一眼看到数组就懵了。实际上这里隐藏着两个知识点:数组的toString()方法会默认把元素用逗号连接成字符串,然后字符串和数字做加法运算时,数字会被转换成字符串做拼接。
所以[1, 2, 3] + 1的结果是字符串"1,2,31",typeof结果是"string"。
这种题我刚工作那会儿也做错过,因为脑子里记的是“数字加数字等于数字、字符串加数字等于字符串”,但没意识到数组会先被隐式转换。做题的时候记住一条主线:加减法运算里,如果两侧有对象或数组,先调valueOf,再调toString,拆到底再比较类型。数组的valueOf返回自身,不是原始值,所以会走toString,因此[1,2,3]变成"1,2,3"。
还有一种变体是[] + []和[] + {},空数组加空数组结果是空字符串,空数组加空对象结果是"[object Object]",原理一模一样。这类题没有捷径,就是多看多记,吃透隐式转换的那套规则。
2.2 作用域、闭包与变量提升
作用域和变量提升也是高频考点。爱奇艺B卷里有一道比较典型的输出顺序题,我复述一下核心逻辑:
var num = 10; function fn() { console.log(num); var num = 20; console.log(num); } fn();答案是undefined和20。考点就是变量提升:函数作用域内的var num会被提升到函数顶部,但赋值不会提升,所以第一次打印时num是undefined,但注意它不会去访问全局的10,因为局部变量已经声明了。
顺带一提,如果把var换成let,结果就变成报错(暂时性死区)。let声明会被提升但不会被初始化,访问就会抛ReferenceError。这俩对比着记,笔试基本不会丢分。
闭包的考点往往会跟循环绑在一起,比如经典的:
for (var i = 0; i < 5; i++) { setTimeout(() => console.log(i), 100); }输出全是5,原因是var没有块级作用域,setTimeout的回调访问的是同一个i。改成let就是0 1 2 3 4,或者用闭包、bind、Promise.resolve包一层也行。这类题考的就是对作用域链和闭包本质的理解。
2.3 this指向与箭头函数
this指向问题在笔试题里几乎从不缺席,爱奇艺B卷也不例外。它的考察方式通常是对象方法调用、函数独立调用、箭头函数混在一起,让你判断输出。
基本规则还是那套:箭头函数没有自己的this,它的this在定义时就继承了外层词法作用域;普通函数的this由调用方式决定。我见过很多人记混,这里提供一个实用的做题顺序:
- 首先看是不是箭头函数,是就走外层作用域;
- 不是箭头函数,再看调用时是不是对象方法调用(
obj.fn()); - 再看有没有
new、call、apply、bind; - 如果都没有,就是独立函数调用,在浏览器非严格模式下指向
window,严格模式和Node环境里是undefined。
套这个顺序,八九成的this指向题都能做对。比如var obj = { name: 'x', get: () => console.log(this.name) },箭头函数的this指向定义时所处的作用域——也就是全局环境,所以obj.get()拿到的是全局的name,而如果name没有用var声明在全局,结果就是undefined。
2.4 Promise与事件循环
异步题在B卷里占的比例相当高。视频网站的前端,播放进度上报、弹幕异步加载、推荐流懒加载,全是异步场景,所以考察Promise、async/await、事件循环完全在情理之中。
爱奇艺B卷里的异步题,经典的一种是把setTimeout、Promise.resolve().then、async/await混在一个代码片段里,让你写出输出顺序。答案的核心是把握好任务队列的优先级:同步代码先执行,然后微任务,然后宏任务。Promise.then和async/await的后续代码属于微任务,setTimeout属于宏任务。
我在这里栽过跟头的地方是async/await的边界情况。比如:
async function test() { console.log(1); await Promise.resolve(); console.log(2); } test(); console.log(3);输出是1 3 2,因为await会让出执行权,后面的console.log(2)被排在微任务里。但如果await右侧是一个已经reject的Promise,那就得配try/catch,否则会抛未捕获的错误。
做题时要特别留意微任务里又产生了微任务的情况,比如Promise.resolve().then(() => Promise.resolve().then(...)),这类嵌套微任务会比外层宏任务更早执行,很多选择题专门在这里埋雷。
3. 编程题实战:从思路到可运行的代码
选择题只是热身,编程题才是笔试拉开差距的地方。爱奇艺B卷的编程题一般有两道,一道偏算法/数据结构,一道偏业务场景实现。我挑两个具有代表性的类型,完整走一遍从审题到实现到优化的过程。
3.1 手写防抖函数与业务场景结合
视频网站里搜索框的实时联想、播放器倍速切换、窗口resize适配,全都要用到防抖或节流。所以手写防抖几乎是笔试必备题,爱奇艺B卷也考了。题目一般这样出:
请实现一个debounce函数,要求:传入的函数在连续触发时只执行最后一次,且能正常接收参数、保持this指向。
function debounce(fn, delay = 300) { let timer = null; return function(...args) { const context = this; if (timer) clearTimeout(timer); timer = setTimeout(() => { fn.apply(context, args); timer = null; }, delay); }; }两点最关键:一是this要保留,因为debounce返回的新函数可能作为对象方法被调用;二是参数要通过...args透传。很多新手写漏了this绑定,结果业务里用debounce包装的方法拿不到this数据,这是非常典型的坑。
如果需要“第一次立即执行、后续触发需要等待”的效果,可以加一个immediate参数:
function debounce(fn, delay = 300, immediate = false) { let timer = null; return function(...args) { const context = this; if (timer) clearTimeout(timer); if (immediate && !timer) { fn.apply(context, args); timer = setTimeout(() => (timer = null), delay); } else { timer = setTimeout(() => { fn.apply(context, args); timer = null; }, delay); } }; }这个版本在即时反馈型功能里非常实用。笔试时如果时间充裕,把immediate方案写出来,会显得你的代码设计能力比普通人高半档。
3.2 数组扁平化与去重排序的组合实现
另一类高频编程题是数组处理。爱奇艺B卷出现过类似“将多维数组扁平化并去重后升序排列”的题目。这类题本身不难,但能考出好几层功底。
const arr = [1, [2, [3, [4]], 5], [6, 7], 8]; // 扁平化 - 递归方式 function flatten(arr) { return arr.reduce((acc, cur) => Array.isArray(cur) ? acc.concat(flatten(cur)) : acc.concat(cur), []); } // 也可以直接用 flat(Infinity) const flatArr = arr.flat(Infinity); // 去重并升序 const result = [...new Set(flatArr)].sort((a, b) => a - b); console.log(result); // [1, 2, 3, 4, 5, 6, 7, 8]但如果你只写出上面的代码,面试官可能还会追问:如果不允许用flat怎么办?如果不用Set能不能去重?这些都是笔试后现场面聊的延伸题。
手写去重时要注意,[1, '1']用Set去重会保留两个元素,因为1和'1'类型不同。而[NaN, NaN]用Set是能去重的,因为NaN === NaN为false,但Set内部用的是严格相等加特殊处理。这些细节,面试官一问一个准。
快速排序、二分查找等基础算法也有概率出现,但B卷整体更偏业务应用,不会出特别变态的ACM题。备考时把常见的数组操作、字符串操作练熟,性价比最高。
4. 框架与工程化知识点的深浅分层
B卷里有相当一部分内容涉及框架和工程化,这部分考的不是“怎么用”,而是“为什么这么设计”。爱奇艺前端大量使用Vue,所以Vue相关原理出现的概率很高。
4.1 Vue 2 响应式原理和侦听器陷阱
典型的题目是:data里有一个对象,怎么让它变成响应式的?如果直接this.obj.newProp = 1,页面会不会更新?答案是不会,因为Vue 2的响应式系统通过Object.defineProperty在初始化时遍历对象已有属性完成依赖收集,新增属性并没有经过defineProperty,所以不是响应式的。解决方案是this.$set,或者用Object.assign重新赋值整个对象。
这类题考的是对源码机制的理解,不是死记API。你要是能说清楚$set内部也是调用了defineReactive重新定义属性,顺带把依赖通知流程提一下,面试官基本就给你打高分了。
但我得提醒一句:不能只背Vue 2的答案。如果笔试或面试中要求对比Vue 3,你要知道Vue 3里用Proxy实现了响应式,新增属性天然是响应式的,因为Proxy拦截的是对整个对象的操作。Vue 2和Vue 3的差异对比,在这套2019年的卷子里未必直接考,但放到现在的面试里,几乎是必问项。
4.2 组件通信与代码组织规范
爱奇艺笔试B卷考查的组件通信方式,通常以选择题形式出现:父子组件通信用props和$emit,兄弟组件通信用事件总线或状态管理,跨层级通信用provide/inject或Vuex。这些大家都熟,但经常被忽略的是边界场景,比如props的默认值必须由工厂函数返回,直接传对象引用容易造成数据串改。
工程化相关的题目则会涉及模块化(CommonJS和ESModule的区别)、打包产物(浏览器缓存策略根据文件指纹判断)、以及代码规范。热词列表里出现了“前端开发规范vue”,这其实反映的是行业普遍痛点——规范不是为了好看,而是为了降低多人协作的维护成本。笔试不会让你背规范文档,但会通过代码风格判断题、重构题来间接考察你有没有规范意识。
我在实际带团队时见过很多次:页面能跑就行,eslint报错一大片也没人管,结果后面接手的人改一行代码要小心翼翼半天。所以碰到这类题,多想想“这段代码如果提交到团队仓库,别人看得懂吗?改起来安全吗?”,思路会清晰很多。
4.3 前端AI开发与新型工具链的一个延伸
标题虽然写在2019年,但热词里有“前端ai开发”,我顺便提一嘴:现在不少公司已经把AI能力引入前端工作流,比如用大模型生成页面代码、自动修bug、生成测试用例。这套B卷当时没有这块,但如果你在面试中表现出对AI辅助开发的理解,比如知道怎么用提示词工程约束代码风格、怎么让AI生成符合团队规范的组件代码,会是一个很大的加分项。
这不等于让大家丢掉基本功。恰恰相反,AI生成代码的背后,你还是得能判断生成得对不对、边界考虑全不全——而判断能力,恰恰就是这套笔试想考的东西。
5. 答题策略与避坑经验汇总
笔试光会知识点不够,策略不对照样翻车。我梳理了几个在真实笔试里反复出现的坑,以及对应的应对策略。
5.1 时间分配的常见失误
很多人开局就在选择题上死磕,特别是一道类型转换题卡了五分钟。一套前端笔试题,选择题大概20到30道,编程题两到三道,总时长一般是一个半小时到两个小时。如果选择题平均每道超过三分钟,后面编程题的时间就会被严重压缩。
我的建议是:拿到卷子先花一分钟扫一遍题目分布,把编程题先看一遍,心里有数。选择题遇到不会的,先标记跳过,不要恋战。编程题先写出能跑通核心用例的版本,再逐步优化,不要一上来就试图写最优解。因为判卷系统通常会跑多个用例,核心用例过不了,细节优化得再漂亮也是零分。
5.2 手写代码必须注意的边界条件
手写函数时,最容易丢分的是边界条件。举几个例子:
- 输入参数为
null、undefined、空数组时,函数是否报错? - 回调函数的
this指向是否被正确绑定? - 数组操作是否有空数组、单个元素数组的边界?
- 递归函数有没有终止条件?
sort函数是否明确传入了比较函数?数组元素是数字时,默认排序是按字符串排序的,[1, 10, 2].sort()结果是[1, 10, 2],这算经典陷阱。
真实笔试题里,不少看起来能跑通的代码,就是因为没处理边界,被判卷系统扣了很多分。写完后花30秒过一遍这些边界,性价比极高。
5.3 审题时容易被忽略的隐藏信息
大厂笔试题喜欢在题干里放“烟雾弹”,比如“请实现一个防抖函数,要求支持取消操作”。如果你只实现了基础防抖,取消了cancel方法,那这道题就丢了一半分。
因此做题前一定要把题干读到每个词。看到“取消”、“立即执行”、“最大等待时间”、“支持对象传参”这些关键词,都要在代码里体现出来。拿防抖进阶版举例,支持取消的写法就是额外暴露一个cancel方法:
function debounce(fn, delay = 300) { let timer = null; const debounced = function(...args) { if (timer) clearTimeout(timer); timer = setTimeout(() => { fn.apply(this, args); timer = null; }, delay); }; debounced.cancel = () => { if (timer) clearTimeout(timer); timer = null; }; return debounced; }这种对题意的敏感度,只能靠平时多做题多总结练出来。没有捷径。
6. 从笔试到面试:看懂题目背后的组织诉求
一套笔试做下来,如果只拿到分数,其实浪费了一半价值。我做技术面试官这些年,看候选人有个习惯:笔试答得好的人,面试时通常不会太差;笔试答得乱的人,面试时大概率也会露馅。因为笔试和面试考察的底层能力高度一致。
6.1 笔试成绩如何影响技术面试的走向
大多数公司面试官在面候选人之前,会先浏览笔试答题情况。如果笔试选择题准确率很高,编程题边界处理完整,面试官在面试时就会倾向聊项目细节、深度原理,而不是重复基础题。反过来,如果笔试里基础题错误多,面试官就会特意追问更多基础问题,而且会挖得更深,试图确认你是不是只是运气好蒙对了几道题。
所以我的建议是:笔试结束后,不要马上对完答案就丢一边。把每道错题记录下来,查漏补缺,再对照相关知识点扩展学习一遍。我自己准备跳槽那会儿,就是靠反复复盘笔试题,把整个知识体系重新夯了一遍,效果比漫无目的地看面经好得多。
6.2 考点背后的团队工作场景
爱奇艺前端笔试B卷里的题目,几乎每一道都能对应到一个真实工作场景。类型转换题对应的是接口返回数据格式不稳定时的兜底处理;事件循环题对应的是播放器里先上报再渲染的时序控制;手写防抖对应的是搜索联想和滚动加载;Vue响应式原理对应的是大数据列表的更新性能优化。
想清楚这层对应关系,笔试就不再是一堆冷冰冰的题目,而是提前走了一遍未来工作的技术地图。你能答得出来,说明你具备解决这些问题的基本素质;答不出来,恰恰是给你敲了警钟,告诉你在哪些方面还需要补课。
6.3 给准备秋招的你的几条实操建议
最后给正在准备秋招的朋友几条实操建议,都是我自己或带过的同学趟过水之后的经验:
第一,刷题不要贪多,用一套大厂真题反复吃透,比草草刷十套效果更好。第二,编程题一定要在本地真实跑一遍,不要只在编辑器里看答案觉得会了。眼会手不会,上考场就露馅。第三,建立自己的错题本,不用多精美,记下来方便考前翻阅就行。第四,有条件的话找人模拟一次笔试,掐时间感受一下节奏,能帮你提前暴露时间分配的问题。
另外,如果你的目标是视频、直播这类高并发、强交互的业务,建议把浏览器渲染机制、动画性能优化、网络请求策略这些知识也一起补上。这些虽然不是笔试必考题,但进了面试环节,几乎是聊项目时绕不开的话题。
说到底,笔试只是第一道门,但它筛的不只是知识储备,还有你的学习习惯和工程意识。基础扎实的人,不一定能拿到所有offer,但一定不会在笔试阶段被莫名其妙地刷掉。希望这篇拆解能帮你把爱奇艺这套B卷吃透,也祝你在接下来的秋招里,每一道题都能看到出题人的良苦用心。