1. 先看清这场仗:360前端校招客观题的科目分布与题型规律
2023年秋招,我投了360的Web前端技术岗,收到笔试链接时心里其实挺没底的。说实话,前端岗位的校招笔试,大厂之间差别极大,有的侧重算法,有的侧重框架源码,有的干脆全是性格测试。360这套客观题给我的第一感觉是:它不是在考你会背多少API,而是在考你在真实开发里踩过多少坑,有没有把前端的底层原理真正吃透。
这套客观题一共60道左右,考试时间80分钟,题型是单选、多选和判断混合。时间算下来每道题只有一分多钟,多选一旦犹豫,全局节奏就会崩。我考完之后把题目按知识点做了归类,大致分布如下:
| 知识点板块 | 占比估算 | 常见考查形式 |
|---|---|---|
| JavaScript核心机制 | 30%左右 | 输出顺序、this指向、原型链、闭包 |
| 浏览器与网络原理 | 20%左右 | 渲染流程、缓存、HTTP、跨域 |
| HTML/CSS基础 | 15%左右 | 布局、选择器优先级、BFC、语义化 |
| 框架与工程化 | 15%左右 | Vue/React原理、组件通信、webpack |
| 前端安全 | 10%左右 | XSS、CSRF、CSP、同源策略 |
| 数据结构与算法基础 | 10%左右 | 时间复杂度、排序、常见数据结构特性 |
这个分布说明了一个很关键的问题:JavaScript和浏览器原理占了半壁江山。如果你在备考时还在死记硬背Vue的生命周期函数、React的Hooks列表,那方向就偏了。客观题真正反复出现的是语言特性和运行机制题,这些内容不依赖框架,也不会因为版本迭代而过时,属于前端工程师真正的“内功”。
另外一个值得注意的规律是多选题的难度断层非常明显。单选题大部分是“看一眼就知道答案”的基础题,但多选题经常出现四五个选项里只有一个是错误项的情况,比如“以下关于事件冒泡的说法错误的是”,这种题如果没有把DOM事件流的细节理清楚,很容易多选一个就全扣分。
提示:360这套客观题不设倒扣分,但多选错选、漏选都不得分。所以遇到没把握的多选,宁可少选,不要乱选。
2. 浏览器原理与网络基础:客观题里占比最重的“埋伏区”
2.1 输入URL到页面展示,不是一道问答题,是一堆选择题
很多考生准备浏览器原理时习惯按简答题来背:“输入URL,DNS解析,TCP连接,发送HTTP请求,服务器返回,浏览器解析渲染……”这套流程确实没毛病,但客观题真正考的是把这条链路上的任意一环拆开,往深处问一层。
比如我印象很深的一道题:“浏览器在解析HTML过程中遇到没有异步标记的外部脚本时,会阻塞下面的哪一项?”选项里有DOM解析、CSS解析、图片加载、页面渲染。这道题看似简单,其实有几个层级。普通脚本会阻塞DOM解析没错,但如果你没有意识到脚本还会阻塞渲染,或者说不清async与defer对DOMContentLoaded事件触发的不同影响,那这道题就危险了。题干里“没有异步标记”这个限定词是关键,它是在逼你区分普通脚本、defer脚本和async脚本三者之间的差异。
我当时就是在这里停了一下。我大概花了半分钟回忆defer脚本的执行时机:defer会在文档解析完成后、DOMContentLoaded触发前按顺序执行;async脚本则是下载完成后立即执行,不保证顺序,也可能会在DOMContentLoaded之前或之后执行。这些细节如果你平时只是“听说过”,没在真实页面里通过Performance面板观察过,考场上很难迅速选对。
2.2 强缓存与协商缓存:选择题里的高频钉子户
Web前端岗位的校招客观题里,缓存机制几乎是必考,360这套题里至少出现了两道。一道直接问响应头Cache-Control字段设置为no-cache时的行为,另一道结合状态码询问协商缓存的判定过程。
这里很多人栽在概念上。no-cache并不是“不缓存”,而是“每次使用缓存前必须先向服务器验证”。真正的“不缓存”是no-store。这属于典型的文字陷阱题,如果你只看名字望文生义,必错。我建议备考时把缓存相关的字段按一张小表来记:
| 字段/场景 | 含义 | 典型状态码 |
|---|---|---|
| Cache-Control: max-age=3600 | 强缓存,3600秒内直接读本地副本 | 200 (from disk cache) |
| Cache-Control: no-cache | 每次必须回源验证后再决定是否使用缓存 | 304或200 |
| Cache-Control: no-store | 完全禁止缓存,每次请求都走服务器 | 200 |
| ETag/If-None-Match | 协商缓存,内容变更时返回新资源 | 304或200 |
| Last-Modified/If-Modified-Since | 协商缓存,基于时间戳,精度为秒 | 304或200 |
客观题考缓存还有一个隐藏考点:强缓存命中时会不会发请求?答案是不会。很多同学把强缓存和协商缓存混在一起答,选“会发送请求验证”,这就是典型的基础不牢。强缓存命中的根本定义就是“不需要请求服务器”,而协商缓存必须发送请求,只不过服务器可能返回304让你继续用本地缓存。
2.3 重排与重绘:性能优化的选择题常客
性能优化相关的客观题在360这套题里也有不少,主要围绕重排(reflow)和重绘(repaint)展开。题目通常是“以下哪个操作会强制触发重排”或者“下列属性变化时,哪个不会引起重绘”。
会强制触发重排的场景包括:读取offsetWidth、getBoundingClientRect、修改DOM几何属性、改变窗口大小、改变字体大小、向文档中插入节点等。这里面最容易忽略的是“读取”也算。比如你连续改了几次样式,然后在中间读了一次offsetHeight,浏览器为了给你返回准确的值,必须立刻执行一次重排,而不是积攒到下一帧统一处理。这类题目在真实开发里对应的就是布局抖动(layout thrashing)问题,写高性能前端的人一定遇到过。
至于重绘,主要涉及颜色、visibility、background等不影响布局的属性变化。注意visibility:hidden是触发重绘的,而display:none会触发重排,因为后者直接把它从文档流里移除了。这个区别也是选择题的最爱。
3. JavaScript执行机制与语言特性:从事件循环到原型链的真考点
3.1 事件循环:闭卷也容易错的输出顺序题
JavaScript的事件循环是360客观题里当之无愧的C位考点,出现频率相当高,而且每次都是以“写出以下代码的输出顺序”的形式出现,只不过在客观题里把选项变成了四个顺序。
我记得有一道题是这样的:
console.log('start'); setTimeout(() => { console.log('timeout'); }, 0); Promise.resolve().then(() => { console.log('promise1'); }).then(() => { console.log('promise2'); }); console.log('end');正确答案是start、end、promise1、promise2、timeout。这个顺序背后是宏任务与微任务的基本规则:同步代码先执行完,然后清空当前宏任务产生的所有微任务,最后才进入下一个宏任务。setTimeout虽然延迟是0,但它始终是一个新的宏任务,必须等微任务队列清空后才能执行。
但360显然不会只满足于这种基础版。我印象里有一道进阶版题,在Promise回调里嵌套了setTimeout,还加入了async/await。await本质上是Promise.then的语法糖,所以await后面的代码会被自动安排到微任务队列里。如果你的理解只是“await会等待结果再往下走”,没有意识到await会提前让出执行权,那么在输出顺序题里一定会错。这种题在考场上做的时候,我建议直接在草稿纸上画两条队列:宏任务队列和微任务队列,每遇到一个任务就往对应队列里推,执行时优先处理微任务队列,然后再看宏任务队列。这个办法虽然笨,但准确率极高。
3.2 this指向、原型链与闭包:语言基石类选择题
客观题里关于this的考查,套路非常固定:默认绑定、隐式绑定、显式绑定、new绑定,四条规则对应四种考题。最容易出错的是隐式绑定中“函数被赋值给变量后调用”的情况。
const obj = { name: '360', getName: function() { return this.name; } }; const fn = obj.getName; console.log(fn());这段代码里,obj.getName赋值给fn后,调用时上下文丢失,this指向undefined(严格模式)或window(非严格模式),所以输出不是'360'。考题如果混入箭头函数,那变化更多——箭头函数根本没有自己的this,它沿用的定义时所在作用域的this。这类题的选择项经常把window、undefined、obj、全局对象混在一起,稍不留神就会选错。
原型链的题目在360的客观题里也出现得很密集。常见考法有两种:一种是问instanceof的判断结果,另一种是给出一段原型继承代码,问对象上某个属性或方法查找的路径。写这类题的关键是理解原型链的本质是“对象与对象之间的关联”,而不是“类与类之间的继承”。JS通过内部属性[[Prototype]]形成链条,查找属性时沿着这条链向上走,走到头是Object.prototype,再往上就是null。
闭包相关的题通常是问作用域和变量提升的组合题。比如for循环里用var声明变量然后绑事件,最后点击输出什么,答案是打印出循环结束后的最终值。原因在于var没有块级作用域,所有循环迭代共享同一个变量环境,而事件回调执行时循环早已结束。let的块级作用域则每次迭代生成一个新的绑定,所以输出才是每个迭代的索引。这个考点现在看起来基础,但如果你平时都用框架模板语法,很少手写原生事件绑定,反而容易在考场上卡壳。
3.3 异步与Promise:由浅入深的陷阱题
Promise相关题目除了输出顺序,还有一类专门考查状态的题目。例如“某个Promise已经变为resolved状态后再调用then,回调是否还会执行”这种。答案是会。Promise的状态一经改变就永久固化,但then回调不管是在状态改变之前还是之后注册,最终都会被执行,区别只在于前者会被放入微任务队列等待执行,后者则立刻被安排到微任务队列。
另外一个360比较爱考的点是Promise.all与Promise.race的行为差异。特别是Promise.all在某个请求失败时,是否会影响其他请求的发送。很多人误以为Promise.all只能“同时”发起请求,但实际上发起请求不是Promise.all做的,Promise.all只负责接收一个Promise数组并聚合结果。如果你在业务里用Promise.all包了一层,里面的请求其实早就各自发送了。所以点击提交后,即使其中一个接口报错,其他接口的请求也已经发出去了,这在实际开发中经常引发“为什么我明明报错了还创建了订单”之类的问题。判断题很容易在这里出。
4. 框架、工程化与网络协议:拉开差距的隐藏分水岭
4.1 Vue与React的底层机制选择题:考的是封装与抽象思维,不是API背诵
360客观题里框架部分的比例不算高,但几乎没有一道是“背API”的送分题,而是在考你对框架设计思路的理解。
Vue相关的选择题最喜欢考响应式原理。核心是Object.defineProperty和Proxy的区别,以及Vue 2到Vue 3响应式重构的动机。有一道题问“Vue 3使用Proxy替代Object.defineProperty之后,以下哪个能力是新增的”,选项里包括监听数组下标变化、监听动态新增属性、监听Map和Set、以上都是。答案是以上都是。Vue 2的defineProperty只能在初始化时遍历对象属性做劫持,所以:
- 新增的属性不是响应式的(需要Vue.set处理)
- 直接通过下标修改数组元素无法被检测(需要重写数组方法解决)
- Map、Set根本没法用defineProperty拦截
这些“历史包袱”在Vue 3里被Proxy全部解决,因为Proxy是代理整个对象而不是某个属性。这种选择题本质上考察的是“当我用Vue 3写代码时,哪些写法是安全的”这个实际问题。
React相关的题则集中在单向数据流和组件状态更新上。印象比较深的一道题是关于“React中调用setState之后,在同步代码里立刻读取state,得到的是什么”,答案是更新前的旧值。React的setState在未开启并发特性时虽然已经是异步批处理,但更关键的设计意图是“state是快照而非实时变量”。如果你在事件处理函数里连续调用三次setState,React会把这三次合并成一次更新,并且updater函数接收到的prevState是同一份基础值。这类题在真实开发里非常实用,但教材和文档很少把“为什么”讲透。
4.2 工程化与模块化:webpack与构建链路
工程化方面的客观题数量不多,但每道都很有代表性。主要集中在模块化规范和webpack构建机制上。
CommonJS与ESModule的区别是重中之重。一道比较经典的选择题:“在浏览器环境中,以下关于ESModule的说法错误的是”,错误选项经常是“ESModule是静态分析,因此不能做条件加载”这种正确的表述,而正确选项是“ESModule的import命令会被提升到模块顶部”。另一个常见错误是“ESModule没有缓存”,实际上import的模块会被缓存,多次import同一个模块只会执行一次。
webpack相关题目更多是概念辨析,比如loader和plugin的区别。loader本质上是一个转换函数,负责把某种文件转换成JavaScript可以处理的模块;plugin则是在webpack打包生命周期的各个阶段注入钩子,能做的事情远比loader多。题目通常给出“压缩文件用loader还是plugin”“代码分割用哪个配置项”这种实际场景。TerserPlugin压缩JS是plugin的作用,而babel-loader、css-loader这种“把输入变成模块”的角色才是loader。
构建链路里还有一个高频考点是Tree Shaking。它依赖ESModule的静态结构,在编译阶段就能确定哪些导出未被使用,从而在打包时把无用代码移除。所以Tree Shaking的前提条件是“必须使用ESModule语法”,CommonJS是做不到这一点的,因为require是运行时执行的,编译器无法静态分析。选择题经常把这个条件藏在选项里,判断你是否真的理解原理而不只是听说过这个词。
4.3 跨域与HTTP:前端工程师的“必修底层”
跨域问题在360客观题里出现得很直接:给出一个页面URL和一个请求URL,问你“以下哪个属于跨域”。同源的定义是协议、域名、端口三者完全一致,任意一个不同就算跨域。比如https://a.example.com向http://a.example.com发请求就属于跨域,因为协议不同。
CORS相关题目最常考的是“跨域请求时,哪些情况下会触发预检请求”。这个要记住几个条件:
- 使用了非简单方法:PUT、DELETE、PATCH等
- 设置了自定义请求头:如Authorization、X-Custom-Header
- Content-Type不是简单类型:如application/json
如果你发的是GET请求,Content-Type是text/plain,不携带自定义头,那就是简单请求,不会触发预检。实际开发里,很多前端同学发现“为什么我的POST请求会先发一个OPTIONS”,就是因为Content-Type用了application/json。这个在客观题里几乎年年见。
HTTP相关内容里还考了状态码的语义,特别是304、403、404、500、502、504这几个在Web开发里最高频的状态。有一道题问“504 Gateway Timeout与502 Bad Gateway的区别”,前者是网关没有在规定时间内收到上游服务器的响应,后者是网关接收到了上游的无效响应。这两个状态码在代理场景下非常容易混淆,客观题把它们放一起出,就是在考察你是否在真实联调环境里排查过问题。
5. 安全视角下的前端题目:360技术岗独有的“隐藏加分项”
5.1 360为何在客观题里考XSS与CSP
按理说,校招前端笔试对安全知识的要求通常不会太高,最多问一句“XSS怎么防”。但360本身就是做安全起家的,这套客观题明显在安全板块上增加了深度。
XSS相关的题在选择题中反复出现,核心考点是XSS的三种类型:反射型、存储型、DOM型。反射型和存储型的区别是反射型不落库、一次性攻击;存储型会把恶意脚本存进数据库,每次用户打开页面都被执行;DOM型则完全是浏览器端的DOM操作导致,不经过服务器。选择题经常给一个场景,让你判断属于哪种类型,或者问哪种XSS能通过后端过滤彻底防止。其实后端过滤能防反射型和存储型,但DOM型因为污染发生在浏览器端,后端很难完全防御,必须从前端代码层面入手。
CSP(内容安全策略)的题目也很典型。考察方式通常是“以下哪条CSP指令可以限制脚本来源”,正确选项是script-src。CSP作为一种响应头策略,能让浏览器只执行白名单来源的脚本,即使攻击者注入了script标签,也会被浏览器拦截。这个是前端防御XSS最有效的手段之一,360爱考它一点也不奇怪。
5.2 CSRF与同源策略:一套逻辑可以同时应对多道题
CSRF的考查不如XSS密集,但出现了就必定是结合Cookie机制的。核心逻辑是:浏览器会自动携带Cookie,所以攻击站点可以诱导已登录用户发起恶意请求。防御方案有几种:
- 校验Origin/Referer
- 使用CSRF Token
- 设置SameSite Cookie属性
其中SameSite是最新最热门的方向,因为它从浏览器层面直接阻断跨站携带Cookie。选择题会问“设置SameSite=Strict与SameSite=Lax的区别”,或者“以下哪个属性可以防止CSRF”。如果你的知识里正好覆盖了Secure的用途(只在HTTPS连接中发送)和HttpOnly的用途(阻止JavaScript访问Cookie),就很容易区分出正确答案。但如果你把SameSite、Secure、HttpOnly三项的用途搞混,这类题基本必错。
这里有一个很实用的备考方法:把所有安全相关机制整理成一张“作用对象”表。比如XSS针对的是脚本注入,CSRF针对的是请求伪造,点击劫持针对的是iframe覆盖。只要明确了每个机制针对的攻击类型,看到题目场景就能反向定位考点,正确率会提升很多。
5.3 前端安全客观题的答题思路
客观题里安全部分我总结出了一个答题顺序:先判断题干描述的攻击类型,再看选项里的每个措施作用于哪一环节。比如“某网站评论区用户可以提交包含script标签的内容,其他用户打开页面时脚本被自动执行,这属于什么攻击?如何防御?”但客观题不会这么完整地给你整个场景,它会把攻击类型和防御措施拆开成多个小题,分布在试卷的不同位置。
做安全题要额外注意一个反直觉的点:HttpOnly并不能防御XSS的全部类型。它只能阻止JavaScript读取Cookie,但DOM型XSS照样可以操作DOM、伪造页面,网络钓鱼和键盘记录依旧可能发生。所以“设置HttpOnly即可彻底防御XSS”这种选项,看上去很安全,实际上是最大的陷阱。
6. 考场实战复盘:时间分配、取舍策略与错题补救
6.1 我的时间分配:前60分钟做完,后20分钟复查
80分钟做60道题,平均每题只有1分20秒,时间其实相当紧张。我的策略是:
- 单选和判断题快速过,控制在40分钟内
- 多选题放慢速度,每题至少花1分钟,用30分钟处理
- 最后10分钟统一复查标记过的题目
我先把一眼能判断答案的题目做完,遇到拿不准的,在题目序号上做标记,不纠结,先跳过去。因为客观题的题干信息量通常不大,你纠结3分钟未必能提升正确率,反而会影响后续题目的状态。复查阶段我会重点关注两类题:一类是“下列说法不正确的是”这种反向提问的题,另一类是多选里只选了部分选项的题。
反向提问是客观题最大的陷阱点。很多人读题时只看选项内容本身对不对,忽略了题干问的是“错误”还是“正确”。整场考下来,我至少遇到5道“不正确的是”这类反向题。我的方法是:在读选项前先把题干的“正确/不正确”圈出来,然后在草稿纸上标明“找错项”或“找对项”,再逐个选项对照。听起来很基础,但考场上大部分人是因为粗心丢的分,而不是不会。
6.2 错题复盘:最容易翻车的三类题
考完趁记忆还热乎,我立刻回忆并记录了几道拿不准的题。复盘后发现,最容易翻车的集中在三类。
第一类是浏览器渲染流程的细节题。能说出“解析HTML构建DOM,解析CSS构建CSSOM,生成渲染树,布局,绘制”这个流程的人很多,但一问到“CSS会阻塞DOM解析吗”“脚本会阻塞CSSOM构建吗”这种交叉阻塞问题时,很多人就含混了。正确答案是:普通脚本会等待CSSOM构建完成后再执行,但CSS本身不阻塞DOM解析,它只阻塞渲染。这道题给我的启示是:备考浏览器原理必须把“阻塞关系”当一张依赖图来记,而不是背一条流水线。
第二类是事件循环与其他机制组合的多选题。单考事件循环很多人会,但一旦把事件循环、DOM事件、requestAnimationFrame、async/await这些机制混在一起,就会顾此失彼。我遇到的一道题就是在Promise里嵌套了事件监听触发,又问页面渲染时机。这种题需要你把“任务队列机制”和“渲染时机”两套知识同时激活,难度确实高。我的经验是:事件循环题先看有没有渲染相关的内容,如果有,注意requestAnimationFrame的回调会在渲染前执行,而Promise微任务则会在当前渲染任务之前全部清空。
第三类是跨域CORS预检请求的边界条件。我错在一个细节上:Content-Type为text/plain的POST请求属于简单请求,不会触发预检;但如果你通过fetch设置了这个Content-Type,同时加了自定义header,它又会变成需要预检的请求。这两个条件叠加在一起,我就漏选了。考后翻文档确认,判断是否简单请求不能只看Content-Type,要三个条件同时满足才行。
6.3 给下一届的备考建议:以“为什么”代替“是什么”
总结这次360校招技术岗Web前端客观题的备考经验,我最想给的建议只有一条:复习时多问自己一句“为什么”。
- 不要只记“Vue 3改用Proxy实现响应式”,要问“为什么不用defineProperty”
- 不要只背“setState是异步的”,要问“为什么不能同步读取到最新state”
- 不要只背“跨域有预检请求”,要问“什么条件会触发预检”
- 不要只背“HttpOnly保护Cookie”,要问“它在XSS攻击链中真正解决的是哪一环”
客观题的选项设计就是针对这些“为什么”来的。你理解得越接近底层,选项之间的细微差别就越容易分辨。而且这种“为什么”导向的复习法,不但应试有效,对后面的技术面也帮助巨大——360的面试官在技术面环节会追问你在笔试里涉及到的知识点,如果你当时是靠“背答案”通过的客观题,面试时会非常被动。我在后面的面试中就被顺着浏览器缓存题的选项一路追问到了HTTP历史版本的缓存字段设计,以及Service Worker缓存策略在真实业务里的取舍。
从笔试到面试,360对Web前端工程师的考察路线其实相当清晰:基础扎实、理解原理、能解决真实问题的人,才是他们想要的人。客观题只是第一道筛子,把“知其然”但“不知其所以然”的人筛掉,把真正花时间研究过底层机制的人留下来。