ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

2020百度校招前端笔试题复盘:第三批试卷考点与备考指南

2020百度校招前端笔试题复盘:第三批试卷考点与备考指南 2020年百度校招前端笔试题复盘从第三批试卷看大厂到底想招什么人2020年秋季招聘季我参加了一次百度校招Web前端工程师的笔试拿到的是第三批试卷。当时做完最大的感受就是这场笔试和平时刷的LeetCode完全是两码事。它不考脑筋急转弯式的算法难题也不问“你知道哪些前端框架”这种泛泛而谈的问题而是把计算机基础、JavaScript语言特性、浏览器原理、网络协议、工程化实践全揉在一起逼你在有限时间里展示自己的真实水平。这份试卷对后来准备校招的人仍然有很强的参考价值。无论你现在是正在刷题的大三学生还是刚转行想做Web前端的开发者只要你想进大厂想搞清楚“前端笔试到底考什么”这篇复盘都可以当作一份路线图来用。我会结合当时考完后的回忆和后续反复查证的结果把试卷结构、核心考点、手写代码题拿分点、简答题答题套路一条一条拆开讲清楚。1. 第三批笔试卷的整体命题逻辑不是在考记忆是在考“有没有建立体系”1.1 试卷结构题型占比和大多数人的预期不太一样当年这套第三批试卷的题型分为四块单选题、多选题、简答题、编程题总分100分考试时长90分钟。很多人惯性思维觉得“大厂笔试肯定全是算法题”但百度前端岗的试卷恰恰不是这个风格。单选和多选占了将近40分简答题20分左右剩下40分左右是两道手写代码题。这个结构其实释放了一个很明确的信号校招前端岗更看重的基础知识广度、概念理解准确度、以及动手实现能力而不是纯粹的逻辑题刷题量。从考生回忆里综合来看各知识板块的占比大约是这样的知识板块大致分值占比典型考点JavaScript语言核心30%-35%闭包、原型链、this绑定、事件循环、类型转换浏览器与网络基础20%-25%渲染流程、缓存机制、HTTP状态码、跨域HTML/CSS基础10%-15%盒模型、定位、选择器优先级、Flex/BFC框架与工程化10%-15%React/Vue生命周期、Webpack原理、组件通信手写代码30%-40%Promise、深拷贝、防抖节流、事件总线等这个比例并不是官方公布的数字而是很多参加过考试的人复盘后的共同感受。它反映了一个规律大厂前端笔试的底层逻辑是“原理优先”。框架版本会变、API会变但JavaScript语言特性、浏览器工作原理、网络协议这些底层知识二三十年内都不会有大的变化。1.2 命题人想看到的不是“会用”而是“能解释为什么”我印象很深的是单选里有一道关于Promise执行顺序的题代码大概是console.log(1); setTimeout(() console.log(2), 0); Promise.resolve().then(() console.log(3)); console.log(4);输出顺序是1、4、3、2。如果只是背过“微任务先于宏任务”这句话这道题能答对但后面多选里继续追问“如果把setTimeout的第二个参数从0改成100输出顺序会不会变化”很多人就懵了。因为那已经不是在考定时器本身而是在考“事件循环里各个任务队列的调度机制”。题目不会直接问“什么是微任务”而是给你一段嵌套了三层Promise和两个setTimeout的代码让你选输出顺便在错误选项里埋一个“async函数里await后面的代码同步执行”的坑。类似的题目还有给出一个对象赋值表达式问原型链上属性查找的顺序给出一段使用var和let混合声明的循环代码问点击后输出什么。这些题表面上是语法题实际上是在检验你是否在脑子里建立了“JavaScript执行机制”的完整心智模型。如果你平时写代码全靠复制粘贴没想过变量提升、作用域链、任务队列这些概念第三批试卷的选择题部分会让你做得非常难受。1.3 这份试卷真正过滤掉的是哪一种人结合我自己和周围同学的反馈第三批试卷的区分度其实很高。它最大的特点就是不考偏题、怪题所有考点都写在常见的面试题清单里但每道题都稍微换了一层皮。比如“闭包”这个考点它不是让你说“闭包是什么”而是给你一个计数器工厂函数问多次调用后返回值是多少同时让你指出其中存在的内存泄漏隐患。再比如“跨域”它不直接问“怎么解决跨域”而是给你四个不同场景的请求让你选哪些会触发CORS预检请求。这种出题方式筛掉的人不是基础差的人而是“学过但没总结”的人。一个知识点如果你只是刷题时见过一次靠短期记忆记住了答案换个场景就不认识了那在第三批试卷里基本拿不到分。反过来如果学习的时候有意识地从“是什么、怎么用、为什么这样设计、会踩什么坑”四个维度去整理知识点这套试卷的选择题部分其实很容易拿高分。2. 选择题里的高频考点拆解这些细节最容易翻车2.1 作用域、闭包和this绑定永远绕不开的三兄弟作用域和闭包几乎是百度历年校招笔试卷里100%出现的考点第三批也不例外。当时有一道多选代码大概长这样var name global; var obj { name: obj, getName: function() { return function() { return this.name; } } }; console.log(obj.getName()());答案是global因为obj.getName()返回的是一个普通函数这个函数执行时没有调用者在非严格模式下this指向window。很多同学在这里栽了跟头原因是把“函数定义时的上下文”和“this的绑定规则”混为一谈。闭包能捕获变量但捕获的是词法作用域里的变量而不是this。this的指向只和调用方式有关和函数在哪定义、在哪返回都没有关系。这种题背后考察的其实是两条核心线索词法作用域链和this的四种绑定规则。准备这类题目的时候我建议不要光刷题而是亲手把下面几种情况写一遍看看输出分别是什么普通函数调用fn()严格模式下this是undefined方法调用obj.fn()this指向obj显式绑定fn.call(obj)、fn.apply(obj)、fn.bind(obj)new调用new Fn()this指向新创建的对象箭头函数不绑定自己的this沿用外层词法作用域的this这五种情况搞清楚了笔试里90%和this相关的题都不会再错。另外还要补充一个容易忽略的点var声明的全局变量会挂到window上而let、const声明的全局变量不会。所以上面那道题如果改成let name global输出就变成undefined了。这种细节不难但考试时很容易忽略。2.2 事件循环和异步机制微任务、宏任务与async/await事件循环在第三批试卷里考得非常多。选择题、编程题都有涉及而且题目的嵌套层级普遍比较复杂。比如一道选择题给了这样一段代码async function async1() { console.log(async1 start); await async2(); console.log(async1 end); } async function async2() { console.log(async2); } console.log(script start); setTimeout(() { console.log(setTimeout); }, 0); async1(); console.log(script end);这道题的输出是script start、async1 start、async2、script end、async1 end、setTimeout。核心就是记住await后面的代码相当于被放进了微任务队列要等当前宏任务执行完、微任务队列清空之后才会继续执行。也就是说async1 end不会在async2()执行完立刻输出而是要等当前同步代码跑完。很多人记不清楚“await到底等的是什么东西”这里有个更准确的理解方式await会暂停当前async函数的执行并把暂停点后面的部分封装成一个微任务。这个微任务要等两件事都完成才执行当前调用栈清空、Promise的状态变为resolve。如果await后面跟的是一个已经是resolve状态的Promise微任务依然要等当前宏任务结束才能执行不会提前。笔试里还喜欢把事件循环和“定时器延迟”结合考。setTimeout(fn, 0)并不是说fn一定会立刻执行而是最快也要等当前宏任务和所有微任务执行完毕。如果前面有一个非常耗时的重计算或者死循环定时器甚至可能无限期延后。理解了这一点很多“输出顺序”题就能做对不会落入“setTimeout一定先于Promise”的错误印象里。2.3 HTTP缓存和状态码选择题里最容易丢分的部分HTTP缓存相关考点在第三批试卷里占了不小的比重。它不像JS可以在浏览器控制台里即时验证很多同学面试前也没系统梳理过所以到了笔试现场只能靠猜。其实这个知识点只要把几个关键字段捋顺就能应对绝大多数题目。首先要区分两种缓存强缓存和协商缓存。强缓存阶段浏览器直接读本地缓存不发请求协商缓存阶段浏览器会向服务器发请求由服务器判断资源有没有更新。控制强缓存的字段主要是Cache-Control比如max-age3600、no-cache、no-store和Expires。控制协商缓存的字段主要是Last-Modified/If-Modified-Since和ETag/If-None-Match。考试时有个高频坑Cache-Control: no-cache到底是不是“不缓存”很多人想当然地认为no-cache就是不缓存实际上它表示“可以缓存但每次使用前必须向服务器确认资源是否新鲜”。真正的不缓存是no-store。这个概念如果没搞清楚选择题就会直接选错。HTTP状态码也考了几道包括301、302、304、403、404、500、502这些常见状态。第三批试卷里比较有迷惑性的一道题是浏览器向服务器请求一个静态资源服务器返回304问这次请求耗费了几次HTTP往返。答案是1次浏览器带上If-Modified-Since或If-None-Match发起请求服务器校验后返回304浏览器使用本地缓存。整个过程是一次请求不是两次。2.4 浏览器渲染机制和性能优化考点浏览器渲染这块第三批笔试既考选择题也考简答题。选择题一般给几个操作问哪个会引起重排reflow哪个只会引起重绘repaint。比如修改width、height、display、font-size这些属性会重排而修改color、background-color、visibility这些只重绘。这类题目有个判断诀窍只要属性变化影响元素的几何尺寸、位置或者导致周围元素布局变化就会重排如果只是视觉样式的变化不影响布局就只重绘。更准确地说重排几乎不可避免因为元素的color变化虽然不改变布局但在某些情况下浏览器为了确保渲染正确也会触发布局计算。笔试层面上掌握最常见的几组即可。还有一道让人印象深刻的题在不断触发滚动事件的场景下是选择防抖debounce还是节流throttle。正确答案是节流。因为防抖的逻辑是“停止触发后等待一段时间才执行”如果用户一直滚动那么回调可能永远不执行节流则是“固定时间间隔内最多执行一次”适合滚动、resize这类高频、持续触发但必须定期响应的场景。这种题考的已经不单纯是API背没背而是对“用户行为模型”的理解。3. 手写代码题能跑通只是及格边界和异常处理才是加分项3.1 第一道编程题手写深拷贝考的不只是递归第三批试卷的第一道编程题是“实现一个深拷贝函数”。看到题的时候大多数人第一反应是简单递归遍历对象复制属性。但真正写起来会发现这题要拿满分很难。满分标准至少包含下面几层基础递归实现function deepClone(source) { if (source null || typeof source ! object) { return source; } const target Array.isArray(source) ? [] : {}; for (let key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] deepClone(source[key]); } } return target; }这版能处理普通对象和数组但几个问题很明显没有处理循环引用遇到Date、RegExp、Map、Set这些特殊对象时行为不对而且for...in会遍历到原型链上的可枚举属性。虽然我用hasOwnProperty过滤了但真正打分时评委更看重的是你有没有意识到这些问题。当时我在这道题里加入了循环引用的检查用了一个WeakMap来记录已经被拷贝过的对象function deepClone(source, map new WeakMap()) { if (source null || typeof source ! object) { return source; } if (map.has(source)) { return map.get(source); } const target Array.isArray(source) ? [] : {}; map.set(source, target); const keys Reflect.ownKeys(source); for (const key of keys) { const descriptor Object.getOwnPropertyDescriptor(source, key); if (descriptor value in descriptor) { target[key] deepClone(source[key], map); } else { Object.defineProperty(target, key, descriptor); } } return target; }为什么用WeakMap而不是普通Map因为WeakMap的键是弱引用不会阻止对象被垃圾回收这样既解决循环引用问题又不会造成内存泄漏。这个细节如果能在代码注释里写出来评卷人一眼就能看出你理解得是否深入。3.2 第二道编程题手写Promise.all或EventEmitter第三批的编程题二考生回忆中比较多的版本是“实现一个简易的Promise.all”以及“实现一个EventEmitter事件发布订阅”。两道题二选一或者都出现的情况都有。以Promise.all为例大多数人的第一版是这样Promise.myAll function(promises) { return new Promise((resolve, reject) { const results []; let count 0; for (let i 0; i promises.length; i) { Promise.resolve(promises[i]).then(value { results[i] value; count; if (count promises.length) { resolve(results); } }, reject); } }); }这个版本基本能跑通正常场景但有几个边界值得补充如果传入的数组是空的应该立即resolve一个空数组如果某个promise已经是普通值要用Promise.resolve包装then的第二个参数是reject处理但更常见的是用.catch统一捕获避免某个promise的reject没有被正确处理导致整体卡死。我当时的最终版本还处理了一个很多人忽略的细节promises参数本身可能不是一个数组而是一个可迭代对象更严谨的写法是先用Array.from转成数组。另外如果promises里某一项是thenable对象Promise.resolve也会把它转换成Promise这个步骤不能省。这类手写题看起来简单但对细节的考察非常密集。评卷人一般不会跑测试用例而是直接看代码重点看三样东西有没有考虑边界情况、有没有错误处理、代码风格是否干净清晰。所以写的时候不要追求行数少而是把正常路径、异常路径、空值、非数组输入都处理到位。3.3 手写题里最隐蔽的坑会把API背得很熟但不理解参数语义第三批试卷里还出现过一道看起来不太难但错误率极高的小题实现一个防抖函数。很多人直接写function debounce(fn, wait) { let timer null; return function(...args) { clearTimeout(timer); timer setTimeout(() { fn.apply(this, args); }, wait); } }这道题的考点是返回函数内部的this必须正确。如果直接用fn.apply(this, args)这里的this是返回函数执行时的调用者这是对的。但有些人会把fn直接放在setTimeout里执行写成timer setTimeout(() { fn(args); }, wait);这样既丢失了this也把参数数组当成了单个参数传入。虽然面试官可能不会真的去运行代码但一眼就能看出对JavaScript函数调用方式理解不透。这类题目我建议平时练习时一定要在浏览器里实际跑一遍加几个不同的调用场景输出结果验证对了才算真正掌握。4. 简答题的答题套路结论先行、原理铺路、实践收尾4.1 “从输入URL到页面渲染完成经历了什么”这道题是第三批试卷简答题里最经典的一道几乎每家大厂前端笔试都爱出。它看起来简单但拿高分不容易。常见的低分答案是贴一段网上看过的流程DNS解析、TCP连接、HTTP请求、服务器响应、浏览器渲染。完。这种答案就算每一步都对分数也高不了因为没体现深度。我当时的答题思路是分层展开请求阶段用户输入URL浏览器解析协议、域名、端口、路径。注意现代浏览器会在输入URL前做搜索意图判断如果输入的不是合法URL会直接走搜索。合法URL则先查DNS缓存浏览器缓存、系统缓存、路由器缓存、根域名服务器逐级查询拿到IP后如果是HTTPS还要做TLS握手。如果是HTTP/2还会多路复用多个请求共用一条TCP连接。网络传输阶段建立TCP连接时三次握手的过程要写清楚——SYN、SYN-ACK、ACK。为什么是三次而不是两次因为要防止历史重复连接请求突然到达服务器导致资源浪费。这个追问在简答题里也出现过如果你只是背了“三次握手”四个字追问就会露馅。服务器处理与响应服务器返回HTML、CSS、JS文件响应头里的Content-Type、Cache-Control、ETag这些字段会影响浏览器后续的缓存行为可以顺手提一句。浏览器渲染阶段收到HTML后先解析HTML构建DOM树同时解析CSS构建CSSOM树两者合并成渲染树。这个过程中如果有script标签默认会阻塞DOM解析所以有defer和async两种优化属性。布局阶段计算每个节点的几何位置绘制阶段生成Paint Layers最后合成线程把图层合成输出到屏幕。如果答题篇幅允许我建议再补充一条为什么CSS要放在head里JS要放在/body前或者使用defer。这叫“理论联系实际”不仅说明你懂原理还说明你平时写页面时有意识地在运用这些原理。4.2 “谈谈你对前端工程化的理解”这道题在2020年这批试卷里出现频率很高第三批也有。很多人在校期间只用过Vite或者Create React App对工程化只有一个模糊概念于是答案变成“Webpack可以打包文件、Babel可以转译ES6”一句话带过。这种答案分数很低。我建议把工程化拆成几个层次去答开发层模块化开发ES Module和CommonJS的区别组件化设计状态管理、路由、按需加载。构建层依赖分析、代码转译、代码分割、Tree Shaking、资源压缩。这里可以结合Webpack的Loader和Plugin机制来谈Loader负责对模块源码进行转换Plugin解决Loader解决不了的事情比如打包优化、资源管理、环境变量注入。质量与规范层ESLint、Prettier、单元测试、CI/CD。前端工程化不只是解决“代码怎么组织”更是解决“多人协作时怎么保证代码质量和可维护性”。部署层静态资源上传CDN、缓存策略、灰度发布、版本回滚。这样一个框架答下来既显示了知识广度又展示了结构化思维。阅卷人看简答题其实是在看你的思维模型清不清晰。同样一个知识点罗列型答案和框架型答案分数差距会很大。4.3 “设计一个登录组件/弹窗组件你会考虑哪些因素”简答题还经常出这种组件设计题。它不是让你写代码而是考察“当你要在真实项目里做一个组件时会不会想全边界情况”。我总结的答题维度是功能边界、状态管理、无障碍、性能、可维护性。以弹窗组件为例功能和样式支持标题、内容、底部按钮自定义点击遮罩是否关闭、按Esc是否关闭、关闭时是否有回调。状态管理弹窗的打开/关闭状态由父组件控制还是组件自身控制是否支持受控和非受控两种模式。无障碍弹窗打开时焦点是否移入面板、关闭时焦点是否归还给触发按钮、是否设置了aria-modal。性能滚动锁定怎么做overflow: hidden和position: fixed各有什么副作用弹窗内容是否懒挂载。复用和扩展能否通过API传入任意内容而不是写死结构。答题时不要把所有点全列出来没有重点建议开头先用一句话定性“一个合格的弹窗组件不只是视觉功能更需要处理好焦点管理、滚动锁定和状态同步”然后再展开。这种答案会让阅卷人觉得你有真实项目经验而不是临时背题。5. 考完第三批之后我对“前端学习路线”重新做的调整5.1 2020年这张试卷反映出来的“人才标准”变化以前总有人说前端门槛低会写页面就行。百度2020校招第三批这张试卷直接把这种观点否掉了。它的题目横向覆盖了计算机网络、浏览器内核、JavaScript语言规范、现代工程化体系纵向又要求手写代码有工程级质量。这背后的人才标准已经从一个“能实现页面的人”变成了“能理解整个Web运行链路的人”。我举一个细节有一道多选问的是“哪些操作会导致浏览器发起跨域预检请求”正确答案包括使用fetch且自定义了非简单请求头、Content-Type为application/json、使用了PUT/DELETE方法。而“使用form表单提交”和“使用img标签请求”不会触发。这种问题如果没做过实际的前后端分离项目光靠背是容易记混的。所以笔试筛的其实是“真实项目经验”不只是“刷题量”。这也解释了为什么很多计算机基础扎实、但没怎么做过Web项目的同学笔试成绩反而不如那些经常写小项目、踩过坑的“野路子”选手。原因是后者在实践里被迫理解了那些底层概念而前者只是“知道”那些概念。5.2 我给备考同学的一份“优先级清单”如果你现在正在准备校招前端岗想按第三批试卷透露出来的思路来备考我建议把这几个方向按优先级排一排优先级备考内容原因P0JavaScript语言核心作用域、this、原型链、异步、类型转换选择题、手写题、简答题全面覆盖P0浏览器渲染机制和性能优化简答题高频考点也是项目优化的理论依据P0HTTP协议、缓存机制、跨域大厂必考且容易形成区分度P1手写常见工具函数深拷贝、防抖节流、Promise系列、事件总线笔试编程题直接考需要达到默写水平P1现代框架原理React或Vue的响应式、生命周期、Diff简答和面试会追问笔试选择题占比不大P2工程化工具的使用和原理Webpack、Vite、Babel简答题常考但选择题涉及不多P2TypeScript2020年考得不多但之后越来越重要照着这个清单去分配时间比漫无目的地刷题效率高很多。尤其是P0层级的内容几乎每一场前端笔试都会遇到。5.3 我的一个私藏方法用“给自己讲一遍”代替单纯刷题备考期间我一直在做一件事每学完一个知识点不急着做下一题而是关掉浏览器尝试把这个知识点用最直白的话讲给一个“完全不懂前端的人”听。比如讲事件循环我会说“JavaScript是单线程的但浏览器背后还有定时器线程、网络线程。等你当前的代码跑完浏览器就会把定时器回调、Promise回调按顺序取出来执行。Promise的回调永远排在定时器回调前面。”这个方法听起来很笨但效果奇好。因为在讲的过程中发现自己讲不通的地方就是理解最薄弱的地方。第三批试卷里那些“代码输出顺序题”如果我能一句话把事件循环讲清楚做题的时候基本不用一步步推扫一眼就能凭直觉选出来。这种直觉不是天生的是反复输出练出来的。5.4 考完之后我才意识到一份试卷的价值不在分数在“查漏清单”最后说说心态。当年考完第三批试卷我大概能估到自己的正确率也就七成左右但我没有陷入“完了这波进不了面试”的焦虑反而当天晚上就拿了张纸把所有拿不准的题对应的知识点列了出来事件循环里微任务嵌套、Cache-Control的no-cache语义、Object.create(null)与普通对象的区别、WeakMap的弱引用特性、Compositor线程在渲染管线里的位置。列了差不多20条。这份清单后来成了我整个秋招复习的核心。我对着它一个一个查漏补缺比任何网课和题库都更有针对性。所以如果你现在也在准备笔试考完之后千万别只对一对答案就完事更别把希望寄托在“多刷几套题”上。正确的做法是每考完一套就把“不确定的题”变成“知识点的漏洞清单”再逐一击破。这才是校招笔试真正带给你的成长。回头看2020年百度第三批那张试卷题目本身已经有些模糊了但那种“每一道题都在提醒我前端工程师不能只做一个页面拼接工”的感觉我到现在还记得。它会让你重新审视自己学过的每一个知识点是真的懂了还是只是看着眼熟。想明白这一点哪怕笔试没过这一趟也值了。
返回列表