2017字节前端笔试考点全解析:从事件循环到算法实战
发布时间:2026/8/29 22:13:03 作者:尧图编辑部 阅读量:1,286

1. 2017年字节前端笔试到底在考什么说实话看到这个标题我愣了一下。2017年那会儿字节跳动还叫“今日头条”前端团队规模远没有现在这么夸张但招人标准已经透着一股“不好糊弄”的劲儿。那年我正好在准备校招印象里刷过不少大厂笔试题字节这家的风格在当时就挺特别——不跟你玩虚的上来就是实打实的代码基础、网络协议、框架原理偶尔还掺一道让你挠头的算法题。现在回过头来看2017年的笔试题其实有很强的时代特征。那一年Vue 2.x如日中天React 16刚发布Fiber架构TypeScript还没大面积普及前端工程化正在从“Webpack配起来麻烦”走向“Webpack标配”。所以笔试题目里你能看到大量ES6语法、闭包、原型链、事件循环、HTTP缓存这些老生常谈但永不过时的东西同时也会有几道跟框架源码实现相关的题目考察你是不是真的用过还是只停留在“会写页面”的层面。这篇博文我想以当年的题目为引子带着大家逐类拆解把每道题背后的考点、踩坑点、以及放到2024年再看还有没有价值全部捋一遍。不吹不黑就算你现在不准备面试纯当复习JavaScript基础这波也不亏。2. 考点地图整张卷子的出题逻辑拆解2.1 从题目分布看字节的用人标准先说整体感受。2017年字节前端实习生笔试题型大概是这样的结构单选多选基础知识、代码补全或输出题JavaScript机制、简答或手写题框架原理或原生API实现、一道算法题通常是数组/字符串操作难度在LeetCode easy到medium之间。这份题目的分布其实非常有意思。单选题里大量考察CSS布局flex、BFC、盒模型、HTTP状态码、浏览器渲染机制多选里经常出现ES6新特性、作用域、this指向这类“背了就会不背就懵”的题目到了代码输出题就是考察事件循环Event Loop、闭包陷阱、原型链查找这些真正区分水平的内容最后的手写题和算法题则是考察你平时有没有真的写过代码、能不能在有限时间内把思路落地。从出题逻辑来看字节在2017年就展现出一种务实导向不考偏题怪题但每一道题都对应一个实际开发中会用到的知识点。比如HTTP缓存那题做前端怎么可能不跟缓存打交道比如事件循环输出题异步编程写多了自然能答对。这种风格也一直延续到了后来的面试中——字节的面试官特别喜欢问“你项目中遇到过什么问题怎么解决的”本质上是在验证你是不是一个“真做过”的人。2.2 跟同时期其他大厂题目的横向对比2017年那会儿我也刷过阿里、腾讯、网易的笔试题说实话各家风格差异挺明显的。阿里的题偏重业务场景和技术广度的结合经常给你一个具体业务需求让你设计方案腾讯的题偏重工程化和Node.js方向问了很多模块化、构建工具的问题网易则相对传统基础知识占比很大算法题也比较温和。字节的题目给我的感觉是基础打得非常深同时留了一道“加分项”题。什么意思呢就是前面大部分的题目只要你把JavaScript核心机制搞透了拿高分并不难但最后那道算法题或者那道让你手写一个防抖节流/深拷贝/发布订阅的代码题才是真正把候选人区分开的地方。这其实反映了字节早期招人的一个理念基础学科要扎实但更看重你在未知问题面前的应对能力——技术涨得快的人往往不是知识面最广的而是底子最牢的。2.3 这些考点放到2024年还有效吗我先把结论放在这里大部分考点放到今天依然有效但考察形式已经升级了。比如“事件循环输出题”2017年考的是setTimeout和Promise混用现在面试官会直接打开浏览器让你现场答还会追问宏任务微任务的执行顺序在不同浏览器里的差异比如“手写深拷贝”当年只要写出递归版本就差不多了现在你得考虑Symbol、函数、循环引用、不同类型分别怎么处理。这种变化其实给了我们一个很实用的复习思路以经典考点为骨架用最新技术栈和工程经验去填充血肉。只要把底层原理吃透了面试形式怎么变都不怕。3. 高频题型精讲JavaScript核心机制3.1 事件循环一道题定胜负的经典款先说所有笔试题里最容易出现、也最容易拉开分差的一类——事件循环输出题。2017年字节的题目大概是这种风格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);问你输出顺序。这道题放到今天已经属于“送分题”了但在2017年很多人是真的答错——尤其是对“Promise的then回调属于微任务比setTimeout的宏任务先执行”这件事没有清晰的认知。输出顺序是script start script end promise1 promise2 setTimeout为什么因为JavaScript执行主线程代码时遇到setTimeout会把回调丢进宏任务队列遇到Promise则把then回调丢进微任务队列。主线程代码执行完毕同步任务清空后会先清空所有微任务然后再取一个宏任务执行。所以promise1和promise2会排在setTimeout前面。这种题目在2017年笔试里属于“必考题型”而且往往会升级一下变成Promise嵌套、async/await混用、或者多个setTimeout和Promise交叉出现。我当时总结的答题口诀是先同步再微任务最后宏任务微任务里如果又产生了微任务就地执行宏任务取一个执行一个每次执行完宏任务都要回头看看有没有新产生的微任务。这里有一个非常隐蔽的坑new Promise里的执行器函数是同步执行的只有resolve调用之后的then部分才是异步的。很多人一看到Promise就以为整段都是异步的导致输出答错。3.2 闭包陷阱for循环里的var和let另一类高频题是闭包和作用域尤其是这个经典场景for (var i 0; i 5; i) { setTimeout(function() { console.log(i); }, 100); }输出是什么答案是5个5。原因很简单var声明的i是函数作用域5次循环共用同一个isetTimeout回调执行时循环已经结束i已经变成了5所以全部打印5。那怎么改成输出0、1、2、3、4当年的标准答案是使用IIFE立即执行函数来保存每次循环的i值for (var i 0; i 5; i) { (function(j) { setTimeout(function() { console.log(j); }, 100); })(i); }因为IIFE每次循环都会创建一个新的函数作用域参数j把当前的i值“冻结”了下来。这题的升级版是如果把var换成let会怎样答案直接输出0、1、2、3、4因为let是块级作用域每次循环都会创建一个新的绑定。我之所以单独把这道题拎出来讲是因为它考察的不只是“记不记得这个写法”而是你对JavaScript作用域机制的理解深度。2017年很多候选人能写出IIFE的解法但被问到“为什么IIFE能保存值”时就卡壳了。到了2024年前端面试已经很少直接考这种题了但它背后的原理——闭包、作用域链、变量提升——依然是一切JavaScript框架和工具链的基石值得花时间彻底搞懂。3.3 原型链与this指向判断一下构造函数和普通函数原型链和this指向也是2017年笔试的常客。典型的题目是function Foo() { this.name foo; } Foo.prototype.getName function() { return this.name; }; var foo new Foo(); console.log(foo.getName()); console.log(foo.hasOwnProperty(name)); console.log(foo.hasOwnProperty(getName));第一行输出foo这个没悬念关键是后面两行name是实例自身属性所以hasOwnProperty返回truegetName在原型上不在实例上返回false。升级版的this指向题大多是判断“在严格模式和非严格模式下普通函数调用时this分别是什么”或者“箭头函数里this指向哪里”。我见过最狠的一道是组合题一个对象的方法里返回一个箭头函数让你判断箭头函数里的this——答案是箭头函数没有自己的this它捕获的是定义时外层作用域的this也就是对象方法的this。这种题考察的核心是**“判断this指向的唯一方法是看函数怎么被调用而不是看它在哪里定义”**箭头函数例外。我当年刷题时总结了一个判断顺序先看new调用再看call/apply/bind调用然后看对象方法调用最后才是普通函数调用严格模式undefined非严格模式指向全局对象。箭头函数单独记忆定义时决定无法改变。4. 框架与工程化题目从“会用”到“懂原理”4.1 Vue响应式原理Object.defineProperty的经典那年2017年笔试里出现Vue相关的题一点都不意外。那一年Vue 2.x是绝对的霸主题目考察的焦点基本都集中在响应式原理上。典型问法是Vue中data里的数据是怎么做到变化后自动更新视图的标准答案的核心是Object.defineProperty。Vue 2在初始化data时遍历所有属性用Object.defineProperty把它们转换成getter/setter。每个组件实例都有一个Watcher当模板渲染时读取了某个属性就会触发getter把这个Watcher收集进该属性的依赖列表里当属性被修改时触发setter通知所有收集到的Watcher去更新视图。当年笔试的进阶问法是为什么Vue 2不能检测到新增属性和数组下标赋值因为Object.defineProperty是在初始化时就为已有属性绑定的新增属性没有经过这个绑定过程所以不是响应式的。数组的下标赋值同理——官方文档直接建议用Vue.set或者this.$set来新增响应式属性。放到2024年回头看Vue 3已经全面转向Proxy实现响应式解决了无法检测新增属性这个痛点但Vue 2这套机制的题目在历史技术栈较多的公司里依然可能出现。而且这道题的价值不在于“背答案”而在于它能考察你对“数据驱动视图”这件事的理解深度——不管用的是Vue 2还是Vue 3框架都在解决同一个问题如何用声明式的方式高效地建立数据和UI之间的关联。4.2 Webpack与模块化构建配置的基本功2017年的前端笔试Webpack已经是绕不开的话题。当年最常见的Webpack题目是简述Webpack的打包原理配置过哪些loader和plugin分别解决什么问题如何做代码分割。Webpack本身是个非常庞大的工具笔试题一般不会让你手写完整配置但会考你对几个核心概念的理解entry入口、output输出、loader模块转换器、plugin插件、mode模式。常见loader包括babel-loaderES6转ES5、css-loader解析CSS中的import和url、style-loader把CSS注入DOM、file-loader和url-loader处理图片字体等静态资源。常见plugin包括HtmlWebpackPlugin自动生成HTML并注入打包后的脚本、MiniCssExtractPlugin提取CSS为单独文件、UglifyJsPlugin或TerserPlugin压缩代码。面试官真正想考察的是你有没有从一个“写页面的人”进化为一个“工程项目负责人”的认知。比如问你“怎么把首屏加载时间降下来”你如果能说出“代码分割路由懒加载第三方库单独打包利用浏览器缓存”这一套说明你真的在项目里思考过性能问题。我当时的建议是刷这类题之前至少要看一遍Webpack官网的Concept文档然后自己手动搭一个包含babel、sass、图片处理的小型配置不用很复杂但对理解loader和plugin的工作结界非常有帮助。没有实际跑过一遍打包流程纯背概念很容易在追问环节露馅。4.3 手写题防抖节流、深拷贝、发布订阅笔试的代码手写题简直是考察候选人代码功底的照妖镜。2017年字节的题目里让我印象最深的是手写防抖和节流。这两者的区别我在面试时被问过无数次也见过无数人答混。先放我的标准答案。防抖debounce的核心思想是在事件被连续触发时只有最后一次触发后的等待时间内没有再触发才执行函数。典型场景是输入框搜索。function debounce(fn, delay) { let timer null; return function(...args) { const context this; if (timer) clearTimeout(timer); timer setTimeout(() { fn.apply(context, args); }, delay); }; }节流throttle的核心思想是在单位时间内只执行一次函数。典型场景是滚动事件和窗口resize。function throttle(fn, interval) { let last 0; return function(...args) { const context this; const now Date.now(); if (now - last interval) { last now; fn.apply(context, args); } }; }注意两个细节第一都要用...args把参数透传进去并且用fn.apply(context, args)绑定调用时的this第二防抖是“清空重来”节流是“时间到了才执行”——很多人把这两者弄反一写就错。现在很多公司已经不满足于手写基础版了会追问”防抖能不能加上立即执行功能“或者“节流如果最后一次没执行要不要补一次”。这些追问本质上是在考察你是否理解这个工具的内在逻辑而不是背模板。我在实际项目中见过不少因为防抖和节流混用导致的bug——比如搜索框既要防抖又要节流、滚动加载既要节流又要判断到底部稍不留神就会出问题。最好的方式是自己封装一套带配置项的通用函数把边界情况都处理掉一劳永逸。5. 算法与数据结构的实战应对策略5.1 高频算法题的优先级排序2017年字节前端实习生笔试的算法题难度总体不超过LeetCode easy到medium。但别小看它——我当年参加笔试的时候就栽在了一道看似简单的字符串题上原因是审题不仔细漏掉了“字符去重”这个条件白白丢了分。根据我刷题和笔试的经验前端笔试的高频算法题可以按优先级排序数组操作去重、扁平化、排序、求交集并集差集。这些和日常开发最贴近几乎每次笔试都会遇到。字符串处理反转、回文判断、字符统计、模板替换。看起来简单但边界条件多容易漏。基本数据结构链表反转、栈实现队列、二叉树层序遍历。考得不多但一旦考了就是分水岭。动态规划和贪心爬楼梯、最大子序和、买卖股票最佳时机。出现概率较低但备考时值得刷一遍。我的策略是数组和字符串题天天练数据结构题每周保持手感动态规划题看缘分——如果备考时间只有一周优先把前三类练透比刷20道DP题更划算。5.2 笔试中的“陷阱题”复盘一次性通过的经验笔试中的算法题和面试时的白人板写题有一个很大的区别笔试是线上OJ判题输出格式要求非常严格多一个空格、少一个换行都可能判错。我吃过这个亏所以特别提醒准备笔试的同学平时刷题时尽量用标准输入输出别只写一个函数。多花30秒读题和确认输出格式比写错了再debug快得多。另外笔试环境一般都有“运行代码”和“提交”两个按钮我建议你在提交之前多跑几组自造的边界用例比如空数组、只有一个元素、全是重复值、负数、超大数。尤其是字符串题空字符串和包含空格的字符串是两大经典坑别问我是怎么知道的。5.3 以一个经典题目为例演示完整解题过程来一道当年非常经典的题目给定一个字符串找出其中不含有重复字符的最长子串的长度。 示例 输入: abcabcbb 输出: 3 解释: 因为无重复字符的最长子串是 abc所以其长度为 3。这道题在LeetCode上是第3题滑动窗口的经典应用。解题思路很简单但第一次见到的人不一定能想到用两个指针left和right维护一个窗口right向右扩展每次把字符放入一个Set中如果窗口内出现重复字符就不断移动left并删除对应的字符直到窗口内不再有重复。整个过程用一个变量记录窗口的最大长度。function lengthOfLongestSubstring(s) { const set new Set(); let left 0; let maxLen 0; for (let right 0; right s.length; right) { const char s[right]; while (set.has(char)) { set.delete(s[left]); left; } set.add(char); maxLen Math.max(maxLen, right - left 1); } return maxLen; }时间复杂度O(n)空间复杂度O(min(n, 字符集大小))。这题如果笔试中出现写出来基本就能确保在算法题这一项拿高分。6. 报考字节前你需要知道的备考策略与时间规划6.1 知识图谱一张表理清复习优先级网上关于前端面试的资料很多但大多数过度堆砌反而让人抓不住重点。根据2017年字节笔试题的考纲以及后来几年我对字节面试风格持续的关注我整理了一张优先级表格供你参考优先级知识点复习方式易错点P0JavaScript事件循环、闭包、作用域、原型链、this指向刷题 看执行机制解析Promise微任务和setTimeout宏任务的顺序P0数组/字符串手写方法、常见算法题LeetCode两题/天边界条件、输出格式P1HTTP缓存、浏览器渲染机制画流程图 背诵关键字段Cache-Control和Expires的区别P1Vue/React响应式原理或组件通信配合手写源码题复习对useEffect/Vue生命周期理解停留在API层P2Webpack构建配置手动搭一个简单工程loader和plugin的职责边界P2TypeScript基本语法加分项学习interface和type的区别泛型使用不熟练P0是我认为无论笔试题型怎么变都必须掌握的内容P1是前端工程师的职场基本功P2则属于“不会扣分、会了加分”的加分项。按这个优先级复习效率最高。6.2 以“刷题为主、看书为辅”的21天备考模板时间规划方面如果你有21天的准备时间我建议这样安排第一周基础巩固期每天3小时2小时刷JavaScript核心机制的题目事件循环、闭包、this、原型链1小时刷LeetCode数组和字符串题。周末做一套完整的模拟卷重点检查输出格式和答题节奏。第二周框架与工程化攻坚期每天2小时学习Vue或React的响应式原理、生命周期、组件通信方式1小时手动实现一个小工具库防抖节流、深拷贝、Promise.all周末用Webpack从零搭一个项目模板。第三周模拟冲刺期每天做一套真题或高质量模拟题严格计时90分钟。把容易错的题目整理成一个错题本考前重点看错题和易混概念。这个规划的核心逻辑是前期打牢基础中期强化工程实践后期全真模拟适应考试节奏。备考最忌讳的就是每天只看不写、或者只刷题不总结——前者到了笔试时手生后者容易在重复的知识点里浪费时间。6.3 关于“背题”和“懂题”的取舍最后聊聊一个比较主观但很重要的话题准备笔试到底该不该背题我的看法是概念题可以背代码题必须懂。像HTTP状态码、CSS属性这种记忆型内容死记硬背完全没问题因为它们的考察方式就是“你知不知道”没有太多推理空间。但像“手写防抖节流”“解释事件循环”这种题背模板只能让你拿到基础分一旦面试官在你的答案基础上做任何延伸追问背诵的痕迹就会暴露得很明显。最稳的备考方式是每一个核心代码题都自己默写三遍以上写到不假思索就能完整写出为止。然后试着换个提问方式看看自己能不能从不同的角度讲清楚这个工具的原理和设计动机。能做到这一步你面对的不只是一场笔试而是整个面试流程中所有关于“前端基础”的追问都可以从容应对了。7. 后记写给从2017年过来的前端人和准备入行的新人2017年距离现在已经有段时间了前端生态也发生了翻天覆地的变化。回头看我当年准备这些笔试题时写下的笔记很多工具和框架的名字已经变成了时代的注脚但JavaScript的核心机制、浏览器的工作原理、HTTP协议的缓存策略依然是每一位前端工程师躲不掉的必修课。如果你正在准备前端方向的校招笔试我的建议只有三条第一把JavaScript底层原理吃透这是所有框架和工具链的地基第二保持每天动手写代码的习惯算法题和手写题没有捷径唯手熟尔第三在笔试的90分钟里先做会做的题遇到卡壳的先跳过别让一道题打乱整场节奏。当年我参加笔试的时候在事件循环那题上掉了坑。后来刷了大量练习题又去翻了规范里关于宏任务和微任务的说明才算真正搞明白那套执行顺序机制。如今每次有人问我“前端笔试怎么准备”我都会把这道题作为第一个推荐案例——因为一道题考的不只是答案而是你在学习过程中是否愿意追根究底的态度。这份态度才是面试官真正想从笔试题里看到的东西。