2019前端开发笔试题全解析:从命题逻辑到高频考点
2026/8/31 8:50:34 网站建设 项目流程

2019校园招聘前端开发工程师笔试题

每年九、十月份,校园招聘的笔试通知就像秋天的落叶一样准时飘进邮箱。2019年那会儿,前端开发已经进入了一个微妙的阶段:Vue 2.x 正值巅峰,React 16 hooks 刚刚普及,TypeScript 开始被大厂列为加分项,小程序开发搅动了一池春水。各家公司的前端开发笔试题,也从早年间那种“考正则、考闭包、考 DOM 操作”的套路,转向了“工程化 + 框架原理 + 手写能力 + 场景设计”的综合考察。

我当时帮HR筛过不少简历,也参与过笔试出题和阅卷,最大的感受是:大部分学生的前端开发基础是有的,但对“为什么”的思考太浅。笔试题其实不会故意为难人,它是在模拟你入职后三个月内会碰到的真实问题。这篇文章,我打算把 2019 校招前端开发笔试题卷子背后的命题逻辑、经典题型、答题方向和踩坑点,从头到尾拆一遍。如果你正在准备前端开发面试,或者想检验自己的 web 前端开发水平,这篇内容应该能让你少走不少弯路。

1. 这张卷子到底在考什么——2019校招前端笔试题的命题逻辑

1.1 笔试题不是为了筛掉你,是为了看清你的“前端开发skills”结构

很多同学拿到笔试卷子,第一反应是“这题好偏”,第二反应是“这题学校没教过”。其实从出题人的角度看,笔试题目设计的核心目的是:在最短时间内,快速建立一个人的前端开发skills全景图。

2019年的校招笔试题,普遍覆盖五个维度:

  • 语言基础:JavaScript 核心机制,包括原型链、闭包、this 指向、事件循环、数据类型判断。
  • 浏览器与网络:渲染机制、缓存策略、HTTP 协议、跨域方案、Web 安全。
  • 框架与工程化:Vue/React 响应式原理、diff 算法、组件通信、Webpack 配置、构建优化。
  • CSS 与页面布局:Flex 布局、BFC、垂直居中、移动端适配、动画性能。
  • 手写代码与场景设计:防抖节流、深拷贝、Promise 实现、数组去重、组件封装、性能优化方案。

这份结构的本质,对应的是一个前端工程师日常工作的真实技能需求。你不会在岗位上天天写“数组扁平化”,但你会天天处理数据转换;你不会天天手写 Promise,但你会天天排查异步执行顺序问题。笔试题只是在用“常见题面”包装“真实能力考察”。

1.2 热词背后的信号:为什么大家都在聊 vue 规范和前端开发规范

2019年搜索榜上,“前端开发规范 vue”“前端开发规范”持续霸榜,这其实是一个重要信号:那个“能跑就行”的前端时代正在过去,团队协作和代码质量开始成为校招考察的隐形维度。

我当时出题时会专门加一道“代码评审”类题目:给出一段 Vue 组件代码,让考生指出问题并说明原因。这种题目,没有实际项目经验或者没有认真读过官方风格指南的人,基本拿不到分。

什么是好的代码?不是说变量名起得长就叫规范,而是可读性、可维护性和可测试性。比如 Vue 组件中,props 校验有没有写全?data 里的数据是否都是组件自身需要维护的状态?computed 有没有依赖不该依赖的东西?事件命名是否符合 kebab-case?这些细节单拿出来都不难,但组合在一起,就是“规范意识”的体现。

所以准备笔试,不要只刷算法题和框架 API,还要花时间总结自己的“开发习惯”,形成一套清晰的“为什么这样写”的依据。这部分能力,在面试聊项目时同样加分。

1.3 2019年笔试题的“时代特色”与后续影响

现在回头看 2019 年的题目,有些特色值得拎出来说。

首先是HTTP/2 和 HTTPS 问题变多了。因为 2018 年全站 HTTPS 改造浪潮刚刚结束,2019 年很多公司开始吃 HTTPS 的“余粮”,所以笔试里会问 HTTP 与 HTTPS 的区别、TLS 握手过程、HTTP/2 多路复用的原理。这些内容现在看已经是基础中的基础,但当年还真能筛掉一批人。

其次是小程序开发题悄然出现。微信小程序 2017 年上线,2019 年进入爆发期,所以笔试题里开始出现“小程序的 setData 和 Vue 的 data 更新有什么区别”“小程序路由跳转方式”这类题目。如果你当年完全没碰过小程序,这几道题基本靠蒙。

第三是工程化题目开始压轴。Webpack 4 在 2018 年发布,2019 年已经成了标配。笔试里最常考的是:Webpack 构建流程、loader 和 plugin 的区别、如何做代码分割、如何配置多入口、CSS 怎么抽离、tree shaking 的原理。现在 Webpack 5 都成熟了,Vite 也出来了,但底层思路一脉相承。

理解这些时代背景,你就知道为什么面试官在聊项目时一定要问“你遇到的最大的前端问题是什么”——因为这些问题往往来自工程化实践,而不是 API 调用。

2. 基础题没答好,后面全白搭——JavaScript、浏览器、网络三座大山

2.1 JavaScript:从原型链到事件循环,每一题都藏着“为什么”

2019 年笔试题的 JavaScript 部分,基本绕不开这几类题。

原型与原型链。典型题:function Foo() {}; Foo.prototype.say = function() {}; const f = new Foo(); f.say();问 f 到 say 方法的查找路径。这题不难,但延伸题才是重点:“如果Foo.prototype被整体重新赋值,之前创建的实例还能访问到新原型上的方法吗?”答案是不能,因为实例内部的[[Prototype]]指向的是旧的原型对象,而实例上的__proto__是创建时决定的,不会跟随后续的Foo.prototype改变而改变。

这个考点背后考察的是“你对对象内存模型的理解程度”,如果你只知道“实例通过原型链找方法”,但不知道原型指针的指向时机,遇到这种变体就很容易翻车。

this 指向问题。出题人特别喜欢把 this 和 call/apply/bind 缠在一起考。比如:

const obj = { name: 'obj', fn: function() { console.log(this.name); } }; const fn = obj.fn; fn(); // 输出什么?为什么?

这题输出是undefined(非严格模式下是window.name,通常是 undefined)。因为fn被赋值给变量后,调用时的执行上下文已经变成了全局对象,这与“定义位置”无关,只与“调用位置”有关。

阅卷时我发现,不少同学能写出答案,但解释不出“执行上下文”这几个字。所以做题的时候,不仅要写出结果,还要养成写理由的习惯,这也是面试官评分的重要依据。

事件循环。2019 年那会儿,Promise 和 async/await 已经普及,所以事件循环题基本是必考。经典题:

console.log(1); setTimeout(() => console.log(2), 0); Promise.resolve().then(() => console.log(3)); console.log(4);

答案是1, 4, 3, 2。考察的是宏任务和微任务的执行顺序:同步代码先执行,微任务队列(Promise.then)在本次宏任务结束前清空,最后才轮到下一个宏任务(setTimeout)。

这只是热身,真正的拉分题是考察await的微任务时机:

async function test() { console.log('a'); await console.log('b'); console.log('c'); } test(); console.log('d');

输出是a, b, d, c。因为await右侧的表达式会立即执行,但后续代码会被放入微任务队列。如果对 async/await 的编译目标(generator + Promise)不熟悉,很容易做错。

2.2 浏览器:渲染机制和缓存策略,决定了你能不能在“性能优化”上得分

浏览器相关问题,在 2019 年校招笔试题里出现的频率非常高,因为性能优化是前端工程师的核心价值之一

渲染机制的经典题是:从输入 URL 到页面渲染完成,中间发生了什么?这题可以简单答,也可以很深入。面试官希望看到你至少能说清楚:DNS 解析、TCP 连接、HTTP 请求、服务器响应、HTML 解析构建 DOM 树、CSS 解析构建 CSSOM 树、合成渲染树、布局、绘制、合成。

这题别急着背八股,关键不是背出全部步骤,而是知道每一步可能出现的性能瓶颈。比如:DNS 解析能不能缓存?CSS 会不会阻塞渲染?JavaScript 的加载和执行会不会阻塞 DOM 解析?如果考到“为什么 CSS 放在 head、JS 放在 body 底部”,你要能从“CSS 阻塞渲染 + JS 阻塞解析”两个维度解释。

缓存策略是另一道高频题,通常组合起来考:强缓存和协商缓存的区别、Cache-ControlExpires的区别、ETagLast-Modified的关系。答题关键是要画出一条清晰的“浏览器请求资源的决策链”。

我当时在项目里就栽过缓存跟坑:改了静态资源的内容,但文件名没变,结果客户端一直拿到旧缓存。后来规范做法是带 hash 的文件名 + 长缓存,这样内容变了 hash 就变,URL 就变,缓存自然失效;内容没变,URL 不变,命中强缓存,性能最优。这种思路,笔试里可以写出来作为加分项。

2.3 网络与安全:跨域方案、HTTP 状态码、XSS 和 CSRF

2019 年笔试题里的网络题,不会考你“三次握手的数据包格式”,而是考前端工程师真正会用到的知识点

跨域是必考项。你需要知道同源策略是什么,然后至少能列出 4 种跨域方案:JSONP、CORS、postMessage、反向代理(或 WebSocket)。CORS 里要分清楚“简单请求”和“预检请求”,因为这在实战中经常出问题。有一个笔试题我印象很深:使用Content-Type: application/json发送 POST 请求时,为什么浏览器会先发送一个 OPTIONS 请求?答案是:该 Content-Type 不是 CORS 白名单中的简单请求值,所以需要预检。当年不少同学答成了“因为跨域了所以要发 OPTIONS”,这就不够深入。

HTTP 状态码也是送分题和送命题的结合体。301、302、304、403、404、500、502、503 这些高频状态码要了然于胸。特别容易被忽视的是 304:它代表“Not Modified”,是协商缓存命中时服务器返回的状态码,浏览器会使用本地缓存。有笔试题让写出“304 和 200(from disk cache)的区别”,本质上是考“协商缓存与强缓存”。

Web 安全方面,XSS(跨站脚本攻击)和 CSRF(跨站请求伪造)是必考。XSS 的核心是“未过滤的用户输入被当作代码执行”,防御手段包括 HTML 转义、CSP(内容安全策略)、httpOnly Cookie。CSRF 的核心是“利用用户已登录状态发起非预期的请求”,防御手段包括 Token 校验、SameSite Cookie、双重 Cookie 验证。这些点要能结合实际场景说明,比如“为什么给用户输入的富文本要做白名单过滤”。

3. 框架题怎么给分——Vue 和 React 考点的高分答题姿势

3.1 响应式原理:Vue 2 的 Object.defineProperty 与 Vue 3 的 Proxy

2019 年那会儿,Vue 3 还在 alpha 阶段,笔试题几乎全部围绕 Vue 2.x 展开。但阅卷时发现一个很有意思的现象:凡是了解过 Vue 3 响应式方案的同学,普遍比只懂 Vue 2 API 的同学答题更出彩。因为它体现出你关注技术演进方向,而不只是“会用”。

Vue 2 响应式原理的经典问法是:```new Vue()时,data 对象是如何变成响应式的?答案的骨架是:递归遍历 data 对象的每一个属性,用Object.defineProperty` 把属性重写为 getter/setter。getter 里收集依赖(Dep),setter 里触发依赖更新(Watcher)。组件渲染时会读取 data 属性,因此触发 getter,完成依赖收集;数据变化时触发 setter,通知 Watcher 重新渲染。

但这只是表层,深入一点的追问通常是:

  • Object.defineProperty有什么缺陷?
  • 为什么 Vue 3 要换成Proxy

Object.defineProperty的缺陷有两个:一是无法监听数组索引的变化,所以 Vue 2 要重写数组的 7 个变更方法(push、pop、shift、unshift、splice、sort、reverse);二是无法监听新增和删除属性,所以 Vue 2 才需要$set$delete来弥补。Proxy直接代理整个对象,天然支持属性新增、删除、数组索引变化,而且在性能上有一定优势(不需要递归遍历时一次性重定义所有属性,而是惰性处理)。

答题时如果能从“设计缺陷 → 补齐方案 → 为什么 Vue 3 要更换”这条逻辑链走,得分一定不会低。

3.2 diff 算法:不要死记硬背,先搞懂“为什么需要它”

Vue 的 diff 算法是框架题里的“拦路虎”,也是最容易被背诵式答题毁掉的一道题。

理解 diff 算法之前,先理解为什么需要它。浏览器里 DOM 操作是昂贵的,哪怕只是修改一个文本节点,都可能触发重排重绘。虚拟 DOM 的本质是在 JavaScript 层面用对象描述 UI,通过对比新旧虚拟节点,找到最小的变更集合,最后批量操作真实 DOM。

2019 年笔试常见的 diff 考点是:

  • Vue 2 的 diff 是同层比较,不做跨层级比较。
  • 先判断sameVnode(key 相同且 tag 相同),相同则走patchVnode更新,不同则直接替换。
  • 子节点数组的 diff 使用双端比较策略(oldStartIdx、oldEndIdx、newStartIdx、newEndIdx),从两端向中间遍历。
  • key 的作用是复用:在列表排序、插入、删除时,通过 key 精确识别节点身份,避免不必要的 DOM 重建。

这题的高分答案不是罗列步骤,而是说明白:为什么双端比较比简单遍历性能更好?简单遍历只能从头开始挨个对比,如果遇到“把第一项移到末尾”这种场景,会误判为大量节点被替换;而双端比较能在若干种常见操作(头插、尾插、反转)下,直接复用已有 DOM 节点,把复杂度降下来。

实际上我在做项目时也验证过:列表渲染没有 key 或者 key 用 index,一旦数据顺序变化,整个列表都闪烁重绘。这个坑,笔试时如果能主动提出来,面试官会眼前一亮。

3.3 React/Vue 组件通信与生命周期:笔试的“稳分题”

框架题不完全都是原理,也有“送分题”——组件通信方式和生命周期执行顺序。这类题的特点是:只要你认真写过项目、踩过坑,就一定能答上来。

组件通信在 Vue 里的常见方式:

  • props / $emit:父子组件通信
  • $refs / $children:直接访问子组件实例
  • $attrs / $listeners:隔代透传属性/事件
  • provide / inject:祖先组件向任意后代注入数据
  • EventBus:跨组件事件广播
  • Vuex:全局状态共享

React 里则是 props 回调、Context、Redux/Mobx、ref 转发等。答题时最好能说出“什么场景选什么方案”而不是罗列名字。比如,一个表单页面里多个兄弟组件共享数据,用 EventBus 确实也能做,但代码会变得极难维护;这种场景用状态管理库(Vuex/Redux)或者提升 state 到父组件更合适。

生命周期同样是必考。Vue 2 的生命周期口诀是“创建前后、挂载前后、更新前后、销毁前后”。但笔试题往往不满足于口诀,而是会问:created里能访问到 DOM 吗?mounted里能访问到 data 吗?子组件的mounted和父组件的mounted谁先触发?答案是:创建过程父组件先于子组件(父 created → 子 created → 子 mounted → 父 mounted),销毁过程则相反。这个顺序在项目里做埋点、统计、初始化数据时非常关键,所以笔试考这个一点都不偏。

React 16 之后的生命周期也常考:componentWillMount/componentWillReceiveProps被废弃后移到哪了?为什么 mount 阶段推荐getDerivedStateFromProps?关键原因是要避免副作用——旧生命周期在 render 之前调用,容易导致在服务端渲染时执行不安全的操作(如访问 window),React 团队因此逐步用静态方法和componentDidXxx替代。如果只背生命周期表格,不理解“为什么改版”,在新题面前就会不知所措。

4. 手写代码题——考的不只是会写,是写对、写稳、写出边界

4.1 防抖节流:这两道题,每年都有,但每年都有人写错

前端开发笔试题里,手写代码题是拉开差距的关键。其中防抖(debounce)和节流(throttle)是出现频率最高的两个。

防抖的核心思想是:事件触发后延迟一段时间执行,如果在这段时间内再次触发,则重新计时。适用场景:输入框实时搜索、窗口 resize 后计算布局。

function debounce(fn, delay = 300) { let timer = null; return function(...args) { if (timer) clearTimeout(timer); timer = setTimeout(() => { fn.apply(this, args); }, delay); }; }

这里要注意:this绑定必须保留,否则在 Vue 组件里用this.xxx会报错。另外,返回值的问题——标准防抖后fn的返回值是拿不到的,如果确实需要返回值,可以考虑“立即执行版”防抖。

节流的核心思想是:一段时间内只执行一次。适用场景:滚动监听、按钮点击防重复提交。

function throttle(fn, interval = 1000) { let last = 0; return function(...args) { const now = Date.now(); if (now - last >= interval) { last = now; fn.apply(this, args); } }; }

节流还有一种基于定时器的实现(适合保证最后一次也执行),面试时如果能主动说出两种实现的区别和适用场景,绝对加分。

阅卷时最大的痛点是:很多同学防抖和节流背得非常熟,但让他写一个“带立即执行参数的防抖”,瞬间懵了。这说明不是真理解,而是背模板。所以准备手写题,核心不是背,而是理解“定时器是用来延迟的还是用来节流的”这个本质。

4.2 深拷贝:从浅拷贝到深拷贝,再到循环引用和函数属性

深拷贝是手写代码里另一个高频题。2019 年的笔试题,基本要求是:手写一个deepClone,能够处理对象嵌套、数组、循环引用。

JSON.parse(JSON.stringify())虽然是最简单的深拷贝,但有几个致命问题:

  • 函数、undefined、Symbol 会被丢弃
  • Date 会被转成字符串
  • RegExp 会被转成空对象
  • 循环引用会直接报错

所以标准答案要使用递归 + WeakMap 处理循环引用:

function deepClone(obj, map = new WeakMap()) { if (obj === null || typeof obj !== 'object') return obj; if (map.has(obj)) return map.get(obj); const clone = Array.isArray(obj) ? [] : {}; map.set(obj, clone); for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { clone[key] = deepClone(obj[key], map); } } return clone; }

这里有几个细节值得展开。

第一,typeof obj !== 'object'这一行,很多人写成了typeof obj !== 'object' || obj === null,忘了 null 的判断。typeof null'object',如果不先排除 null,递归会崩。

第二,为什么要用 WeakMap?因为 WeakMap 的 key 是弱引用,不会阻止垃圾回收,而且语义上说“这个 map 只是辅助克隆过程用的”,用完就应该能被回收。用普通的 Map 也不会报错,但面试官更希望看到你理解 WeakMap 的用途。

第三,fork 一个字段是函数时怎么处理?上面代码直接返回该函数(因为typeof fn !== 'object',走第一行 return),这在大多数业务场景中是合理的——函数共享引用即可,不需要深拷贝。

但这题真正想考察的是边界意识。阅卷时我们看到一份优秀答案会额外处理 Date、RegExp、Map、Set,甚至会说明“Symbol 属性在 for...in 中拿不到,需要用 Reflect.ownKeys 才能复制”。这些细节,就是拉开差距的地方。

4.3 Promise 实现与数组 API:从使用到实现,是“理解”的分水岭

手写 Promise 在 2019 年校招笔试题里开始高频出现。尤其是要求实现Promise.allPromise.race

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); }, reason => reject(reason) ); } }); };

这里有三个关键点,缺一个都是错的。

第一,results[i]的位置不能写成results.push(value)。因为 promise 的 resolve 顺序不一定是传入顺序,如果第一个 promise 很慢、第二个很快,push 的结果会顺序错乱。用索引赋值保证输出顺序和输入顺序一致,这正是Promise.all的标准语义。

第二,promises数组里可能混入非 Promise 值,所以必须用Promise.resolve()包裹一下,保证then能正常调用。

第三,循环里如果用for...of而不是for循环,代码更简洁,但要注意await会让过程串行化,如果需要并行执行,不要在里面加await

当然,更深层的考法是手写一个完整的 Promise(包含 then 链、状态流转、异常捕获、resolve 中传 Promise 等),这个在笔试题里相对少,但面试环节很有可能出现。

数组 API 也是手写题的重灾区,最经典的是“手写 reduce”和“用 reduce 实现其他数组方法”。例如:

Array.prototype.myReduce = function(callback, initialValue) { const arr = this; let acc = initialValue !== undefined ? initialValue : arr[0]; let startIndex = initialValue !== undefined ? 0 : 1; for (let i = startIndex; i < arr.length; i++) { acc = callback(acc, arr[i], i, arr); } return acc; };

注意点:没有传initialValue时,要跳过第一个元素作为初始值;空数组且没有初始值时会报错(标准行为是抛 TypeError);callback 的四个参数(acc、currentValue、currentIndex、array)要完整传给回调。这种题最大的价值在于让你重新理解数组方法背后的遍历逻辑,写一遍比背十遍 API 文档管用。

5. 工程化与 CSS——容易被忽略的“送分题”和“送命题”

5.1 Webpack 的 loader 与 plugin:年年考,年年有人说混

2019 年笔试题的工程化部分,几乎必问loaderplugin的区别。这是最基础的问题,但每年都有大量同学答反。

loader:用于转换模块的源代码,本质上是函数。在 import 资源时,loader 会对文件内容进行“加工”。比如babel-loader把 ES6+ 代码转成 ES5,css-loader解析 CSS 中的@importurl()style-loader把 CSS 以<style>标签形式注入页面。loader 的执行顺序是从右到左、从下到上,比如{ test: /\.css$/, use: ['style-loader', 'css-loader'] }会先用css-loader处理 CSS,再把结果交给style-loader注入页面。

plugin:用于解决 loader 无法处理的其他事情,本质上是。插件在 Webpack 构建过程中监听事件钩子,在特定时机执行逻辑。比如HtmlWebpackPlugin自动生成 HTML 并注入打包后的资源,MiniCssExtractPlugin把 CSS 从 JS 中抽离成独立文件,BundleAnalyzerPlugin可视化分析打包产物。

答题时可以这样打比方:loader 是“加工原材料的工人”,plugin 是“优化生产流程的管理者”。一个管内容转换,一个管生命周期事件。

如果你想拿高分,可以再加一句:Webpack 的内部实现里,插件机制基于 Tapable 事件系统,loader 则被集成在 module 的编译流程中,两者从架构定位上就不一样。这句话点到为止即可,不用深入展开。

5.2 兼容性与适配题:移动端适配、BFC、Flex 布局

CSS 题目在 2019 年笔试题里的地位有些微妙:因为框架工程化以后,大家普遍觉得 CSS 不重要,结果出题人反手给你来一道“移动端适配方案对比”,直接打懵一片。

移动端适配的经典设计题:给出一个设计稿(宽 750px),让你设计一套 H5 适配方案。答案可以从这几个方向答:

  1. 使用 rem:html字体大小按屏幕宽度动态计算,设计稿宽 750px,设置1rem = 100px,页面元素尺寸用 rem 书写。
  2. 使用 vw/vh:100vw = 视口宽度,按设计稿比例直接用 vw 换算,公式是(设计稿宽度 / 750) * 100vw
  3. 使用 flexible 方案(动态设置 dpr 和 rem 比例),这是 2019 年比较主流的做法。
  4. 新方案:viewport 单位 +postcss-px-to-viewport插件自动转换。

答题关键是不能只说一种方案,要对比优劣。rem 方案兼容性好,但需要引入脚本计算;vw 方案更简洁,当时在 Android 低端机上偶尔有兼容问题。这些实践中的经验是答题的加分项。

BFC(块级格式化上下文)在 CSS 题里出现率极高,因为它是布局问题的万金油解释。常考场景包括:

  • 清除浮动(父容器高度塌陷)
  • 防止兄弟元素 margin 重叠
  • 两栏自适应布局(左侧固定 + 右侧自适应)

触发 BFC 的方式:overflow: hiddendisplay: inline-blockdisplay: flexposition: absolute/fixedfloat等。答题时至少要能说出 3 种以上,并且说明哪种是最推荐的。实际项目里overflow: hidden最常用,但要注意它会不会裁切溢出的内容。

Flex 布局的经典题是垂直水平居中和实现一个两栏布局。2019 年 Flex 已经普及了,但不少考生还是只会display: flex; align-items: center; justify-content: center;。题目稍加变化,变成“如何实现一个左侧固定右侧自适应的双栏布局”,很多人就卡住了。正确答案是用flex: 0 0 200px固定左侧,右侧flex: 1自适应。如果还要处理“左侧宽度可能变化”的场景,可以用min-width: 0配合flex的坑,这是实战里常踩的点。

5.3 “前端 ai 开发”等新话题在笔试中的渗透

2019 年“前端 ai 开发”这一热词已经出现,虽然不至于直接考“用 TensorFlow.js 做模型推理”,但笔试题里已经开始出现这类题目:“如果页面需要在浏览器端完成图像分类,你会怎么做技术选型?”

这类开放性题目没有标准答案,考察的是你对技术边界的认知。答题思路可以从这几个方向展开:

  • 模型来源:训练好的模型如何转换成前端可运行的格式(TensorFlow.js / ONNX)
  • 推理方式:WebAssembly 加速、GPU 后端(WebGL)
  • 资源体积:模型文件压缩、量化、按需加载
  • 降级方案:浏览器不支持 WebGL 时如何处理

虽然 2019 年这类题占比很小,但它释放了一个明确的信号:前端开发正在向“端智能”蔓延。如果你能在笔试题里体现出对新技术趋势的关注,哪怕只是说一句“我了解过 TensorFlow.js,知道它可以在浏览器里做推理”,印象分也会显著提升。

6. 两小时实战心得——时间分配、踩坑记录和复盘方法

6.1 拿到卷子先别做题,前 5 分钟决定你能不能做完

2019 年校招笔试,普遍是“线上笔试 + 摄像头监考”模式,时间一般在 60 到 120 分钟不等,题量在 25 到 40 题之间,其中包含 3 到 6 道手写代码题。

很多人一打开卷子就开始埋头答题,结果前面的选择题花了 40 分钟,后面的手写题只剩 15 分钟,直接崩盘。我建议的时间分配策略是:前 5 分钟通读全卷,标记题目难度。

把试卷上的题目分成三类:

  • 秒杀题:一眼看出答案的,如 “typeof null输出什么”“HTTP 状态码 304 代表什么”。
  • 思考题:需要演算、推理的,如事件循环输出顺序、数组手写题。
  • 大题/设计题:需要组织语言描述的,如“浏览器渲染流程”“Webpack 优化方案”。

秒杀题先做完,把基础分稳稳拿到手;思考题按“先易后难”的顺序推进;大题留到最后答,但至少要写出关键点,不要留白。

这个方法听起来很简单,但真的能让你多拿 10 到 20 分,因为很多同学不是不会,而是没时间做完。笔试除了考知识,也在考压力下的时间管理和优先级判断,这两项能力恰恰是真实工作中最重要的。

6.2 线上的“手写代码”怎么练,遇到不会的题怎么办

线上笔试的手写代码题,和本地 IDE 里写代码完全是两个体验:没有语法提示、没有自动补全、没有单元测试。哪怕用同一套代码,线上编辑器里手写也容易出低级错误。

所以备战手写题时要专门训练“裸写”能力:

  • 找一个空白的编辑器(比如 Notepad++ 或 vim),关掉补全提示,定时 10 分钟手写防抖、节流、深拷贝。
  • 写完先在脑内跑一遍,检查边界:传 null 怎么办?空数组怎么办?参数没传怎么办?
  • 再复制到本地环境里跑一遍,对照标准答案找出差异。

遇到不会的题怎么办?笔试题一般会有“部分正确给分”的规则,所以不要直接放弃。能写多少写多少,把思路写出来。比如让你实现Promise.all,你记不住完整实现,但知道要用new Promise包一层、知道要遍历数组、知道要计数,那就把骨架写出来。哪怕最后运行不对,阅卷人也能看到你的思路。

我自己后来帮公司出题时,评分标准里明确写了:“有一定思路但实现不完整者,可以拿 50% 以上的分数。”所以遇到不会的题,写思路永远比留白强。

6.3 编译原理、HTTP 状态码这些边角料怎么补

2019 年校招笔试题里,偶尔会出现一些看起来很“偏”的题,比如:“AST 是什么?Babel 的编译流程是怎样的?”、“span标签能设置width吗?为什么?”、“=====的隐式转换规则是什么?”、“Cookie、localStorage、sessionStorage 的区别,以及 Cookie 怎么设置 httpOnly?”

这类题本质上不是“偏”,而是在考察“你是否真的经历过这些场景”。以 Babel 为例,你写 Vue 代码时离不开它,但很少有人主动去查它的编译流程。其实 Babel 的编译流程就三步:解析(parse)→ 转换(transform)→ 生成(generate),解析阶段把源码变成 AST,转换阶段遍历 AST 做插件处理,生成阶段把 AST 改回代码。如果你在项目里配过 Babel 插件,这个答案自然就能写出来。

这些边角料的准备策略不是“押题”,而是从自己的项目里找问题。你在配置 postcss、babel、webpack 时遇到的所有“为什么”,都可以变成笔试题目。反过来,如果你项目里从来没碰过这些,笔试时遇到不会的也很正常。

6.4 复盘方法:比刷新题更重要的,是整理自己的错误清单

笔试落幕不等于学习结束。我自己当年带校招生时,最推荐的做法是:每次模拟笔试或真实笔试后,做一份自己的“错误清单”,按主题分类记录。

举个例子,假如你在“事件循环”上栽了两次,就不要只记答案,而是要把“宏任务和微任务的本质区别”梳理一遍:

  • 宏任务:setTimeout、setInterval、I/O、UI 渲染
  • 微任务:Promise.then、MutationObserver、process.nextTick
  • 两者关系:每执行完一个宏任务,先清空微任务队列,再执行下一个宏任务

你甚至可以自己试着画一张执行流程图,标出每个任务的入队、出队时机。这张图比任何笔记都有价值,因为它是你亲手梳理的因果链路。

整理错误清单时,我还会建议给每条记录加一个“如果重新出题,会怎么变着法考我”的预测。这是训练“命题人思维”的方法——当你站在出题人的角度看知识点,你会发现考察点其实是有限的、循环的。这件事坚持做一个月,效果比闷头刷十套题都明显。

这几年陆续带过一些新入职的前端同学,也出过几次校招笔试题,最大的体会是:前端开发笔试题从来不是“考倒你”,而是“帮你照镜子”。2019 年的卷子和今天的比,题目内容有了不少变化——TypeScript 登场了,Vite 来了,AI 辅助编码也成了常态话题,但考察的内核始终没变:你知不知道一个网页从输入 URL 到渲染出来的全过程?你知不知道代码写完后 Webpack 帮你做了哪些事?你知不知道一个列表渲染为什么要加 key?

如果你准备笔试的时间有限,我建议你先把“事件循环 + 深拷贝 + 防抖节流 + Vue 响应式 + 浏览器缓存”这几块练到闭着眼都能写对的程度,它们就是笔试的“基本盘”。在此基础上再去看框架源码解析、工程化配置、HTTP 协议细节,查漏补缺。

校招只是职业生涯的起点,笔试题答得好不好,决定的是三个月后你在哪家公司的哪间工位上。但真正决定你能走多远的,是那个愿意在做错之后,把每一道题都拆开揉碎、追根问底的自己。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询