☰
奇安信前端笔试真题解析:从基础到安全的全面备考指南
2026/10/31 11:04:38 网站建设 项目流程

2019年那时候,奇安信还没有从360体系里完全独立出来多久,春招笔试的题目风格其实已经很有辨识度了。我印象里那套前端开发试题整体难度中等偏上,不算变态,但覆盖面很广,基础不扎实的人很容易在及格线附近徘徊。今天把这套题掰开揉碎讲一讲,不只是给答案,更重要的是讲清楚每一类题目背后的考察逻辑和备考思路。不管你是准备应届生校招,还是社招想跳槽去安全行业的技术团队,这套题里的知识点都值得过一遍。

1. 试题整体印象:怎么看懂一套前端笔试题的“出题人意图”

拿到任何一套笔试题,先别急着埋头做题。我习惯先花五分钟把整张卷子扫一遍,标出题目类型和分值分布,这时候出题人的“口味”基本就暴露了。

1.1 奇安信2019春招前端卷的题型构成

从整体来看,这套题大致分为四个板块:基础理论题、代码输出题、手写实现题和开放设计题。基础理论题覆盖HTML、CSS、JavaScript、浏览器原理和网络基础;代码输出题主要考察JavaScript的语言特性,比如作用域、闭包、异步顺序;手写实现题则集中在数组去重、深拷贝、防抖节流这类经典场景;开放设计题会给你一个业务场景,让你描述技术方案。

这种结构说明什么?说明奇安信的前端团队在招人时,非常看重候选人的语言基本功和工程思维,而不是看你背了多少框架API。那一年Vue和React已经非常流行了,但这套题里框架相关的考点占比并不高,反而基础能力占了大头。这和当时很多大厂的出题风格是反着来的——当时不少公司一上来就问Vue生命周期、React diff算法的细节。

后来我复盘了一下,这个思路其实和奇安信的业务属性高度相关。安全公司做的前端产品,比如管理后台、态势感知大屏、终端管控界面,绝大多数时候不是面向海量C端用户的,而是面向企业客户和安全运维人员的。这类产品对稳定性、数据准确性、安全性要求极高,花里胡哨的交互反而是次要的。所以面试官更在意你能不能写出靠谱的代码,而不是能不能背出某个框架的源码细节。

1.2 这套题的备考价值在哪儿

哪怕你不是去奇安信面试,这套题的参考价值也很大。原因很简单:它考察的知识点全部是前端领域“保值率”最高的那部分。反而是那些当年很热门的框架题,放到今天可能早就过时了。ES6+语法、事件循环、原型链、HTTP缓存、跨域方案这些内容,今天依然是前端面试的绝对主力。

所以如果你现在正在准备前端面试,与其漫无目的地刷题,不如拿这套题当一次自测。能把这套题做到80分以上,至少说明你的JS基础是过关的,面对大多数公司的笔试环节都不会太虚。

2. HTML与CSS考点:安全公司会在布局题里埋什么坑

很多人对HTML和CSS题不以为然,觉得就是背背标签、记记属性。但实际上,奇安信这类公司的前端笔试里,CSS题的陷阱往往藏得很深。

2.1 盒模型与BFC:不只是概念题

盒模型是CSS的第一课,但能把content-box和border-box的区别讲透的人并不多。标准盒模型(content-box)的width只包含内容区,而IE盒模型(border-box)的width包含内容、内边距和边框。实际开发里,我们普遍通过box-sizing: border-box来统一全局盒模型,因为这样更符合人脑直觉——你设置多大的宽度,元素就占多大的宽度。

BFC(块级格式化上下文)同样是高频考点。BFC可以理解为一个独立的渲染区域,内部元素的布局不会影响外部。触发BFC的方式有:float非none、position为absolute或fixed、overflow非visible、display为inline-block或flex等。常见的应用场景有两个:一是清除浮动,当子元素全部浮动导致父容器高度塌陷时,给父容器设置overflow: hidden触发BFC,父容器就会重新包裹子元素;二是防止 margin 折叠,两个兄弟元素的上下margin在垂直方向会取较大值合并,但把它们各自放进独立的BFC里,就可以避免折叠。

这里有个实操经验:真正做后台管理系统的时候,overflow: hidden触发BFC来清除浮动这个方案,在新老浏览器上表现都不错,但也有副作用——如果子元素需要溢出显示下拉菜单,会被父容器裁掉。所以现代项目里我一般优先用display: flow-root或者直接改用flex布局,这两种方式干净利落。

2.2 经典布局题:圣杯布局与双飞翼布局

圣杯布局和双飞翼布局是CSS笔试的常青树,它们要解决的核心问题是一样的:左右两栏固定宽度,中间主内容栏自适应宽度,且中间栏在DOM结构上优先渲染,这对首屏加载和SEO友好。

圣杯布局的思路是:三栏都用float: left,中间栏宽度设为100%,然后利用padding为左右栏腾出位置。左右两栏通过负margin移动到对应位置——左栏margin-left: -100%让它上移到中间栏的左侧起点,右栏margin-left: -自身宽度让它上移到最右侧。最后给三栏的父容器设置左右padding,宽度等于左右栏的宽度。

双飞翼布局则换了个思路:中间栏内部再套一层div,左右两栏的定位方式和圣杯一样,但为中间栏内容腾位置时,不用父容器的padding,而是给中间栏内部那层div设置左右margin。这样父容器宽度就是100%,左右栏直接贴在两侧,省去了相对定位的步骤。

实际笔试里这种题不一定要求你手写完整代码,更多是让你说清楚实现思路和区别。但我的建议是,哪怕不写完整代码,也要把这个过程推导清楚,同时提一句“现在都用flex或grid实现了”,这样面试官会觉得你既懂老方案,也跟得上新趋势。

2.3 垂直水平居中的N种姿势

垂直水平居中几乎每次笔试都会出现,而且出题人常常会补一句“元素高度未知”。这个限制条件很关键,它排除了line-height和绝对定位配合负margin的方案。

我一般会给面试官按场景分类:

  • 元素定宽高:绝对定位 + 四角为0 +margin: auto,这个方案兼容性最好;
  • 不定宽高:绝对定位 +transform: translate(-50%, -50%),用CSS3解决,唯一注意父容器要相对定位;
  • flex方案:父元素display: flex; align-items: center; justify-content: center;,这是当前项目里的首选,代码量最少;
  • grid方案:父元素display: grid; place-items: center;,更简洁。

实话说,现在项目里我从来不给弹窗用transform居中,而是直接用flex。因为transform会创建新的层叠上下文,有时候会连带出z-index和定位问题。笔试写方案的时候,可以提一句“flex最稳,transform有层叠上下文副作用”,这种细节会让你跟其他候选人明显拉开差距。

3. JavaScript核心考点:输出题背后藏着多少语言特性

JS部分永远是前端笔试的主导,奇安信也不例外。这套题里代码输出题占比不低,而且专门挑那些“看似简单,一写就错”的语法糖来考。

3.1 作用域、闭包和立即执行函数

经典题目:var在for循环中配合setTimeout打印的问题。连续输出10个10,原因在于var声明是函数作用域,循环体里的i是同一个变量,等到定时器回调执行时,循环早已结束,i已经变成了10。解决办法有两个:用let声明,让每一次循环都绑定一个新的i;或者用立即执行函数(IIFE)传递当前值。

闭包在奇安信这类基础题里几乎是必考的。比如问你以下代码输出什么:

function foo() { let count = 0; return function () { count++; console.log(count); }; } const f = foo(); f(); f();

答案是1, 2。核心考点是:内部函数引用了外部函数的变量,外部函数执行结束后,变量没有被垃圾回收,而是被内部函数继续持有。这也解释了为什么闭包可能造成内存泄漏——如果你在DOM事件里用了闭包,又忘了移除事件绑定,整个作用域链都会残留。

3.2 this的指向问题:别背口诀,画调用栈

this指向是JS笔试的重灾区,也是很多工作两三年的前端说不清的地方。出题人很爱把this和对象调用、普通函数调用、箭头函数混在一起出题,比如:

const obj = { name: 'qihoo', getName: function () { return this.name; }, getNameArrow: () => { return this.name; }, }; console.log(obj.getName()); console.log(obj.getNameArrow());

第一行输出qihoo没问题,this指向调用者obj。第二行就有意思了,箭头函数没有自己的this,它的this是在定义时从外部作用域捕获的,所以这里的this指向全局对象,this.name是undefined。

我不建议死记“谁调用指向谁”这种口诀,因为遇到箭头函数这口诀立刻就失效了。更好的分析方式是:先把函数调用方式画出来,看它是普通调用、对象方法调用、call/apply调用还是new调用,然后逐层确定this;如果函数是箭头函数,直接往上找最近的外层普通函数的this。这套逻辑可以应对所有this考题。

3.3 事件循环与异步顺序

输出题里最能拉开差距的就是事件循环。比如考这样的代码:

console.log('a'); setTimeout(() => { console.log('b'); }, 0); Promise.resolve().then(() => { console.log('c'); }); console.log('d');

输出顺序是a d c b。这里考察的微任务和宏任务执行顺序:同步代码先执行,然后本轮事件循环中的微任务(Promise的then回调)优先于宏任务(setTimeout回调)执行。即使setTimeout的延迟是0,它也会被放进宏任务队列,要等下一轮事件循环才轮到。

2019年的考题还很少问到async/await和微任务嵌套的复杂情况,但现在这里已经成了必考深水区。我的建议是,把事件循环的机制彻底搞清楚:执行栈清空后,微任务队列会一次性清空,然后再取一个宏任务执行;宏任务执行过程中又会产生新的微任务,这些微任务会排在下一次宏任务之前执行。把这条链路理解透,不管题目怎么嵌套你都不会懵。

3.4 对象与数组方法:map、filter、reduce的熟用程度

数组方法题在笔试题里也经常出现。比如['1', '2', '3'].map(parseInt)的输出是什么?答案是[1, NaN, NaN]。原因是parseInt接收两个参数,map回调会把当前值和索引传进去,所以第二次调用是parseInt('2', 1),第三次是parseInt('3', 2),都是无效进制,返回NaN。

这类题考察的不是你会不会用map,而是你清不清楚map回调的完整参数列表(当前值、索引、原数组),以及parseInt的完整参数签名(字符串、进制基数)。所以平时写代码多留意标准API的完整签名,少依赖记忆中的“常用方式”,这种坑踩一次就能记住。

4. 框架与工程化考点:安全公司也躲不开的范畴

虽然前面说这套题基础占比大,但框架和工程化的内容也没有缺席。尤其是在开放题和应用题里,Vue/React的使用经验是加分项。

4.1 Vue与React:从“会写页面”到“说清原理”

笔试中常见的框架问题有:Vue的双向绑定原理、虚拟DOM的作用、key的作用、组件通讯方式、生命周期钩子对比。React的常见考点则是:state与props的区别、setState的异步性、受控组件与非受控组件、 useState/useEffect的依赖数组、Fiber架构解决了什么问题。

奇安信前台产品偏管理类和展示类,Vue的普及率在我印象里比React高一些,所以Vue出题概率更大。重点准备这几个问题:

  • computed和watch的区别:computed是声明式地根据依赖数据计算出新值,有缓存;watch是监听数据变化执行副作用操作,用于异步或开销较大的操作。
  • v-if和v-show的区别:v-if是条件渲染,不满足条件直接不渲染DOM,切换有渲染销毁成本;v-show是css的display切换,只是视觉隐藏,适合频繁切换的场景。
  • key的作用:key帮助diff算法识别节点复用,当列表顺序变化时,正确的key可以最小化DOM操作。不建议用数组索引当key,因为增删元素后索引会变,可能导致状态错乱。

4.2 前端性能优化:笔试爱问,实际项目更要会

安全产品的前端页面往往数据量大、图表多、刷新频繁,性能优化是实际问题。笔试里的性能优化题通常不要求你写代码,但要求你按场景列出方案。

我通常会按浏览器工作流程来组织答案:网络层面,做资源压缩合并、HTTP缓存、CDN分发;渲染层面,减少DOM操作次数,避免强制同步回流,用文档碎片或虚拟列表处理长列表;代码层面,做按需加载和懒加载,拆分首屏代码,优化图片格式和尺寸。

这里有一个很多人的误区:一说性能优化就在扣JS执行时间,但实际上首屏性能的大头通常在资源加载和网络请求。2019年我优化一个数据中心管理后台时,把十几个第三方依赖全部改为按需引入,首屏体积从2.4M降到800K,加载时间从5秒变成2秒左右,这个收益远大于优化几个函数执行耗时。所以面试时一定要先说网络和加载层面的优化,再说渲染和运行时的优化,这更符合真实场景的优先级。

4.3 工程化工具链:webpack问题怎么答不露怯

工程化题偶尔会考webpack的构建流程、loader和plugin的区别、如何做代码分割。这类题其实有个答题模板:先说整个构建过程是入口解析、依赖收集、模块编译、代码生成这几个阶段;loader负责对模块源代码进行转换,是在编译单个模块时执行;plugin则在整个构建流程里都可以介入,通过钩子机制完成更广泛的任务。只要把base流程说清楚,然后举一两个常用的loader和plugin例子,比如babel-loader处理ES6+、eslint-loader做代码检查、HtmlWebpackPlugin生成HTML、TerserPlugin做代码压缩,基本就能过关。

5. 安全公司面试的隐藏彩蛋:前端安全题才是重头戏

奇安信做的是安全业务,前端笔试题里几乎一定会出现安全相关的考点。这既是奇安信面试的特色,也是非安全公司面试容易忽略的盲区。把这块准备好,你能给面试官留下极其深刻的印象。

5.1 XSS攻击与防御:别只知道alert弹窗

XSS(跨站脚本攻击)是前端安全里最经典的考点。基本原理是攻击者把恶意脚本注入到页面中,当其他用户访问这个页面时,脚本在用户浏览器中执行,从而盗取Cookie、篡改页面内容或者发起请求。

防御手段有三个层次。第一层是输入过滤,用户输入的内容一律当作数据而非代码处理,前端要对特殊字符做转义,比如<替换为&lt;,>替换为&gt;;第二层是输出编码,在不同上下文(HTML标签内、属性内、JavaScript内)要用不同的编码方式;第三层是设置安全响应头,比如Content-Security-Policy(CSP),可以限制页面能加载的资源和脚本来源,就算脚本被注入也执行不了。

5.2 CSRF与CORS:跨域问题的安全视角

CSRF(跨站请求伪造)的经典场景是:用户登录了银行网站,又去访问了恶意网站,恶意网站利用浏览器自动携带Cookie的特性,构造一个跨站请求,让用户在不知情的情况下完成转账或修改操作。

防御CSRF的思路主要有:校验请求头中的Origin或Referer;用token机制——后端生成一个随机token存到表单或请求头里,服务器验证token是否有效;设置Cookie的SameSite属性,限制跨站请求是否携带Cookie;用自定义请求头,因为跨站请求无法自动构造自定义头。

CORS(跨域资源共享)和CSRF容易混淆,但考点完全不同。CORS是浏览器对外部请求的一种协议规范,当页面请求了其他域的接口,浏览器会先发起预检请求(OPTIONS),服务器通过响应头里的Access-Control-Allow-Origin来声明是否允许跨域。前端开发中常见的跨域方案除了CORS外,还有JSONP、代理服务器等。

有一道题让我印象很深,题目问的是“前端做了CORS配置,能彻底解决跨域安全问题吗”。正确答案当然是不能。CORS只是浏览器层面的访问控制,接口本身是否安全还需要后端做鉴权验证。你能在理解CORS的同时指出这个边界,面试官会明显高看你一眼。

5.3 路径遍历与文件上传场景

热词里提到了“奇安信 输入验证:路径遍历”,这个知识点同样会出现在笔试题甚至实际产品中。路径遍历是指攻击者通过构造../这样的特殊路径,访问服务器上本不该被访问的文件。前端在接收文件上传、下载参数时,一定要对路径参数做白名单校验,不能直接拼接用户输入到文件路径里。

比如下载文件的接口,如果后端拿到的文件名参数是../../etc/passwd,拼接路径后就可能读取到系统敏感文件。前端的责任是:上传文件时校验文件类型,限制文件大小,对文件名做合法性校验;下载文件时不要把用户输入直接作为路径参数传递,而是建议后端用映射ID来定位文件。

6. 手写实现题:这些代码现在就可以背下来

手写题是笔试里最能直接反映编码能力的一环。说实话,这部分题是有套路的,核心题型不多,练熟了就是送分题。但如果没练过,现场写很容易翻车。

6.1 数组去重:至少给出三种思路

数组去重是最经典的手写题,也是我当年笔试的第一道手写题。现在回想起来,这道题的关键不是写出来,而是写得全面、有层次。

最朴素的方案是双重循环或使用indexOf做去重,时间复杂度较高。用Set是最简洁的方案,一行代码搞定:[...new Set(arr)]。但面试官往往不希望你就此打住,还会追问:如果数组里有对象,Set去重还靠谱吗?这时候要答到Array.from(new Set(arr.map(item => JSON.stringify(item))))来对对象序列化后去重,或者用reduce配合Map来做按属性去重。

我写题时的习惯是先说清楚各种方案的优缺点,再选一种代码量适中的方案写上。除非题目明确要求性能最优,否则不要一上来就写奇技淫巧。

6.2 深拷贝:考你会不会考虑边界情况

深拷贝题的高频程度不用多说。手写一个递归深拷贝,看起来简单,但能拿满分的人不多。

基础版本是判断值类型和引用类型,值类型直接返回,引用类型创建新对象后递归复制属性。但要注意几个边界:数组和对象要分别处理;要防止循环引用,否则会栈溢出;函数的特殊处理不算重点,但要说清楚。

比较稳妥的写法是:

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

这里用WeakMap来处理循环引用是关键点。很多人写深拷贝不考虑循环引用,一遇到a.self = a这种结构就爆栈。能主动想到用WeakMap处理这个问题,这道题基本稳了。

6.3 防抖和节流:应用场景比代码本身更重要

防抖(debounce)和节流(throttle)也是手写题里的常客。防抖的核心是“延迟执行”,在事件触发后的一段时间内如果再次触发就重新计时,适用于输入框搜索联想、窗口resize后的计算;节流的核心是“限制执行频率”,一段时间内只执行一次,适用于滚动加载、按钮连点、拖拽等场景。

一个比较完整的防抖实现是:

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

注意这里用apply绑定this,并且...args接收参数,这两个细节很多培训班出来的候选人都会漏。如果面试官让你说应用场景,别只说搜索输入,可以补充一个“请求取消”的场景:用户快速点击多个筛选条件时,只保留最后一个请求结果,既能防止重复请求,也能避免旧请求覆盖新请求。

6.4 其他高频手写题清单

除了上面几道,下面是2019年前后前端笔试中出现频率很高的手写题,建议每道题都能做到10分钟内独立写出可运行版本:

  • 实现一个new操作符
  • 实现Function.prototype.call/apply/bind
  • 实现一个Promise.all
  • 实现一个简单的发布订阅(EventEmitter)
  • 实现instanceof的底层逻辑
  • 实现一个简单的Object.create
  • 洗牌算法(Fisher-Yates)
  • 手写一个简单的MVVM响应式系统

这些题目虽然看着多,但其实是相互关联的。比如Promise.all的核心是理解Promise的执行和状态流转,EventEmitter的核心是维护一个事件回调数组。把底层逻辑想明白,代码写出来就是水到渠成的事。

7. 时间分配与答题策略:笔试比的不只是会多少

一套笔试题做下来,很多人挂掉的原因不是不会,而是来不及做。笔试的时间分配直接决定你的得分上限。

7.1 拿到卷子先做这三件事

第一,快速浏览全卷,把所有题目分成“秒杀题”“思考题”“硬骨头”三类。第二,先把秒杀题做完并检查一遍,保证拿满基础分。第三,再去做思考题,最后进攻硬骨头。不要把时间耗在某一题上,比如深拷贝写了一半卡住,就先跳到下一题,最后再回来补。

我见过不少人在一道手写题上死磕了30分钟,结果后面10道基础选择题全没做。这种策略性失误完全可以通过考前模拟来避免。建议考前自己卡着时间做两套完整的真题或高质量模拟题,别只看题不解题。

7.2 代码题的“过程分”怎么拿

手写题即使写不出来完整答案,也要把自己的思路分步骤写下来。比如深拷贝写不出来,你写了“先判断类型,然后递归复制,注意循环引用”三行字,也能拿一部分过程分。更聪明的做法是在注释里写清楚思路,然后写出一个不完美但思路正确的版本——笔试批卷人更看重你解决问题的思维路径,而不是最后的代码是否一字不差。

另外,手写题的代码格式一定要干净。变量命名合理、缩进统一、函数抽取清晰,这些细节都能加分。别小看这些印象分,在水平接近的候选人里,代码风格好的往往优先进面试。

7.3 安全公司的笔试复习重点

既然目标公司是安全行业,除了常规前端知识,一定要多花时间看安全和业务结合的部分。我的建议是准备一个“安全场景下的前端项目经验”故事:比如你曾经处理过登录表单的输入校验、给文件上传接口做过类型和尺寸校验、用CSP增强过页面的安全性,或者改过接口的鉴权逻辑防止越权访问。把这些真实经历整理成一小段有背景、有举措、有结果的描述,比背十个面试题模板都管用。

8. 那些年我踩过的笔试坑和回头看的心得

现在回头看看2019年的前端笔试,再对照这些年带团队的面试经历,有些心得值得和还在准备笔试的你说一说。

8.1 笔试挂掉最常见的三个原因

第一,基础题不仔细读题。很多题目不是不会,是题眼没看到。比如题目要求用ES5实现防抖,你上来就用let、箭头函数,直接扣分。第二,手写题只看逻辑不看边界。代码在正常输入下没问题,但一遇到空数组、空对象、循环引用就崩了,这种代码在工程化标准里是过不了评审的。第三,框架经验写得太满,基础一塌糊涂。笔试就是一面照妖镜,你平时靠框架和工具掩盖的知识盲区,在基础题面前全都会现原形。

8.2 从面试官视角看,什么样的候选人能过

我后来也参与过校招笔试的出题和阅卷,站在面试官的角度,我会优先看三样东西:一是代码的完整性,边界条件和异常处理有没有考虑;二是思路的清晰度,即使题目没完全做出来,注释和流程描述也能看出思考过程;三是对安全相关的意识,哪怕笔试没有专门的安全题,候选人在回答性能优化、跨域问题时能否主动提到安全风险,这会让我觉得这个候选人很契合公司业务。

8.3 给正在准备前端笔试的你的实操建议

如果你现在是准备阶段,我建议你做两件事。第一件,把本文提到的所有手写题全部写一遍,写到不需要思考就能默写的程度。笔试现场是有时间压力的,如果这些基础题你在脑子清醒时都不能秒写,现场环境会更糟。第二件,找一个有经验的前端帮你做一次模拟面试,让他用这套题的类型抽考你,重点看你能不能边说思路边写代码,而不是默默写完。很多笔试挂掉的人,不是不会写,是不敢在时间压力下写,这个问题只能靠模拟场景来克服。

这组题放在今天依然不过时,因为它考的从来不是某个特定版本的框架API,而是你对前端底层的理解深度。这份理解力一旦建立,不管面哪家公司,笔试环节都不会对你构成真正的阻碍。

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

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

立即咨询