刚参加完TME2024校园招聘前端方向的第一场笔试,趁着热乎劲还在,把整场考试的命题套路、考点分布、失分点复盘一遍。这篇文章既是一份笔试记录,也是一份前端校招备考地图——谁适合看?打算投大厂前端岗的应届生、正在刷题但方向感不强的同学,还有带新人的团队 leader 想了解现在校招笔试难度的,都可以参考。
先说结论:TME这场笔试整体属于“基础扎实就能过、想拿高分得靠综合能力”的类型。题型覆盖了计算机基础知识、JavaScript深度理解、框架应用、工程化场景题,没有偏题怪题,但每道题都往原理层面深挖了一层。换句话讲,背八股文能过初筛,想拿高分必须真懂。
1. 先说结论:这次笔试到底在考什么
1.1 题型分布与分值结构
整场笔试时间是120分钟,我拿到的是前端方向第一套卷,整体题量和时间配比还算合理。题型大致可以分为四块:
| 题型 | 题量 | 建议用时 | 考察方向 |
|---|---|---|---|
| 单选题 | 15道 | 30分钟 | 计算机网络、浏览器原理、JS语言基础 |
| 多选题 | 5道 | 10分钟 | 框架原理、工程化、安全 |
| 编程题 | 2道 | 50分钟 | 数据结构与算法、JS编程能力 |
| 简答题 | 2道 | 30分钟 | 场景设计、性能优化、框架原理 |
注意多选题比单选题危险得多,选错不得分、少选可能得一半分,但TME这场多选是“少选不得分”,也就是说漏选也算错。这个规则在开考前一定要看清,我见过不少同学在这上面吃大亏,明明会做,因为漏了一个选项直接整题扣光。
编程题是核心拉分项。两道题分值大约占总分的40%,一道偏数据结构(数组处理/链表操作),一道偏场景实现(手写函数/组件逻辑)。最后半小时如果还在单选上纠结,编程题大概率写不完——这是时间分配上最大的坑。
1.2 考点优先级:大厂前端笔试的选人逻辑
从这次试卷反推,TME前端岗位的笔试选人逻辑其实很清晰:基础能力是底线,工程化思维是加分项,原理理解深度决定上限。
先说基础能力。网络协议(TCP/UDP、HTTP状态码)、浏览器渲染机制、JS核心机制(原型链、闭包、事件循环、Promise)、ES6+语法,这些大概占了50%的分数。这类题的考察方式不是“背概念”,而是给出代码让你推结果,或者给一个场景让你判断行为。比如“以下代码输出什么”,每个选项都长得差不多,不深究底层原理很容易被绕进去。
再说工程化思维。Webpack构建流程、Vue响应式原理、组件通信、性能优化手段,这些以多选题和简答题形式出现,大概占30%。这类题没有标准死答案,考的是你平时写代码时有没有想过“为什么”。
剩余20%是算法和数据结构。TME这次考的题目难度中等偏下,一道是数组去重与排序的变种,一道是链表的环检测。比起LeetCode hard题,大厂笔试更看重“能否用代码解决实际问题”,所以刷题时不要死磕难题,把常见的数据结构操作写熟更重要。
1.3 前端开发skills:不只是写页面那么简单
很多同学对“前端开发”的理解还停留在写页面、调样式、接接口。但这次笔试反映出来的一个明显信号是:企业眼中的前端开发skills是一个复合能力集合。
从考点反推,TME至少希望候选人具备四个层次的能力。第一层是语言基本功:JavaScript语法、类型转换、作用域、异步模型,这是地基。第二层是浏览器和网络理解:从输入URL到页面展示中间发生了什么、浏览器缓存策略、事件机制,这些决定了你能否排查线上问题。第三层是框架和工程化能力:Vue或者React的原理、组件化设计思想、构建工具链,这些决定了你能否在团队里独立负责业务。第四层是软素质和场景设计能力:遇到性能瓶颈怎么办、如何设计一个高复用的组件、如何监控前端报错。
这套能力模型不只是TME的要求,绝大多数中大厂前端岗笔试都是这个思路。所以备考时不要只刷题,要把知识体系搭起来,每个知识点都要能回答“为什么这样设计”。
2. 计算机基础考点:笔试筛人的第一道闸
2.1 数据结构与算法:核心题型与答题节奏
TME这场笔试的两道编程题,一道是“数组扁平化加去重排序”的变种,一道是“判断链表是否有环并返回环的起点”。这两道题都是LeetCode上很经典的题目,难度不算高,但现场写的时候有几个细节值得注意。
数组那道题,题目大致是:给定一个多维数组,要求扁平化、去重、并按升序排序。看起来简单,但考点其实藏在三个细节里。第一,数组的维度不确定,循环嵌套解不了,得用递归或者flat(Infinity);第二,去重要考虑元素类型,数字1和字符串'1'是不是同一个元素?题目如果不明确,默认要靠Set去重但注意Set的严格相等机制;第三,排序要考虑是否有负数、是否要求稳定排序。
我当时写的是这样的版本:
function flattenUniqueSort(arr) { const flat = arr.flat(Infinity); const unique = [...new Set(flat)]; return unique.sort((a, b) => a - b); }这只是基础版,如果想让面试官眼前一亮,可以在flat、去重、排序三个环节都手写实现,体现你懂原理而不是只会调API:
function flatten(arr) { return arr.reduce((acc, cur) => Array.isArray(cur) ? acc.concat(flatten(cur)) : acc.concat(cur), []); } function unique(arr) { return arr.filter((item, index) => arr.indexOf(item) === index); } function sort(arr) { if (arr.length <= 1) return arr; const mid = arr[Math.floor(arr.length / 2)]; const left = arr.filter(x => x < mid); const right = arr.filter(x => x > mid); return [...sort(left), mid, ...sort(right)]; }再说链表环检测那道题。现场手写快慢指针解法,网上有大量模板,这里不再贴代码。想提醒的是:笔试环境的代码补全能力很差,没有IDE的自动提示,所有的API和方法名都要靠记忆。平时刷题最好在无提示环境下练几遍,这样上考场不会因为拼写错误浪费时间。
2.2 网络与浏览器:高频概念题背后的考察意图
网络和浏览器是笔试单选的重灾区。TME这场覆盖了TCP三次握手、HTTP与HTTPS区别、HTTP缓存策略、浏览器渲染流程、事件循环等高频考点。
一个让我印象深刻的题目是:“输入URL到页面展示,中间发生了什么”。这题作为简答题出现,考察的是系统性思维。完整的答题链条应该是:
- DNS解析:把域名解析成IP地址,涉及浏览器缓存、系统缓存、路由器缓存、DNS服务器递归查询。
- 建立TCP连接:三次握手,确认双方的接收和发送能力正常。
- 发送HTTP请求:携带请求头、请求体,经过负载均衡到达服务器。
- 服务器处理并返回响应:涉及后端处理逻辑、CDN命中、缓存策略。
- 浏览器解析并渲染:HTML解析成DOM树、CSS解析成CSSOM树,合成RenderTree,布局绘制。
这道题答得好不好,不在于背得多完整,而在于每一个环节能不能展开讲两层。比如说到缓存策略,能不能说清楚Cache-Control的max-age和ETag的区别?说到渲染,能不能解释什么是回流和重绘、什么时候触发?这些都是连环追问的素材,面试官通过笔试回答就能判断出你的知识深度。
2.3 浏览器缓存:一道必考但容易混淆的概念题
浏览器缓存策略值得单独拿出来说,因为这是笔试高频中的高频。TME这场虽然没有直接考缓存的大题,但选择题里出现了,而且选项设计非常容易混淆。
核心知识点其实就两类:强缓存和协商缓存。强缓存是浏览器直接用本地副本,不发请求,由Expires(HTTP/1.0)或Cache-Control: max-age(HTTP/1.1)控制。协商缓存是浏览器拿本地资源的标识去问服务器“这个资源还能用吗”,能用就返回304,不能就用200返回新资源,标识字段是Last-Modified/If-Modified-Since(时间戳维度)和ETag/If-None-Match(内容哈希维度)。
选择题最常挖坑的地方是问你“如果服务端同时返回了Cache-Control: no-cache和ETag,浏览器会怎么处理”。正确答案是:no-cache的意思是“可以缓存,但每次使用前必须向服务器验证”,所以浏览器仍然会缓存资源,但每次请求都需要走协商缓存逻辑。注意no-cache不等于no-store,后者才是完全不缓存。
备考这块最好的方式不是死记字段,而是打开浏览器DevTools的Network面板,随便找一个线上网站刷新两次,观察哪些资源是从memory cache、disk cache、304来的,把现象和原理一一对应,记忆会深刻很多。
3. JavaScript进阶:校招前端笔试的重头戏
3.1 原型链、闭包、this与作用域:必须拿到满分的送分题
JavaScript基础题占的比重最大,但也是最好拿分的部分——前提是你真的理解了。TME这次考了“箭头函数里的this指向什么”和“经典循环闭包问题”,都是稍有JS开发经验就应该答对的题。
先说一下箭头函数的this问题。箭头函数本身没有自己的this,它捕获的是定义时外层作用域的this。看下面这个代码:
const obj = { name: 'TME', getName: function() { return () => { console.log(this.name); }; } }; const fn = obj.getName(); fn(); // 输出什么?答案是TME。因为getName的调用者是obj,所以它的this指向obj,而箭头函数捕获了外层的this。如果把getName改成箭头函数,结果就变成undefined了——因为obj.getName是箭头函数,它没有自己的this,会捕获全局作用域的this。
再看经典循环闭包问题:
for (var i = 0; i < 5; i++) { setTimeout(() => console.log(i), 1000); }输出的是5个5。原因是var声明的i是函数作用域,循环结束后i已经变成5,所有定时器回调共享同一个i。改成let声明就能输出0到4,因为let是块级作用域,每次循环都会创建一个新的绑定。
这类题目看似简单,但出错率很高。我在笔试时就有一道多选问“哪些方式能让上面的定时器输出0到4”,选项包括let、立即执行函数传参、bind传参、const变量代替等。学习时不要只记答案,要把每种改动背后涉及的原理过一遍,这样遇到变种题也不怕。
3.2 异步编程与事件循环:从Promise到async/await
异步是前端笔试的常青考点。TME这次出了一道判断执行顺序的题,把setTimeout、Promise.resolve().then、async/await、process.nextTick混在一起,考察对事件循环微观任务和宏观任务的理解。
这道题的关键在于事件循环的机制:每执行完一个宏任务,会清空整个微任务队列,然后才执行下一个宏任务。Promise.then的回调是微任务,setTimeout的回调是宏任务,process.nextTick在Node环境中优先级高于Promise微任务。
一个常见的执行顺序题:
console.log(1); setTimeout(() => console.log(2), 0); Promise.resolve().then(() => console.log(3)); console.log(4);输出是1, 4, 3, 2。先同步输出1和4,然后清空微任务输出3,最后执行宏任务输出2。如果换成async/await,要注意await表达式后面的代码可以看作是.then中的回调,也是微任务。把事件循环的规则理解透了,这类题就是白给分。
我强烈建议复习时自己在控制台把这些代码跑一遍,把输出结果记下来。笔试时遇到类似题就不需要推断,直接凭记忆写答案,速度能快不少。
3.3 手写题:以深拷贝、防抖节流为例
TME这场简答题考了一道手写防抖函数,属于前端笔试的高频手写题。这题说难不难,但写出一个在真实场景中能用的版本,比背模板重要得多。
一个合格的防抖函数需要支持立即执行选项和取消功能:
function debounce(fn, wait = 500, immediate = false) { let timer = null; let result; const debounced = function(...args) { if (timer) clearTimeout(timer); if (immediate) { const callNow = !timer; timer = setTimeout(() => { timer = null; }, wait); if (callNow) result = fn.apply(this, args); } else { timer = setTimeout(() => { result = fn.apply(this, args); timer = null; }, wait); } return result; }; debounced.cancel = function() { clearTimeout(timer); timer = null; }; return debounced; }这里有两个细节值得注意。第一是用this绑定,因为防抖函数经常用作对象方法的事件处理,如果不绑定this,内部的this会指向window或undefined。第二是返回值的处理,immediate模式下同步返回第一次调用的结果,非immediate模式下返回最后一次调用的结果,实际开发中还要结合Promise来处理异步返回值。
类似的还有节流、深拷贝、数组去重、函数柯里化、Promise.all等高频手写题。建议每种至少手写三遍,第一遍看着思路写,第二遍凭记忆写,第三遍在无提示环境下计时写。考场上的手感就是这样练出来的。
4. 前端框架与工程化:拉开差距的分数来源
4.1 Vue方向:响应式原理与diff算法
TME是腾讯系,Vue和React都有使用,但笔试题目明显更偏Vue一些。TME这场有一道多选考了Vue 3的响应式原理,选项涉及reactive、ref、Proxy和Object.defineProperty的区别。
这里要搞清楚的核心是:Vue 2的响应式是Object.defineProperty逐个遍历属性进行拦截,它无法监听新增属性和删除属性,所以Vue 2提供了$set和$delete方法来解决。Vue 3改用Proxy代理整个对象,可以拦截get、set、has、deleteProperty等13种操作,所以新增属性、删除属性都能被监听到,这是设计上的根本差异。
另一个高频考点是diff算法。TME这场没有直接考,但面试大概率会追问。理解diff算法的核心是“同层比较、双端对比”,通过key来复用节点,尽可能减少DOM操作。回答这类问题时建议画图说明,但笔试环境不方便画图,所以要在文字表达上多下功夫,逻辑要讲清楚。
如果时间充裕,建议把Vue的一个响应式核心手写实现一遍。从最简单的reactive到effect,再到computed,大约不到100行代码就能跑通一个简化版本。这个过程比看十篇源码解析都有用。
4.2 工程化与构建工具:考的不是配置而是原理
工程化方向的考题,TME出了一道关于Webpack构建流程的理解题。这类题目很多同学容易答成“背配置项”,比如entry是什么、output是什么。但笔试考的是执行流程的底层理解。
Webpack的核心执行流程是:初始化配置、编译、解析模块、生成chunk、输出文件。编译阶段从入口出发,通过Loader对不同类型资源进行转换,遇到import/require就是发现新模块,继续递归解析;构建依赖图之后,通过Plugin在构建流程的不同节点插入自定义逻辑,比如代码压缩、资源内联、环境变量注入;最终根据配置生成chunk和文件。
答题时如果能把Loader和Plugin的区别、Loader的执行顺序(从右到左,从下到上)、Tree Shaking的触发条件(ES Module静态分析、sideEffects标记)都解释清楚,这题基本就是满分。
4.3 性能优化:笔试里最常见的开放题
简答题有一道跟性能优化相关:如何提升首屏加载速度。这类题是典型的开放题,没有标准答案,但答题的逻辑框架决定了分数高低。建议从三个维度展开。
第一个维度是资源体积优化。代码层面做代码分割,按需加载路由组件;图片用WebP格式、做懒加载;开启Gzip压缩,能减小60%以上的传输体积。第二个维度是网络策略优化。合理设置HTTP缓存,静态资源用强缓存加文件名hash,HTML用协商缓存;使用CDN加速静态资源分发;接口开启HTTP/2多路复用。第三个维度是渲染效率优化。关键CSS内联,避免CSS阻塞渲染;script标签加defer或async;减少重排重绘,动画尽量用transform和opacity。
答题时建议分点作答,每一点带一句“为什么这么做”。比如“把大图片转成WebP格式”这句话得分低,改成“WebP比PNG小约25%-35%,使用<picture>标签按需加载不同格式图片,减少体积的同时不影响清晰度”得分就高很多。判卷人能从你的扩展里判断你是背答案还是真的做过性能优化。
5. 笔试过程中的实战策略与时间分配
5.1 答题顺序的取舍
120分钟做完四类题,时间不算宽裕。我的策略是:先快速扫一遍所有题目,估计总体难度,然后先做编程题,再做简答题,最后做选择题。这个顺序不是拍脑袋定的,而是根据分数比重和思维成本计算的。
编程题分值高、需要集中精力,放在头脑最清醒的时候做效率最高。简答题需要组织语言,但不需要像编程那样反复调试,放在中等精力段。选择题虽然是客观题,但部分题目文字陷阱多,需要细心,放在最后精力不足时做反而能靠直觉避开一些过度思考。单选整体是送分题,只要你基础扎实,不需要花大把时间纠结。
当然,如果做到某道选择题时一眼能看出答案,就立刻选掉,不要留到最后再回来。我的经验是:单选题里“以下哪个选项不属于...”容易因为惯性思维失手,这类题圈一下关键词再选。
5.2 在线笔试环境与代码编写实战
TME这场用的是在线笔试系统,代码编辑器非常基础,没有自动缩进、没有代码补全,甚至连括号匹配都时灵时不灵。所以平时刷题在高亮环境下写,和在裸文本环境下写的速度差异很大。备考最后阶段要刻意在记事本或者纸笔上练手写代码。
另外一个容易被忽视的点是编程题的“提交前检查”。在线判题系统会跑多个测试用例,你本地跑通了一组样例,不代表所有边界都能过。提交前要检查:数组为空时怎么办?输入是null或undefined怎么办?数字超出Number.MAX_SAFE_INTEGER怎么办?这些边界情况在笔试中是区分排名的重要细节。
TME的编程题还允许自定义函数名,但要求严格匹配题目指定的函数签名。我在考试时就遇到一个坑:题目的函数名是findCircle,我习惯性地写成了findCycle,本地测试没问题,提交时全部用例报错,才发现是拼写问题。这种低级失误在笔试中非常常见,提交前一定要对照题目检查函数名和参数名。
5.3 共享屏幕?在线笔试的规则细节
校招在线笔试通常会要求开启摄像头或共享屏幕,TME这场同样如此。开考前要提前测试设备,确保摄像头能正常工作、网络稳定。我见过有同学因为摄像头没开被当作作弊处理,也有因为网络断线导致交卷失败的,这些技术问题虽然不影响能力评估,但会直接影响成绩,务必重视。
还有一点,在线笔试的前几分钟不要急着做题。先把规则页完整读一遍,确认选择题的评分规则、编程题的IO方式(是输入输出示例格式还是核心代码模式)、能否使用本地IDE。这些信息在规则页都有,但很多同学不看直接做题,结果用错了代码模板。
6. 常见问题与备考建议速查
6.1 备考时间不够怎么办
这个问题几乎每个来咨询的同学都会问,我的答案始终一样:抓大放小,以真题为核心做定向训练。如果只有两周时间,优先级应该是:事件循环和异步(必考)、Vue响应式原理(大厂高频)、手写题(输入率高)、HTTP缓存(容易混淆但必考)、两道简单算法题练手(保持手感)。
优先级低的模块是:CSS的偏门布局技巧(笔试很少考)、TypeScript高级类型体操(除非岗位明确要求TS)、WebGPU/Canvas等图形学(除非投的是可视化方向)。复习要服务分数,不要追求知识面上大而全。
6.2 笔试和面试最大的区别是什么
笔试和面试最大的区别在于:笔试考“广度”——知识点覆盖面广,什么都要知道一点;面试考“深度”——围绕一个点反复追问,直到问倒你。很多同学备考笔试时只看自己不熟悉的知识点,结果熟悉的部分反而丢分。正确做法是把知识体系过一遍,标记自己模糊的模块,重点突破。
TME这场笔试还体现出另一个趋势:手写题从“背模板”转向“考理解”。比如防抖函数,如果只是背下来模板,问你“为什么要保留this绑定”就答不上来。备考时一定要把每个手写题涉及的知识点拆解,做到能一边写出代码一边解释每个关键步骤。
6.3 笔试的分数多少才够
校招笔试一般不看具体分数,而是看排名百分比。TME官方没有公布过分数线,但根据往年经验,前端岗位至少要到前30%才有面试机会。编程题全做对基本能保证过线,简答题答出逻辑清晰的答题框架也能加分,选择题的准确率是拉开排名的关键。
所以不要把精力全部押在算法题上。我见过编程题全做对但选择题错一半的同学,排名反而不如编程题做出一道但选择题全对的人。原因很可能是单选题量大面广,是大多数人分数的基本盘。
7. 一场笔试之后:写给下一届候选人的话
考完之后我复盘了整张卷子,最大的感触是:TME这场笔试没有偏题怪题,但每道题都比“标准答案”多要求了一层理解。不管是框架的响应式原理,还是防抖手写,都在验证你是不是真的写过代码、真的遇到并解决过问题。
这份经验同样适用于准备其他大厂前端笔试。把JavaScript语言基础打牢,把浏览器和网络这块吃透,把Vue和React的核心原理理解到位,把常见手写题练到肌肉记忆,再配合有节奏的少量算法训练,当前端开发的校招笔试其实是很有把握的。
我记得有人问为什么进大厂要考这么多计算机基础,一个资深面试官说过一句话:“我们不是在招一个会写页面的人,而是在招一个能解决复杂问题的人。”知识是可以在工作中积累的,但解决问题的思维方式和学习能力很难被快速训练。笔试的每道题,其实都在筛选这一点。
最后分享一个备考阶段的私人技巧:每次刷完一套题,花十分钟把错题按知识点分类汇总到一张表格里,标出“完全不会”“知道但记错”“会的但粗心”三档。考前一天只看这张表,效率很高。校招是一场持久战,笔试只是第一关,稳扎稳打比什么都重要。