1. 试卷整体观察:安全厂商的前端考察有什么不一样
1.1 为什么这类试卷值得认真拆
看到“奇安信秋招前端方向试卷3”这个标题,我第一反应不是去回忆题目本身,而是想聊聊这类安全厂商的前端试卷为什么值得单独拿出来拆一遍。2020年秋招那会儿,前端岗位的面试套路已经比较成熟了,各家大厂的题库大同小异,基本围绕 JavaScript 基础、浏览器原理、框架应用、工程化、手写题这几大块。但安全厂商的试卷有个很明显的特点:它会把“安全”这个基因渗透到前端考察里,而且考察方式往往不是单独出一道“什么是XSS”的背诵题,而是把安全思维糅进 JavaScript 特性、网络请求、浏览器渲染这些常规考点里。
这么说吧,如果你只按普通互联网公司的题库去准备,遇到安全厂商的试卷,大概率会在某些题目上卡壳。不是因为题多难,而是出题人的视角不一样。普通公司问你“怎么实现一个防抖函数”,安全厂商可能就会接着问“如果这个防抖用在登录按钮上,你怎么防止恶意脚本绕过前端校验直接提交”。这种追问方式,考察的不光是你会不会写代码,还有你有没有“前端代码是不可信的”这个安全意识。
所以这篇文章,我结合接触过的同类试卷和面试经历,把前端方向秋招试卷里大概率出现的考点、出题逻辑和准备思路完整梳理一遍。2020年的试卷放在今天看,核心技术点并没有过时,反而因为前端安全、微前端、构建工具链这些方向的发展,很多知识点变得更值得深挖了。适合正在准备秋招的应届生、想跳槽但基础不扎实的初中级前端,以及带新人时想系统梳理考察点的技术Leader参考。
1.2 从试卷结构反推面试官的筛选逻辑
一份前端试卷,本质上不是考你背了多少 API,而是面试官在有限时间内建立“这哥们儿能不能干活”这个判断的一种手段。2020年前后端分离已经是行业标配,前端要做的事远不止切页面,所以试卷的题目分布基本能反映出一家公司对前端岗位的能力预期。
从整体上看,这类试卷的结构一般遵循“基础占比约40%、框架与工程化约30%、算法与手写题约20%、其他杂项约10%”的分布。奇安信这种安全背景的公司,对网络协议和浏览器安全机制相关内容的考察比例会更高一些。我做过的模拟和接触过的真实反馈里,比较典型的题型包括:
- JavaScript 语言特性题:作用域、闭包、原型链、this 指向、事件循环。这些属于“答不对基本没戏”的题,因为它们是所有前端能力的底座。
- 浏览器与网络题:从输入 URL 到页面展示的完整过程、缓存机制、HTTP 与 HTTPS 的差异、跨域解决方案。安全厂商会额外关注 CSP、XSS、CSRF 这些点。
- 框架应用题:Vue 响应式原理、组件通信、生命周期、虚拟 DOM。2020 年 Vue 2 正值巅峰,Vue 3 刚发布不久,React 16 的 Hooks 也已经普及,所以框架题一般二选一或者都考。
- 手写题与算法题:防抖节流、深拷贝、Promise 实现、数组去重、简单排序。前端算法题不像后端那么深,但基础的数据结构和复杂度分析需要过关。
- 工程化与安全题:Webpack 构建流程、首屏优化、XSS 与 CSRF 的防御、HTTPS 握手过程。
这套结构放在今天依然成立,只是框架题会向 Vue 3 和 React 18 倾斜,工程化题会加入 Vite、微前端、Monorepo 这些新东西。但底层逻辑没变:基础不牢,框架换得再勤也没用。
2. JavaScript 核心考点:从答题到理解“为什么”
2.1 作用域与闭包:别只背执行上下文
作用域和闭包几乎是前端试卷里必出的一对“组合拳”。典型考法有两种:一种是直接给一段代码让你输出结果,另一种是让你解释闭包是什么、有什么应用场景。很多准备充分的同学能背出“闭包是函数和其词法作用域的组合”这种定义,但一旦题目涉及的变量提升和块级作用域混在一起,就很容易翻车。
我见过一道很典型的题,代码大概是这样的:
for (var i = 0; i < 5; i++) { setTimeout(function() { console.log(i); }, 100); }问输出结果是什么,以及如何让它输出 0、1、2、3、4。如果你不懂var的函数级作用域和闭包捕获的是同一个i引用,这道题就会错得很彻底。用let改成块级作用域是最直接的方案,但面试官往往会追问:为什么let可以?因为let在每次迭代时都会创建一个新的词法环境,setTimeout里的回调捕获的是每次迭代新生成的i绑定。
这里我要多说一句:闭包不只是“函数套函数”这种表面形式,它的本质是“一个函数记住了它被创建时的词法作用域,即使这个作用域已经执行完了”。理解到这一层,你才能解释为什么闭包会导致内存泄漏、为什么 React Hooks 的useEffect里能拿到最新的props而不会过期、为什么防抖节流函数要用闭包来保存 timer 变量。这些都是闭包在真实项目里的延伸,也是面试官通过一道小题目观察你有没有工程思维的切入点。
2.2 this 指向与原型链:画图比背口诀有用
this 指向的题目,属于那种“看着简单,做起来错一半”的题型。它不像闭包那样有明确的规律,因为 this 是在函数被调用时才确定的,跟函数定义的位置无关。普通函数、箭头函数、bind/call/apply、构造函数、事件回调各自有不同的规则,混在一起考的时候,非常搞心态。
我建议准备这类题的时候不要硬背“谁调用指向谁”这种口诀,而是自己画一张调用栈和对象的指向图。例如下面这种题:
const obj = { name: 'obj', fn: function() { console.log(this.name); } }; const f = obj.fn; f();答案是undefined或全局对象上的name(取决于运行环境),因为f()是独立调用,this 指向全局。画图的话,就画一个函数被提取出来、调用点不在 obj 对象方法调用位置上的过程,一下子就通了。
原型链也是一个道理。题目经常会让你手动实现一个instanceof或者模拟new的过程,这比单纯问你“原型链是什么”更有区分度。模拟new本质上就四步:创建新对象、把新对象的原型指向构造函数的prototype、把构造函数里的 this 绑定到新对象上执行、根据返回值类型决定返回新对象还是构造函数的返回值。能把这四步写清楚,说明你是真懂,不是背出来的。
2.3 异步与事件循环:宏任务和微任务的底层逻辑
事件循环是 JavaScript 这门语言最反直觉但又最重要的运行机制,前端试卷基本必考。常见考法是给你一段混合了setTimeout、Promise、async/await、process.nextTick的代码,让你写出打印顺序。这种题如果没有真正理解微任务队列的处理时机,光靠背结论很容易在变种题上翻车。
理解事件循环的关键,在于记住“执行栈清空后,先处理所有微任务,再取一个宏任务执行,执行完宏任务队列里剩下的微任务,再取下一个宏任务”这个循环。注意是“所有微任务”,也就是说微任务队列里如果在执行微任务的过程中又产生了新的微任务,会继续在当前循环内执行完,不会让出给宏任务。
console.log('1'); setTimeout(function() { console.log('2'); }, 0); Promise.resolve().then(function() { console.log('3'); }); console.log('4');输出顺序是 1、4、3、2。原因就是同步代码先执行完,然后清空微任务队列里的Promise.then,最后才取宏任务setTimeout。如果面试官再深挖一层,问为什么微任务优先于宏任务,这就涉及到 JavaScript 引擎设计时对“用户交互响应”和“任务公平性”的权衡了。你答到这一层,就算真正把这道题吃透了。
3. 浏览器与网络:安全厂商偏爱的那几道题
3.1 从输入 URL 到页面渲染,到底考什么
“在浏览器里输入一个 URL 到页面完整展示,中间发生了什么?”这道题是前端面试的经典大题,同时也是安全厂商很喜欢出的一道题。因为它能覆盖 DNS 解析、TCP 连接、HTTP 请求、浏览器渲染引擎的 HTML/CSS/JS 处理流程等多个维度,一道题就能探出你的网络基础和浏览器原理功底。
针对这道题,我建议准备的时候按阶段来组织答案:
- URL 解析与编码:浏览器先判断输入是合法的 URL 还是搜索关键词,然后对非 ASCII 字符做 Punycode 编码。
- DNS 解析:查找浏览器缓存、操作系统缓存、路由器缓存、本地 hosts 文件、根 DNS 服务器、顶级域名服务器、权威域名服务器,最终拿到 IP 地址。
- 建立 TCP 连接:三次握手,确认双方收发能力正常。如果是 HTTPS 站点,还要额外进行 TLS 握手。
- 发送 HTTP 请求:构建请求行、请求头、请求体,经过浏览器缓存检查后发出。
- 服务器处理并返回响应:返回带状态码的响应报文。
- 浏览器解析与渲染:解析 HTML 生成 DOM 树,解析 CSS 生成 CSSOM 树,合并成渲染树,经过布局和绘制流程展示到屏幕上。
- 断开连接:TCP 四次挥手(HTTP/1.1 下 keep-alive 可能保持连接)。
安全厂商的延伸追问通常会集中在 HTTPS 握手过程和 DNS 劫持的防范上。你需要能说清楚 CA 证书链的验证机制、对称加密与非对称加密在 TLS 握手过程中的分工、以及为什么前端代码里写死了 IP 地址反而更容易被中间人攻击。
3.2 浏览器缓存策略:强缓存与协商缓存的一整套细节
缓存是前端性能优化里性价比最高的一块,也是试卷里喜欢出对比题的点。常考的是强缓存与协商缓存的区别,以及Cache-Control、Expires、Last-Modified、ETag这几个头的组合使用。
我给你整理一个对照表:
| 维度 | 强缓存 | 协商缓存 |
|---|---|---|
| 触发条件 | 请求头/响应头命中缓存规则,未过期 | 缓存已过期,需要向服务器确认 |
| 关键头 | Cache-Control: max-age=xxx、Expires | Last-Modified/If-Modified-Since、ETag/If-None-Match |
| 服务器是否收到请求 | 不发送,直接读本地缓存(200 from memory cache/disk cache) | 会发送请求,服务器返回 304 或 200 |
| 优先级 | Cache-Control优先于Expires | ETag优先于Last-Modified |
| 适用场景 | 静态资源(JS/CSS/图片),配合文件名 hash | HTML 页面,需要随时感知内容更新 |
这里我想特别提一个容易被忽略的坑:Expires是绝对时间,如果客户端系统时间和服务器不一致,强缓存可能提前失效或者过期后依然命中的错觉。所以 HTTP/1.1 引入了Cache-Control: max-age这种相对时间。你回答的时候如果能顺带说出“面试官,这里有一个时间同步的问题,所以后来推荐用 Cache-Control”,会显得你对边界情况有敏感度。
3.3 HTTPS 与安全头:为什么安全厂商必考
安全厂商的试卷里,HTTPS 和浏览器安全几乎是从不缺席的主题。你需要能讲清楚这几件事:
- HTTPS 不是一种新协议,而是 HTTP 跑在 TLS/SSL 之上。数字证书的作用是完成身份认证,防止中间人冒充服务器。
- TLS 握手的关键流程:客户端发送支持的加密套件列表和随机数,服务器返回证书和自己选的加密套件,客户端验证证书链合法性后生成预主密钥并用服务器公钥加密发送,服务器用私钥解密得到预主密钥,双方基于两个随机数和预主密钥生成会话密钥。之后的通信全部使用对称加密。
- 为什么需要混合加密:非对称加密性能差,适合少量关键数据的交换;对称加密性能好,适合大数据量的传输。TLS 的设计就是两种方案取长补短。
安全头这块,XSS 和 CSRF 的防御是重头戏。你可以从响应头Content-Security-Policy设置白名单域名、X-XSS-Protection开启浏览器过滤器、X-Frame-Options防止点击劫持、SameSiteCookie 属性限制跨站携带这几个维度展开。前端代码层面,转义用户输入、不信任任何innerHTML插入的第三方内容、使用HttpOnlyCookie 存储登录态,这些都是哪怕不做安全专项也必须具备的基本素养。
4. Vue 框架与工程化:手写题之外的真实工作能力
4.1 响应式原理:Vue 2 和 Vue 3 的对比
2020 年秋招时 Vue 2 还是绝对主流,但 Vue 3 已经发布,所以试卷上通常会让考生对比两者的响应式实现。这题放在今天依然是热点,因为 Vue 3 的 Composition API 和相关生态已经全面铺开。
Vue 2 的响应式核心是Object.defineProperty,通过递归遍历 data 中的每个属性,用 getter 收集依赖、setter 触发更新。它的缺陷很经典:新增属性不会触发视图更新、通过索引修改数组元素不会触发更新、对深层嵌套对象做劫持时初始化性能较差。
Vue 3 改用了Proxy,它可以代理整个对象,能监听属性的新增和删除,也能监听数组的变化。初始化时不需要深层递归,而是依赖运行时访问自动触发懒代理,性能提升明显。对应的依赖收集和触发更新的机制也做了重构,effect替代了Watcher,WeakMap结构存储依赖关系。
如果你在面试中能写出一个最小版的响应式实现,效果会非常好:
function reactive(target) { return new Proxy(target, { get(obj, key) { track(obj, key); return obj[key]; }, set(obj, key, value) { obj[key] = value; trigger(obj, key); return true; } }); } // track 负责收集依赖,trigger 负责执行副作用函数能写出来不代表你全会,但至少说明你理解 Proxy 拦截的基本模型,也理解 Vue 2 为什么最后选择这条路。
4.2 computed 与 watch:功能边界在哪里
框架应用题里,computed和watch的区别是一道高频送分题,但也最容易答得没有深度。很多人只会说“computed 有缓存,watch 没有”,然后就没了。
完整的回答应该包含三个层次:
第一层,功能定位:computed用于根据已有响应式数据派生出新数据,它是模板表达式的替代方案;watch用于监听某个数据变化后执行副作用逻辑,比如搜索防抖、路由变化后的数据请求。
第二层,缓存机制:computed只有在它依赖的响应式数据变化时才会重新计算,只要依赖没变,多次访问都返回缓存结果。watch不缓存,每次变化都会执行回调。
第三层,使用场景:模板里的复杂逻辑能放computed就不放method;需要异步操作或相对开销较大的操作放在watch里;如果多个数据变化需要联动处理,watch会更合适。
如果能再补充一个“为什么 Vue 3 里当我们需要监听对象内部属性变化时要用watch(() => obj.a, fn)这种函数形式”的例子,就体现出你实际写过新版本代码。
4.3 工程化与构建工具:前端面试里的“隐形题”
工程化题不是每次笔试都能看到,但在面试中一定会被问。2020 年的重点是 Webpack,现在 Vite 已经占据半壁江山,但 Webpack 的底层知识依然是理解前端工程化的地基。
常见的考察维度包括:
- Webpack 的构建流程:初始化参数、编译入口、解析依赖、生成 chunk、输出文件。核心是 entry、module、chunk、bundle 这四者的关系。
- Loader 和 Plugin 的区别:Loader 是让 Webpack 能处理非 JS 文件,本质是转换器;Plugin 则是在打包生命周期的各个阶段 hook 自定义逻辑。一个管文件内容,一个管构建过程。
- Tree Shaking 的原理:基于 ES Module 的静态结构分析,剔除没被使用的导出。这个知识点在 2020 年很热,因为它直接关系到打包体积优化。
- 代码分割:通过
import()动态导入和splitChunks将公共依赖拆成独立 chunk,提高首屏加载速度。
如果你现在准备 2026 年的秋招,建议把重点向 Vite 倾斜一点,但要理解 Vite 的“开发时用原生 ESM 按需加载,生产时用 Rollup 打包”核心策略,以及它为什么比 Webpack 冷启动快。这种对比思维,比单纯背配置项更有价值。
5. 手写题与算法题:面试中的硬骨头
5.1 高频手写题与答题思路
手写题是秋招前端试卷里区分度最高的部分,因为背题和学习是两码事,代码一写就知道水平。我把高频的手写题分成三梯队:
第一梯队(必会):防抖、节流、深拷贝、数组去重、Promise.all/Promise.race、new、instanceof、call/apply/bind。
第二梯队(常见):JSON.stringify的模拟实现、函数柯里化、发布订阅模式、Object.create、reduce的实现、列表转树形结构。
第三梯队(加分):Promise完整实现(包含 then 链、错误捕获、静态方法)、async/await的 Generator 实现原理、虚拟 DOM 的 diff 简化版。
以防抖为例,很多人的实现只是简单套 setTimeout,但完整版应该包含this绑定、参数传递、立即执行选项和取消方法:
function debounce(fn, wait = 300, immediate = false) { let timer = null; function debounced(...args) { const later = () => { timer = null; if (!immediate) fn.apply(this, args); }; const callNow = immediate && !timer; clearTimeout(timer); timer = setTimeout(later, wait); if (callNow) fn.apply(this, args); } debounced.cancel = () => { clearTimeout(timer); timer = null; }; return debounced; }写完之后主动说一句“我把 cancel 也暴露出来,因为实际项目中防抖函数经常需要在组件销毁时取消”,这种工程意识往往是加分点。
5.2 算法题的取舍策略
前端算法题不会考到动态规划里的偏难怪题,但也需要掌握基本的数据结构和复杂度分析。2020 年秋招常见的是:
- 字符串类:最长回文子串、字符串翻转、括号匹配。
- 数组类:两数之和、三数之和、最大子序和、数组去重排序。
- 链表类:反转链表、合并两个有序链表。
- 二叉树类:层序遍历、最大深度、路径总和。
- 排序类:手写快速排序、归并排序,并能说出时间复杂度和稳定性。
我对算法题的建议是:不要死磕高难度题目,但一定要把每种题型的最优解思路和复杂度分析准备好。比如两数之和,暴力解的复杂度是 O(n^2),用哈希表是 O(n),面试官让你写最优解就是为了判断你有没有“在资源受限情况下选择合适数据结构”的意识。这种意识,日常工作里写 API 请求缓存、状态管理、渲染优化都用得上。
6. 应试之外的思考:一份前端试卷背后的能力模型
6.1 安全行业对前端的特殊要求
奇安信这种安全厂商对前端的要求,和一般互联网公司相比确实有差异。最大的差异在于:他们对“输入不可信”有极强的执念。
常规前端面试问 XSS 怎么防御,你答“在模板里用 v-html 要小心、用户输入要转义”基本就能过。但在安全厂商的面试里,你还需要进一步解释:为什么前端转义不是最终的防御手段?后端为什么必须同样做校验和转义?CSP 是如何在浏览器层面提供兜底防护的?iframe的沙箱机制有哪些限制?如果用户手动改了前端代码绕过校验直接给后端发请求,服务端能否识别?
这些问题表面上是在考安全知识,实际上是在考察你能不能换位思考:前端只是整个系统的一层窗口,真正的安全边界在后端。具备这种思维的面试者,才适合在安全公司里参与涉及政企客户的控制台、态势感知平台、安全运营中心这类产品的前端开发。
6.2 应届生准备秋招的实际建议
基于我对这类试卷的观察,给正在准备秋招的应届生几条很实在的建议:
第一,建立自己的知识树,而不是刷题清单。前端知识体系虽然杂,但有一条清晰的骨架:语言基础、浏览器原理、网络协议、框架、工程化、性能优化、安全。每一个板块都准备几道自己做过的题、踩过的坑、写过的 demo,面试时无论怎么问都能接得住。
第二,手写题要练到闭眼能写。防抖节流、深拷贝、Promise、new、instanceof 这些是基本功,不要靠面试前一晚突击。每次练习都当作一次代码评审来对待,注释写清楚,边界情况处理好。
第三,项目复盘比项目数量重要。面试官问项目不是为了听你重复需求描述,而是想听到你在项目里做的技术选型、遇到的问题、怎么排查和解决的。比如你做过一个表格类的后台管理页面,好的回答不是“我用了 el-table 套数据”,而是“几千行数据渲染会卡顿,我分析后发现是大量响应式对象导致的,最后用虚拟滚动和精简响应式依赖解决了”。
第四,准备一套自己的“为什么”问答链。比如你简历里写了熟悉 Vue,那就要准备好:为什么选择 Vue 不选 React?Vue 2 的响应式缺陷是什么?Vue 3 为什么用 Proxy?依赖收集具体是怎么实现的?这套问题链,一个接一个的追问会非常密,答得住就说明你真会。
6.3 我踩过的坑与后续扩展思路
最后分享几个我当年准备秋招时踩过的坑,也是我在后来带新人时反复提醒的点。
第一个坑是只看不练。看十篇 Vue 响应式原理的文章,不如自己写一个最小版reactive。因为只有亲自动手,你才会发现Proxy的 getter 里track的依赖 key 是针对对象还是针对页面、嵌套对象重新代理时要怎么处理已代理对象的缓存问题。阅读时觉得懂了的知识,一动手就露馅。
第二个坑是忽略网络层。很多前端同学在面试前把 Vue 和 React 的源码文章刷了一遍,浏览器缓存、HTTPS 握手、HTTP 状态码这些基础反而不熟。但这些都是前端每天在用的东西,调试接口、排查线上问题、优化首屏都离不开。2020 年秋招的试卷里网络题占了不少比例,现在看这个趋势更明显。
第三个坑是没有总结错题的习惯。笔试完不做复盘,同样的知识点换个花样又错一遍。建议每次做完一套题,把错题按“JS 基础、浏览器、网络、框架、工程化”五大类归档,标注错误的根源是概念不清、原理不懂还是代码不熟,然后针对性地补练习。
这份试卷里的知识点,放在 2026 年的前端面试里依然很有参考价值。技术框架会迭代,但语言基础的考察逻辑、网络与浏览器原理的重要性、手写题的工程思维和表达能力,这些是不会变的。如果你正在准备秋招,不妨按这个框架去梳理一遍自己的知识体系,把每个点都过到“能讲清楚为什么”的程度。前端这条路很长,一场秋招笔试只是起点,扎实的基础才是后续走得远的地基。