公司动态
爱奇艺前端笔试题深度解析:JS基础与浏览器机制考点全梳理
爱奇艺2019秋招前端方向笔试题A在网上已经传了好几年但每次拿出来看都不过时。原因很简单这份卷子考的不是“背答案”而是前端基础功底的扎实程度以及遇到陌生问题时怎么拆解、怎么推导。我自己在做这份题的过程中最大的感受就是——它把JS的语言特性、浏览器运行机制、CSS布局原理、网络协议常识、代码手写能力这几个维度全部串在了一起。如果你正在准备大厂前端岗的笔试或者已经工作但想系统复盘一下基础这份题都是一个很好的试金石。这篇内容我会按照笔试题的高频模块来拆解把每类题目背后的考点、原理、踩坑点都展开讲最后附上一些实战经验。1. 内容整体设计与思路拆解1.1 核心考点拆解爱奇艺这套前端笔试题A的考察范围基本可以映射到大多数中大型互联网公司前端笔试的经典结构JavaScript语言特性、CSS布局与渲染、浏览器与网络、手写代码与逻辑题。它不会直接问“闭包是什么”这种八股而是通过读代码写输出、补全代码、判断执行顺序等方式考察你是否真正理解这些特性。这套卷子里最值得注意的是把“输出顺序题”和“原型/继承题”作为重点。这类题在牛客网上特别常见但很多人刷题只是记答案不去追“为什么”。比如一道经典的setTimeout与Promise输出顺序题如果你不理解微任务和宏任务的执行时机、不理解事件循环的每一轮都会“先清空微任务队列”那换一个变体就必错。爱奇艺的题也有这个风格喜欢在细节上做文章一个选项里的小括号位置都会影响整个逻辑。另外CSS部分不会直接考“flex怎么用”而是给一个布局需求让你写属性或者给你一段代码问最终渲染居中还是歪了。这说明考点是“实际场景下能不能正确地使用属性”不是背单词。而 HTML 语义化、BFC、层叠上下文这些虽然老但依然会反复出现——因为这些直接决定了页面的可维护性和渲染表现。1.2 为什么大厂笔试偏爱这类题型很多人疑惑前端平时写业务都是 Vue/React为什么笔试不考框架核心原因是框架迭代太快语言和浏览器才是恒定的底层。Vue 3 的源码、React 的调度机制本质上都是基于 JS 语言特性和浏览器 API 来实现的。如果一个候选人连var和let的区别、和的转换规则都说清楚那让他上手框架也得靠猜。爱奇艺作为视频巨头前端团队要面对播放器、首屏渲染、流量控制、广告投放、页面性能优化等高复杂度场景。这些场景非常依赖对事件循环、DOM 操作代价、缓存策略、网络请求调度的深入理解。所以笔试出题方向天然偏向这些基础能力。同时笔试题也筛掉“只会调接口写页面”的候选人。前端岗位的竞争早就白热化了单纯会“调库”“会用组件”已经不够。企业需要一个候选人能解释“为什么页面卡”、能定位“为什么这个按钮点击后延迟反馈”、能设计“如何减少不必要的渲染”。这些全得靠基础功底。所以做这份题与其说是应付面试不如说是一次自我体检。2. 核心细节解析与实操要点2.1 JavaScript 基础考点从执行上下文到闭包JS 部分最核心的几块执行上下文与作用域链、闭包、this 指向、原型链、Event Loop、ES6 新特性。爱奇艺这类大厂笔试很少直接考概念更多是给代码问输出所以关键是要学会“模拟执行过程”。一个常见题型是var a 1; function foo() { console.log(a); var a 2; } foo();输出是什么答案是undefined。原因是var声明会提升到函数作用域顶部所以函数内的a在打印时已经被定义但还没有赋值。这就叫变量提升。很多人只看答案觉得简单但换成let就会变成ReferenceError因为let存在暂时性死区TDZ。闭包题往往结合循环for (var i 0; i 3; i) { setTimeout(function() { console.log(i); }, 100); }输出是3 3 3。原因是var没有块级作用域setTimeout回调里访问的是同一个i而循环结束时i已经是 3。把var改成let或者用 IIFE、bind、闭包包一层才能输出0 1 2。这背后实际上就是作用域捕获的时机问题也是笔试里最常设的坑。关于 this 指向我给大家一个最实用的判断口诀“函数被谁调用this 就指向谁”。但还要记住例外箭头函数没有自己的 this它继承外层词法作用域的 thisnew调用的时候 this 指向新对象call/apply/bind可以显式指定 this。笔试题里最常见的套路是var obj { name: a, fn: function() { console.log(this.name); } }; var f obj.fn; f();这段输出undefined严格模式下或全局对象属性而不是a。因为f()调用时调用者是全局对象不是obj。这类题考察的是“引用丢失”问题在 React 类组件时代经常出现现在写函数组件也偶尔会遇到类似场景。2.2 CSS 与浏览器渲染盒模型、BFC、层叠上下文CSS 部分不能只靠“用过 flex”。笔试题会重点考察标准盒模型和 IE 盒模型的区别、外边距折叠、BFC 的形成条件与作用、层叠上下文、水平垂直居中方案、flex 的 flex-grow/shrink 计算。盒模型这道基础题每次笔试出现率都极高。box-sizing: content-box时width只算内容宽度border-box时width包含内容、内边距和边框。实际开发时设置全局* { box-sizing: border-box; }可以减少大量宽高计算麻烦。这一点在笔试题里往往通过“问某个元素的实际占位宽度”来考。BFC 是一块硬骨头但记住“BFC 是一个独立的渲染区域内外互相不影响”就抓住了本质。触发 BFC 的条件很多float不为none、overflow不为visible、display: inline-block、position: absolute/fixed、display: flex等。用途主要是清除浮动、防止外边距折叠、阻止元素被浮动元素覆盖。比如经典的“父元素高度塌陷”问题给父元素设置overflow: hidden触发 BFC就能把浮动子元素的高度算进去。层叠上下文则容易和z-index混淆。实际上z-index只在相同层叠上下文中比较。transform、opacity、filter、position加z-index都会创建层叠上下文。笔试题常给一个多层嵌套的定位元素问你哪个在最上面这时候就要按“父级上下文先比再比同级的 z-index”来推。我见过不少人死记z-index: 9999碰到嵌套场景还是出错关键是理解规则。2.3 浏览器与网络HTTP 缓存机制前端笔试里网络部分的常客是TCP 握手、HTTP 状态码、GET/POST 区别、HTTP 缓存、跨域。爱奇艺这套题里同样有涉及尤其是缓存。HTTP 缓存可以简单理解为“服务器给资源打标签浏览器下次按标签决定是否复用”。强缓存阶段浏览器直接用本地副本不请求服务器协商缓存阶段浏览器带着标签去问服务器“这个资源还能用吗”服务器决定返回304还是新资源。相关字段有Cache-Control: max-age、Expires强缓存Last-Modified/If-Modified-Since、ETag/If-None-Match协商缓存。前端笔试特别爱问“输入 URL 到页面展示的全过程”。这不是背流程就行而是要说明每一步的关键机制DNS 解析可能会查缓存、TCP 连接三次握手、发送 HTTP 请求携带缓存校验信息、服务器返回响应、浏览器解析 HTML 构建 DOM 树、解析 CSS 构建样式规则、JS 阻塞解析、布局与绘制。能流畅说出这个过程说明你对浏览器运行机制有整体概念这也是性能优化思路的起点。2.4 手写代码与算法从数组去重到防抖节流手写题是笔试中的重头戏。最常出现的几类数组去重、数组扁平化、深拷贝、防抖节流、Promise 实现、函数柯里化、Pub/Sub 事件总线。爱奇艺这类题的特点是要求不一定用 ES6 一行流而是看你能不能写出健壮且可读的实现。数组去重看起来简单但考察的点是你知不知道多种方式Set一行解决filter indexOf解决但只能处理原始类型Map或对象键值处理引用类型。如果面试官追问“[1, 1]去重后有几个”你就会发现Set用的是SameValueZero比较不会把1和1混掉。防抖和节流是面试必考题也是笔试手写题常客。防抖debounce的核心是“只认最后一次”短时间内连续触发只有最后一次等待期结束后才执行。典型场景是搜索框输入联想。节流throttle的核心是“限制频率”不管触发多少次每段时间最多执行一次。典型场景是滚动事件、resize。实现都不难但要注意this绑定和参数透传否则改 bug 改到怀疑人生。下面是一个带this和参数处理的防抖实现function debounce(fn, wait) { let timer null; return function(...args) { const context this; if (timer) clearTimeout(timer); timer setTimeout(() { fn.apply(context, args); }, wait); }; }3. 实操过程与核心环节实现3.1 数组与对象操作常用方法背后的原理笔试题里经常考“下列哪个方法会改变原数组”。很多人用的时候不关心这个但笔试偏偏要考。像push、pop、shift、unshift、splice、sort、reverse会改变原数组而map、filter、reduce、slice、concat不会。如果记不清可以直接用一个技巧方法名暗示是“原地操作”的一般会改。Array.prototype.reduce是高频考点因为它是“万能函数式工具”。笔试有时候会让你用reduce实现map、filter、groupBy或者compose。比如用reduce实现数组扁平化function flatten(arr) { return arr.reduce((acc, cur) { return acc.concat(Array.isArray(cur) ? flatten(cur) : cur); }, []); }对象相关考点则集中在属性遍历for...in 与 Object.keys 的区别、对象深比较、可选链、解构赋值、展开运算符。有一道经典题是const obj { a: 1 }; const obj2 { ...obj }; obj2.a 2; console.log(obj.a); // 1因为第一层是浅拷贝但如果对象里嵌套了对象展开运算符只能拷贝第一层引用修改嵌套对象会连坐。所以深拷贝必须自己写递归或借助structuredClone或lodash.cloneDeep。笔试写深拷贝时还要考虑循环引用、日期、RegExp、Map、Set 等情况能写出一个面试官会点头的版本能加分不少。3.2 异步流程控制从回调地狱到 Promise异步是前端笔试的“分水岭”。一部分人看到 Promise 就头晕但真正理解事件循环后会发现所有异步题都是一个套路同步代码先执行然后按微任务和宏任务的优先级轮询执行。你只要记住 Node.js 和浏览器的核心差异不是太大最重要的是“每执行完一个宏任务都会清空整个微任务队列”。下面这个顺序题几乎成为大厂必考console.log(script start); setTimeout(function () { console.log(setTimeout); }, 0); Promise.resolve() .then(function () { console.log(promise1); }) .then(function () { console.log(promise2); }); console.log(script end);输出依次为script start、script end、promise1、promise2、setTimeout。原因是Promise.then属于微任务setTimeout属于宏任务同步代码结束后会先清空微任务队列再去取宏任务。如果题目里再加async/await其实也简单await右边的表达式会立即执行await之后的代码相当于.then里的回调会放入微任务队列。所以看到async题先把同步部分推完再把await后面的内容当作微任务按顺序排好即可。3.3 网络请求与 API 设计前端如何和服务器协作前端笔试还会通过代码题考察你对HTTP 状态码和请求方法语义的理解。比如“创建一个资源用什么方法更新整个资源用什么方法删除用什么方法”——这就是 RESTful 风格。POST用于创建PUT用于整体更新PATCH用于部分更新DELETE用于删除。如果对语义不熟接口设计时容易和别人撞车。另外一个高频点是GET 与 POST 的区别。很多人背“GET 有长度限制、POST 安全”其实不严谨。本质区别更多体现在GET 请求通常用于“查询”参数放到 URL 上会被浏览器缓存、会留在历史记录里POST 通常用于“提交”参数放 body不会被缓存。至于长度限制其实是服务器或浏览器实现的限制不是 HTTP 协议硬性规定。这道题考的是你能不能区分“协议语义”和“实现限制”。还有一类代码补全题要求你封装一个request函数处理超时、重试、错误码。实现上核心是“用Promise.race做超时控制”或者“用递归/循环做重试”。下面是一个简化版的超时请求封装function requestWithTimeout(url, options {}, timeout 5000) { return Promise.race([ fetch(url, options), new Promise((_, reject) { setTimeout(() reject(new Error(timeout)), timeout); }) ]); }这种题看着不难但能把边界条件想清楚超时后要中断请求、重试要避免重复提交、loading 状态如何处理就能体现你写业务代码时是否严谨。3.4 前端工程化模块化、构建工具和组件化爱奇艺这套题既然叫前端开发笔试工程化相关的内容也免不了。常见方向有CommonJS 与 ES Module 的区别、Tree Shaking 的原理、webpack 的构建流程、Vue/React 组件通信。CommonJS 和 ES Module 的区别是基础题但很多人的理解只停留在“一个是require一个是import”。深入一点CommonJS 是同步加载、动态加载、输出的是值的拷贝ES Module 是静态分析、异步加载、输出的是值的引用。这些差异直接决定了浏览器和 Node.js 对模块的处理方式不同。现在 Node.js 同时支持两种但.mjs与.cjs后缀不同行为也不同笔试有时候会出这个坑。关于组件化前端笔试可能给一段 Vue 或 React 代码问你父子组件如何通信、跨级组件如何通信、状态提升是什么。这类题目的核心是“单向数据流”父组件通过 props 向子组件传数据子组件通过事件回调通知父组件更新。如果项目里状态复杂再用全局状态管理Vuex/Redux/Zustand或者 Context/Provide-inject。能把这个逻辑讲清楚说明你在团队协作中不会乱写全局变量。4. 常见问题与排查技巧实录4.1 读代码题总“想当然”怎么办读代码题是踩坑重灾区。最常见的问题就是“还没理清变量提升就直接按从上到下的顺序读”。比如这段经典代码var name global; function printName() { console.log(name); var name local; } printName();如果你按顺序读会以为先打印global实际输出undefined。原因前面说过了函数内var name提升到顶部但赋值不提升。遇到这种“怎么和我想的不一样”的题先停下来把代码重写一遍把所有var声明提到作用域顶部再模拟执行。还有一个常见问题是忽略严格模式。如果代码开头有use strict那么this在独立函数调用中是undefined而不是全局对象。变量赋值时不声明会直接报错。很多人在普通模式下测没问题一旦环境切换就懵。所以做题时先看文件开头有没有严格模式标记这会改变整个执行结果。4.2 Promise 题老是排错顺序异步顺序题出错通常不是不知道“微任务先执行”而是没有区分 Promise 构造器中的代码和.then中的代码。新手的误区是以为new Promise里的代码也是异步的。实际上Promise构造器里的函数是同步执行的只有resolve或reject之后的.then回调才是微任务。举个例子new Promise((resolve) { console.log(inside); resolve(); console.log(after resolve); }).then(() { console.log(then); });输出顺序是inside、after resolve、then。resolve()只是把状态改为 fulfilled并不会立即执行.then函数体剩余代码仍然同步执行完。这个细节在笔试题里经常设陷阱回答的时候不要一看Promise就以为是异步。4.3 布局题老忘记“父容器尺寸不定”的情况CSS 笔试题的另一个高频失分点是忽略父容器没有固定高度/宽度时的表现。比如经典的“让子元素垂直居中”问题很多人直接写margin: auto但margin: auto只能在水平方向自动居中垂直方向需要display: flex或position transform配合。如果父容器没有设置高度垂直居中其实没有意义因为父容器高度由内容撑开。再比如flex: 1的含意很多人只知道“填满剩余空间”但不清楚它其实是flex-grow: 1; flex-shrink: 1; flex-basis: 0%的简写。笔试如果给你一个flex: 1和flex: auto的对比你要能解释区别flex: 1的 basis 是 0所以不会受内容固有尺寸影响flex: auto的 basis 是auto所以会优先基于内容尺寸分配空间。这一类细节平时写样式不注意做题必丢分。4.4 手写题“会写但没考虑边界”导致扣分手写代码题最容易出现“主流程对边界漏”的情况。比如写深拷贝只处理了普通对象和数组没处理null、Date、RegExp、循环引用就会被扣分。实际上面试官看手写题看的不是你“能不能写出来”而是你“能不能考虑全面”。我建议你面试前准备一个“模板库”把高频手写题都写成“带边界检查”的版本而不是网上抄个一行版就背。比如数组去重可以按“原始类型 引用类型 NaN”这三个维度来写Promise.all要确保“有一个 reject 就整体 reject”还要保证“传入空数组时返回一个已解决的空数组”。这些边界条件恰恰是日常写代码中最容易忽略的也是区分资深者和初学者的关键。5. 深度扩展这份笔试题的深层价值5.1 从笔试看大厂前端的能力模型把爱奇艺笔试题放到更大的视角下看它其实描绘了“大厂前端的能力模型”语言基础扎实、运行机制清楚、工程化意识强、边界意识好。这不是爱奇艺一家的要求而是整个行业对成熟前端工程师的通用预期。很多从业三年左右的前端工作里一直在写业务组件遇到问题就百度、CtrlC/V看起来什么都会但笔试一考就露馅。原因不是不聪明而是没有建立“原理到实践”的映射关系。比如用了无数次Array.prototype.map却答不出它和forEach的本质区别用了无数次display: flex却不清楚 Flex 容器的三条主轴交叉轴规则。这份笔试题就像一面镜子能照出你基础功底的薄弱环节。另外这套题对“学习路径”也有指导意义。如果你现在还是学生或者刚入行与其追热点学新框架不如先把 JS 高程、CSS 权威指南、HTTP 权威指南这些“老书”啃透。框架更新换代是常态而语言特性和浏览器机制是十年内都不会大变的地基。地基稳了学框架只是换个语法而已。5.2 针对不同阶段的备考策略对于在校生和应届生笔试准备的核心是“刷题 建错题本”。不要只闷头在牛客上刷题每次做错的题都要把“错误原因、正确推导、涉及知识点”记下来。过了两周再拿出来做一遍直到能独立推导出正确答案为止。针对爱奇艺这套题你可以关注高频考点但不要跳过你认为“简单”的部分因为笔试的坑往往就埋在简单题里。对于已经工作的前端备考重点应该放在“从原理角度重新组织答案”上。比如问你“什么是闭包”不要只回答“函数内部访问外部变量”而要能画出作用域链、说出内存回收的影响、举一个实际业务场景比如防抖、柯里化、组件内部函数。这样你在面试官追问时才能接得住。笔试是笔试面试是面试但能力模型是通的能把面试中讲清楚的东西写到纸面上才说明真的掌握了。5.3 我发现的高频规律与出题趋势如果把近年的大厂前端笔试题放在一起看会发现出题趋势非常明显越来越重视“真正的场景题”而不再满足于八股概念。所谓场景题就是“给一个具体业务问题让你设计实现方案”。比如“有一个搜索框用户输入后需要防抖搜索同时要处理竞态条件快速输入时只取最后一次结果你会怎么做”这类题考察的点已经超越了语言语法进入架构设计和边界思考层面。爱奇艺这套2019年笔试题虽然整体偏基础但已经能看到这种趋势的苗头。比如它会在代码题里设置“如果某个请求失败了怎么办”“如果这里传的参数是不确定的怎么办”等铺陈其实就是在考察边界处理。现在的笔试题更是直接甩场景实现一个带并发限制的异步调度器、实现一个 LazyMan、实现一个带超时的 fetch、实现一个可取消的 Promise。这些题目背后考察的都是抽象能力和工程思维。我个人判断未来前端笔试的难度还会继续上探但考点永远围绕“语言机制 异步控制 工程化 性能优化”这几条主线数据结构与算法也在逐渐加重。所以趁早补齐基础比临时抱佛脚刷题靠谱太多。5.4 心态调整笔试不是终点而是起点我见过不少候选人因为一套笔试题做崩了就直接放弃这其实挺可惜的。笔试做不好往往不是能力不行而是练习方式不对或者准备周期不够。你只要把笔试当作一次学习诊断把自己不会的题整理成专题一个个攻破效果远好于焦虑“我怎么这么菜”。另外提醒一句不要迷信“原题”。网上流传的题库再多也不可能押中所有面试题。真正稳妥的做法是把每道题背后的知识点当成一个“知识锚点”从这个锚点延伸出去把相关的概念、原理、应用场景全部复习一遍。比如遇到一道“改变函数 this 指向”的题你可以复习call/apply/bind的区别、手写bind、箭头函数、构造函数new的过程、React 类组件中 this 绑定的常见错误。这样一来一道题就变成了一套知识网络不管怎么变着问你都能应对。