前端面试通关包(2026版,完整版)
适用人群:1~5 年及以上前端工程师
使用方式:先按模块通读,再挑你最薄弱的题目反复复述。
目标:不是"背答案",而是能把问题讲清楚、讲完整、讲出工程思维。
一、JavaScript 核心高频题
1. 什么是事件循环?宏任务和微任务有什么区别?
面试回答
JavaScript 是单线程执行的,但浏览器和 Node.js 运行时会把一些异步任务交给宿主环境处理,例如定时器、网络请求、DOM 事件等。
当主线程执行完当前调用栈里的同步代码后,会去任务队列里取下一批任务执行,这个不断"执行同步代码 -> 清空微任务 -> 取下一个任务"的过程,就是事件循环。
通常可以这样理解:
- 宏任务(Task):script、setTimeout、setInterval、I/O、UI 渲染、postMessage 等
- 微任务(Microtask):Promise.then/catch/finally、MutationObserver、queueMicrotask 等
执行顺序一般是:
- 执行一整个宏任务
- 执行该宏任务产生的所有微任务,直到微任务队列清空
- 进行必要的页面渲染
- 再进入下一个宏任务
所以微任务优先级通常高于宏任务。最常见的面试题就是判断一段代码的输出顺序,本质就是看:
- 同步代码先执行
- 当前宏任务结束后,微任务全部清空
- 然后再执行下一个宏任务
一句话记忆
同步代码先走,当前轮次的微任务全部清空,最后才轮到下一个宏任务。
常见追问
- 为什么 Promise 比 setTimeout 先执行?
- 浏览器渲染是在微任务前还是后?
- Node.js 事件循环和浏览器事件循环有何差异?
易错点
很多人把"异步"直接等同于"setTimeout"。实际上 Promise 也是异步,但它进入的是微任务队列,不是宏任务队列。
2. Promise 的本质是什么?为什么能解决回调地狱?
面试回答
Promise 本质上是一个表示异步操作最终结果的对象。它把"未来会得到的值"抽象成统一的数据结构,并且把异步流程变成可以链式书写的形式。
Promise 有三个状态:
pending:进行中fulfilled:已成功rejected:已失败
状态一旦从 pending 变为成功或失败,就不可再逆,这叫状态不可逆。
Promise 能缓解回调地狱,主要有三个原因:
-
链式调用
- 以前多层异步要一层层嵌套回调
- Promise 可以
.then().then().catch()平铺下来
-
统一的错误传递
- 回调风格里每层都要手动处理错误
- Promise 链中抛出的错误会一直向后冒泡到最近的
catch
-
更适合组合多个异步任务
Promise.allPromise.racePromise.allSettledPromise.any
例如:
js
requestA()
.then(resA => requestB(resA))
.then(resB => requestC(resB))
.catch(err => handleError(err))
这样比层层嵌套的回调更清晰,也更容易维护。
常见追问
Promise.all和Promise.allSettled的区别?then为什么可以链式调用?- 手写 Promise 时为什么要用队列保存回调?
易错点
Promise 并不是"让异步变同步",它只是让异步代码更容易组织和管理。
3. async/await 和 Promise 是什么关系?
面试回答
async/await 本质上是 Promise 的语法糖 。
async 函数执行后一定返回一个 Promise;await 会等待一个 Promise 完成,然后拿到它的结果。
例如:
js
async function getData() {
const res = await fetch('/api/data');
return res.json();
}
等价思路大致可以理解为:
js
function getData() {
return fetch('/api/data').then(res => res.json());
}
async/await 的优势是:
-
代码更接近同步写法
- 可读性更强
- 更适合复杂业务流程
-
错误处理更自然
- 可以直接用
try...catch
- 可以直接用
-
便于写条件分支和循环
- Promise 链在复杂逻辑里会越来越绕
async/await在控制流上更直观
但是它不是性能优化工具。多个独立异步任务如果写成连续 await,反而会串行执行,导致变慢。
这时应该用:
js
const [a, b] = await Promise.all([taskA(), taskB()]);
常见追问
await后面如果不是 Promise 会怎样?- 为什么说
async函数一定返回 Promise? - 如何把串行 await 改成并行?
易错点
很多人一上来就把多个 await 串起来,这在互不依赖的请求场景里是低效写法。
4. 什么是闭包?闭包有什么实际作用和风险?
面试回答
闭包指的是:函数可以访问并记住其词法作用域中的变量,即使该函数在作用域外执行。
经典例子:
js
function createCounter() {
let count = 0;
return function () {
count++;
return count;
};
}
const counter = createCounter();
counter(); // 1
counter(); // 2
这里内部函数引用了外部函数的 count,外部函数执行结束后,这个变量没有被销毁,因为还被内部函数引用着,这就是闭包。
实际作用
- 数据私有化
- 可以把变量封装起来,外部不能直接修改
- 函数工厂
- 根据不同参数生成不同功能函数
- 缓存
- 记住计算结果,避免重复计算
- 框架底层
- React Hooks、函数柯里化、模块封装等都大量使用闭包思想
风险
闭包本身不是坏事,但如果引用了大量不再需要的对象,又长期不释放,就可能造成内存无法及时回收 。
比如:
- 定时器里引用大对象
- 事件监听函数里持有 DOM 或大数组
- 某些缓存没有淘汰机制
常见追问
- 闭包为什么不会被垃圾回收?
- 闭包一定会导致内存泄漏吗?
- React Hooks 和闭包有什么关系?
易错点
闭包不等于内存泄漏。闭包是机制,泄漏是误用。
5. this 的绑定规则有哪些?
面试回答
this 的指向不是在函数定义时决定的,而是在函数调用时决定的。常见规则有四种:
1)默认绑定
独立函数调用,非严格模式下指向全局对象,严格模式下是 undefined。
js
function fn() {
console.log(this);
}
fn();
2)隐式绑定
作为对象的方法调用,this 指向调用它的对象。
js
const obj = {
name: 'A',
say() {
console.log(this.name);
}
};
obj.say(); // A
3)显式绑定
通过 call、apply、bind 指定 this。
js
function say() {
console.log(this.name);
}
say.call({ name: 'B' });
4)new 绑定
用 new 调用构造函数时,this 指向新创建的实例对象。
js
function Person(name) {
this.name = name;
}
const p = new Person('Tom');
特殊点:箭头函数
箭头函数没有自己的 this,它会继承外层作用域的 this。
所以箭头函数适合拿来避免普通函数里 this 丢失的问题。
常见追问
call、apply、bind区别?- 箭头函数为什么不能当构造函数?
- 事件回调里
this指向谁?
易错点
不要死记"this 指向函数本身"或者"this 永远指向调用者",这两种说法都不完整。
6. 深拷贝和浅拷贝有什么区别?如何实现深拷贝?
面试回答
浅拷贝只复制第一层属性,如果属性值还是引用类型,那么新旧对象仍然共享内部引用。
深拷贝会递归复制所有层级,得到一个完全独立的新对象。
浅拷贝例子
js
const a = { info: { age: 18 } };
const b = { ...a };
b.info.age = 20;
console.log(a.info.age); // 20
常见深拷贝方案
1)JSON.parse(JSON.stringify(obj))
优点:简单
缺点:
- 会丢失
undefined - 会丢失
Symbol - 会丢失函数
Date会变字符串Map/Set会丢失- 循环引用会报错
2)structuredClone
现代浏览器和新环境支持更好,能处理更多内置类型,且支持循环引用,实际开发更推荐。
3)手写递归深拷贝
适合面试展示基本功,要注意:
- 区分数组和对象
- 处理
null - 处理循环引用
- 处理
Date、RegExp、Map、Set
面试建议回答
在业务里优先考虑:
- 数据是否真的需要深拷贝
- 能不能通过不可变更新、结构共享解决
- 需要时优先用成熟能力而不是自己造轮子
常见追问
- 为什么 JSON 方案不可靠?
- 如何处理循环引用?
structuredClone和 lodash 的cloneDeep如何选?
7. 什么是防抖和节流?分别适合什么场景?
面试回答
它们都是为了控制高频触发事件,核心区别在于"执行时机"。
防抖(debounce)
事件触发后,不立即执行,等停止触发一段时间后再执行。
如果这段时间内又触发了,就重新计时。
适合场景:
- 搜索框输入联想
- 窗口 resize 后重新布局
- 表单输入校验
核心目标:
只关心"最后一次"。
节流(throttle)
规定一个时间间隔,在这个间隔内无论触发多少次,只执行一次。
适合场景:
- 页面滚动监听
- 鼠标移动
- 拖拽
- 高频上报
核心目标:
把执行频率降下来,稳定输出。
一句话区分
- 防抖:等你停下来我再执行
- 节流:你一直触发也没关系,但我按固定频率执行
常见追问
- 如何实现立即执行版防抖?
- 节流如何在最后一次也执行?
- React/Vue 中如何正确清理防抖节流?
二、浏览器与网络高频题
8. 从输入 URL 到页面渲染完成,中间发生了什么?
面试回答
这是一个典型综合题,建议按阶段回答:
1)URL 解析
浏览器先解析输入内容,判断是 URL 还是搜索关键字。
2)缓存检查
浏览器会先看:
- 是否命中强缓存
- 是否需要协商缓存
如果缓存可用,就可能不用真正发请求。
3)DNS 解析
把域名解析成 IP 地址。
4)建立连接
- HTTP:TCP 三次握手
- HTTPS:TCP + TLS 握手,协商加密参数和证书校验
5)发送 HTTP 请求
浏览器发出请求头、请求体等。
6)服务器处理并返回响应
响应包括:
- 状态码
- 响应头
- 响应体
7)浏览器解析页面
如果是 HTML:
- 解析 HTML,构建 DOM
- 解析 CSS,构建 CSSOM
- 合并生成 Render Tree
- Layout(回流/布局)
- Paint(重绘)
- Compositing(合成)
8)遇到资源继续加载
HTML 解析过程中可能继续加载:
- CSS
- JS
- 图片
- 字体
- 异步接口数据
9)JS 执行影响页面
JavaScript 可能修改 DOM、样式、数据,触发再次渲染。
10)页面可交互
关键资源完成后,页面逐渐达到可交互状态。
面试答题技巧
这个题不要只背"DNS/TCP/HTTP/渲染"四个名词,重点是把它们串成一个完整流程。
9. 强缓存和协商缓存分别是什么?
面试回答
HTTP 缓存的目标是减少重复请求、降低延迟、减轻服务器压力。
强缓存
浏览器直接使用本地缓存,不发请求到服务器。
常见响应头:
Cache-Control: max-age=3600Expires
只要缓存没过期,就直接用缓存。
协商缓存
本地有缓存,但浏览器会发请求问服务器"我这个缓存还能不能继续用?"
常见字段:
ETag/If-None-MatchLast-Modified/If-Modified-Since
如果资源没变,服务器返回 304 Not Modified,浏览器继续使用本地缓存。
区别总结
- 强缓存:连请求都不发
- 协商缓存:会发请求,但可能不传资源内容
实战建议
静态资源常用:
- 文件名加 hash
- 配合强缓存长期缓存
动态 HTML 一般缓存更谨慎
常见追问
Cache-Control和Expires谁优先?ETag和Last-Modified有什么区别?- 为什么打包文件要带 hash?
10. HTTP/1.1、HTTP/2、HTTP/3 有什么区别?
面试回答
这道题建议从"性能瓶颈是如何一步步被解决的"去讲。
HTTP/1.1
特点:
- 支持长连接
- 支持管线化(但实际使用有限)
- 一个 TCP 连接里请求仍容易队头阻塞
- 浏览器通常通过开多个连接缓解问题
HTTP/2
主要改进:
- 二进制分帧
- 多路复用
- 一个连接里并发多个请求
- 头部压缩
- 服务器推送(实际使用有限)
它明显改善了 HTTP/1.1 的并发效率问题。
HTTP/3
基于 QUIC,而 QUIC 基于 UDP。
主要优势:
- 更快的连接建立
- 更好地处理丢包和弱网
- 减少 TCP 层队头阻塞带来的影响
- 移动网络切换场景更友好
面试总结版
- HTTP/1.1:文本协议,连接效率一般
- HTTP/2:多路复用、头部压缩,显著提升并发能力
- HTTP/3:基于 QUIC,弱网和连接迁移体验更好
常见追问
- HTTP/2 已经多路复用了,为什么还需要 HTTP/3?
- TCP 队头阻塞和 HTTP 队头阻塞是什么关系?
11. HTTPS 比 HTTP 安全在哪里?
面试回答
HTTPS = HTTP + TLS/SSL。
它主要解决三个问题:
-
加密
- 数据传输过程中不容易被窃听
-
完整性
- 数据不容易被篡改
-
身份认证
- 通过证书机制确认你访问的是正确服务器
握手简化理解
- 客户端发起连接
- 服务器返回证书和公钥相关信息
- 客户端验证证书是否合法
- 双方协商出会话密钥
- 后续数据用对称加密传输
为什么既有非对称加密又有对称加密?
- 非对称加密安全,但慢
- 对称加密快,适合大量数据传输
所以一般用非对称加密来协商密钥,再用对称加密传输数据。
常见追问
- 为什么 HTTPS 还是可能被中间人攻击?
- 证书链是什么?
- TLS 握手为什么会影响首包时间?
12. 什么是跨域?常见解决方案有哪些?
面试回答
跨域本质上是浏览器的同源策略限制 。
协议、域名、端口三者只要有一个不同,就算不同源。
例如:
https://a.com和https://b.com跨域https://a.com和http://a.com跨域https://a.com:3000和https://a.com:8080跨域
常见解决方案
1)CORS
最正规、最常用。
后端通过响应头声明允许哪些源访问,例如:
Access-Control-Allow-OriginAccess-Control-Allow-MethodsAccess-Control-Allow-Headers
2)反向代理
开发环境常见:
- Vite proxy
- Webpack devServer proxy
- Nginx 代理
本质是让前端请求同源服务器,再由服务器转发。
3)JSONP
只支持 GET,现在很少用了,面试里知道原理即可。
4)postMessage
适用于不同窗口、iframe 之间通信。
面试提醒
跨域是浏览器限制,不是服务器限制。
服务端之间互相请求通常不受浏览器同源策略影响。
常见追问
- 什么是预检请求(OPTIONS)?
- 为什么有些请求会触发预检,有些不会?
- Cookie 跨域传输要注意什么?
三、Vue3 / React 高频题
13. Vue3 为什么用 Proxy 替代 Object.defineProperty?
面试回答
Vue2 使用 Object.defineProperty 劫持对象属性,Vue3 则用 Proxy 代理整个对象。
Vue3 这样做主要是为了解决 Vue2 响应式的一些天然缺陷。
Vue2 的痛点
- 无法直接监听对象新增/删除属性
- 数组某些操作需要特殊处理
- 需要递归遍历对象,初始化成本较高
Proxy 的优势
- 代理整个对象
- 不用一开始就把所有属性都递归劫持
- 可以监听新增、删除属性
- 可以原生拦截更多操作
getsetdeletePropertyhasownKeys
- 更适合复杂数据结构
MapSet- 嵌套对象
但要说明
Proxy 不是"绝对更快"的万能答案。它更大的优势在于能力更完整、设计更现代、便于维护框架底层。
常见追问
- Vue3 依赖收集是在哪一步完成的?
ref和reactive的区别?- 为什么
reactive不能直接代理基本类型?
14. ref 和 reactive 有什么区别?
面试回答
它们都是 Vue3 响应式 API,但适用对象不同。
reactive
用于代理对象类型:
- Object
- Array
- Map
- Set
js
const state = reactive({ count: 0 });
state.count++;
ref
通常用于包装基本类型,当然也能包装对象。
js
const count = ref(0);
count.value++;
区别总结
ref访问值要用.valuereactive更适合对象整体状态ref更适合单值、可解构、组合式封装- 模板里会自动解包,所以模板中经常不用写
.value
使用建议
- 单个数字、字符串、布尔值:优先
ref - 一个表单对象、页面状态对象:优先
reactive
常见追问
- 为什么 setup 解构 reactive 后会失去响应式?
toRefs是干什么的?ref包对象和reactive有什么取舍?
15. React Hooks 为什么不能放在条件语句里?
面试回答
因为 React Hooks 的底层依赖调用顺序稳定 。
React 在函数组件渲染时,会按顺序把每个 Hook 挂到内部链表或对应位置上。它不是靠变量名识别,而是靠"第几个 Hook"。
如果你把 Hook 写在条件里:
js
if (flag) {
useEffect(() => {}, []);
}
那么第一次渲染和第二次渲染的 Hook 顺序可能不同,React 就无法正确把状态和对应 Hook 对上,结果会错乱。
正确写法
把 Hook 始终写在顶层,再把条件放进 Hook 内部:
js
useEffect(() => {
if (flag) {
// do something
}
}, [flag]);
本质
Hooks 规则不是语法限制,而是为了保证 React 在多次渲染之间,能够稳定找到同一个 Hook 的状态。
常见追问
useState为什么调用后状态能记住?- Hooks 和闭包有什么关系?
- 为什么自定义 Hook 也必须遵守同样规则?
16. useEffect 和 useLayoutEffect 有什么区别?
面试回答
两者都会在组件渲染后执行副作用,但执行时机不同。
useEffect
通常在浏览器完成绘制后异步执行。
适合:
- 请求数据
- 订阅事件
- 打日志
- 非阻塞副作用
useLayoutEffect
会在 DOM 更新后、浏览器绘制前同步执行。
适合:
- 读取布局信息
- 同步修改 DOM,避免闪烁
举例
如果你要测量元素尺寸并立刻修正位置,useLayoutEffect 更合适;
如果只是发请求、绑定事件,用 useEffect 就够了。
风险
useLayoutEffect 会阻塞浏览器绘制,用多了会影响性能。
常见追问
- 为什么某些 UI 闪动问题要用
useLayoutEffect? - 服务端渲染环境下它有什么注意点?
17. key 在 diff 算法里有什么作用?为什么不能乱用 index?
面试回答
key 的作用是帮助框架在新旧节点比较时,识别哪个节点是同一个元素,从而尽量复用 DOM,减少不必要的删除和重建。
为什么需要 key
列表更新时,如果没有稳定 key,框架只能按位置猜。
当插入、删除、排序发生时,可能导致:
- 原本可复用的节点没复用
- 组件状态错位
- 输入框内容错乱
- 渲染性能变差
为什么不建议用 index
当列表是静态的、不增删排序时,用 index 问题不大;
但一旦列表顺序会变化,index 就不稳定了。
例如:
js
items.map((item, index) => <Row key={index} />)
如果头部插入一项,后面所有 index 都变了,React/Vue 可能会把旧节点错误复用到新位置。
最佳实践
优先使用业务上真正唯一且稳定的 id 作为 key。
常见追问
- key 改了为什么组件会重新挂载?
- 为什么有时故意改 key 来强制重置组件状态?
四、工程化高频题
18. Vite 和 Webpack 的核心区别是什么?
面试回答
Webpack 和 Vite 都是前端构建工具,但思路不同。
Webpack
Webpack 的核心是打包一切资源,构建依赖图 。
开发环境下也会先做较完整的打包流程,所以大型项目启动和热更新可能偏慢。
Vite
Vite 利用现代浏览器原生支持 ES Module 的能力:
- 开发时按需加载模块
- 不必一开始打完整包
- 启动很快
- 热更新更轻量
生产环境下,Vite 通常仍会借助 Rollup 做正式构建优化。
通俗理解
- Webpack:先把仓库都整理打包好再给你用
- Vite:开发时谁用谁加载,生产时再统一打包优化
选择建议
- 新项目一般更偏向 Vite
- 老项目、复杂历史包袱项目可能还在 Webpack 体系里
常见追问
- Vite 为什么冷启动快?
- HMR 为什么更快?
- Vite 插件生态和 Rollup 有什么关系?
19. Tree Shaking 是什么?为什么有时不生效?
面试回答
Tree Shaking 指的是:在打包时移除没有被使用到的代码 。
它常依赖 ES Module 的静态结构,因为 ESM 的导入导出关系在编译阶段就可以分析。
为什么 ESM 更适合 Tree Shaking
因为:
import/export是静态的- 依赖关系可提前分析
- 哪些导出没被使用更容易判断
不生效的常见原因
- 使用了 CommonJS
- 模块有副作用
- 打包配置不正确
- 引入方式不够精细
- 第三方库本身构建质量一般
面试可补充
项目里除了 Tree Shaking,还会配合:
- 代码分割
- 懒加载
- CDN
- gzip/brotli
- 图片优化
常见追问
- 什么是副作用(side effects)?
- 为什么
import 'xxx.css'不能被轻易删掉?
20. Babel 的编译流程是怎样的?
面试回答
Babel 的核心流程可以概括为三步:
-
Parse(解析)
- 把源代码解析成 AST(抽象语法树)
-
Transform(转换)
- 对 AST 做遍历和修改
- 插件就是在这一层工作
-
Generate(生成)
- 把转换后的 AST 再生成新的代码
举例
比如把箭头函数:
js
const add = (a, b) => a + b;
转换成 ES5 普通函数,本质上就是 AST 转换。
Babel 的作用
- 语法降级兼容旧环境
- 支持 JSX、TypeScript 等语法转换
- 配合插件做代码增强
常见追问
- Babel 和 TypeScript 编译器的区别?
- Babel 能做类型检查吗?
- 插件和 preset 有什么关系?
五、性能优化高频题
21. 首屏加载慢,通常从哪些方面优化?
面试回答
首屏优化要分层次回答,不能只说"压缩资源"。
1)资源体积优化
- 代码分包
- 懒加载
- Tree Shaking
- 压缩 JS/CSS
- 图片压缩、WebP/AVIF
- 删除无用依赖
2)请求链路优化
- CDN
- HTTP 缓存
- 减少重定向
- 减少 DNS 查询
- 使用 HTTP/2 或 HTTP/3
- 接口合并
3)渲染路径优化
- 关键 CSS 优先
- 减少阻塞渲染的脚本
- 合理使用
defer/async - SSR / SSG 提前输出 HTML
- 骨架屏提升感知速度
4)运行时优化
- 降低首屏执行 JS 量
- 避免主线程长任务
- 延后非关键逻辑
- 分片计算、Web Worker
面试建议
最好给出你自己的实战案例,例如:
- 包体从 3MB 降到 900KB
- 首屏时间从 4.5s 降到 2.1s
- 通过路由级拆包和图片懒加载完成优化
常见追问
- 白屏时间和首屏时间有什么区别?
- CSR、SSR、SSG 怎么选?
22. 什么是虚拟列表?适合解决什么问题?
面试回答
虚拟列表用于解决大数据量列表渲染性能问题 。
核心思想是:
页面里只渲染"可视区域附近的少量 DOM",而不是把几千条、几万条数据一次性全部渲染出来。
为什么有效
浏览器渲染大量 DOM 成本很高,会影响:
- 首次渲染
- 滚动流畅度
- 内存占用
实现思路
- 根据容器高度和单项高度,算出可视区可显示多少项
- 根据滚动位置,算出当前应渲染的起止索引
- 只渲染这一小段数据
- 用一个占位容器撑出完整滚动高度
- 内部列表通过
transform偏移到正确位置
适用场景
- 聊天记录
- 日志列表
- 大表格
- 商品长列表
常见追问
- 不定高列表怎么做?
- 虚拟列表为什么不适合数据量很小的场景?
- 虚拟列表和分页有何区别?
23. 前端性能指标 LCP、FCP、CLS 分别是什么?
面试回答
这是面试里越来越常见的 Web 性能指标题。
FCP(First Contentful Paint)
首次内容绘制时间。
表示页面第一次把文本、图片、SVG、canvas 等内容绘制出来的时间。
LCP(Largest Contentful Paint)
最大内容绘制时间。
通常反映用户看到主内容的速度,是非常关键的首屏体验指标。
CLS(Cumulative Layout Shift)
累计布局偏移。
衡量页面元素是否"乱跳"。比如图片没预留尺寸、广告插入导致页面抖动,CLS 就会变差。
如何优化
- FCP/LCP
- 优化首屏资源大小
- 提前加载关键资源
- 减少阻塞脚本
- 服务端渲染
- 图片优化
- CLS
- 为图片和广告预留尺寸
- 避免动态插入内容挤压已有布局
- 使用稳定布局策略
常见追问
- 这些指标如何监控?
- Lighthouse 和真实用户监控有什么区别?
六、前端安全高频题
24. 什么是 XSS?如何防御?
面试回答
XSS(Cross-Site Scripting)指攻击者把恶意脚本注入页面,并在其他用户浏览器中执行。
常见类型
- 存储型 XSS
- 恶意脚本被保存到数据库,别人访问时触发
- 反射型 XSS
- 恶意脚本来自 URL 参数,服务器原样返回
- DOM 型 XSS
- 前端脚本不安全地操作 DOM 导致执行恶意代码
防御手段
- 对用户输入做转义/过滤
- 避免使用危险 API
- 如直接拼接
innerHTML
- 如直接拼接
- 使用 CSP(内容安全策略)
- 富文本场景使用白名单过滤
- 后端也要参与校验,不能只靠前端
常见追问
- Vue/React 为什么能降低部分 XSS 风险?
v-html/dangerouslySetInnerHTML为什么危险?
25. 什么是 CSRF?如何防御?
面试回答
CSRF(Cross-Site Request Forgery)是指攻击者诱导用户在已登录目标网站的情况下,偷偷向目标网站发起非本人意愿的请求。
比如用户登录了银行网站,同时又访问了攻击网站,攻击网站可能诱导浏览器带着银行 Cookie 发请求。
防御手段
- CSRF Token
- 服务端下发随机 token,请求时一起提交并校验
- SameSite Cookie
- 限制跨站请求携带 Cookie
- 验证 Referer / Origin
- 关键操作二次确认
- 短信、验证码、密码确认
易混点
- XSS 是"执行恶意脚本"
- CSRF 是"冒充用户发请求"
七、AI 前端面试题(2025--2026 明显升温)
26. 现在前端面试会问 AI 相关内容吗?
面试回答
会,而且越来越常见,但通常不是考你训练模型,而是考你如何把 AI 能力接入前端产品。
常见考法
-
AI 聊天产品怎么做
- 对话 UI
- 历史消息
- 流式输出
- 打字机效果
- 错误重试
-
流式响应怎么接
- SSE
- fetch stream
- WebSocket
-
Prompt 和上下文管理
- system prompt
- 多轮会话
- token 截断策略
-
RAG 基本概念
- embedding
- 检索
- 拼接上下文
你可以这样回答趋势
对通用前端岗位,AI 题目不一定每轮都问;
但中高级岗位、平台型岗位、效率工具、企业应用、内容产品、数据平台等方向,被问到 AI 相关工程问题的概率明显更高。
面试建议
你不用把自己包装成算法工程师,但至少要能讲清:
- 怎么做一个 AI 聊天页面
- 怎么接流式响应
- 如何处理 markdown、代码块、复制、重试、停止生成
- 如何控制上下文长度和历史消息
27. 如何实现一个 AI 聊天应用?
面试回答
可以从前端、服务端、模型接入三个层面讲。
前端层
- 聊天列表
- 输入框
- 停止生成
- 重新生成
- markdown 渲染
- 代码块高亮
- 打字机效果
- 历史会话管理
服务端层
不建议前端直接暴露模型密钥,通常由服务端代理:
- 接收前端消息
- 拼接上下文
- 调用模型接口
- 把流式结果转发给前端
模型交互层
需要考虑:
- 模型选择
- token 限制
- 系统提示词
- 错误重试
- 超时控制
- 审计与安全
关键难点
- 流式输出
- 让用户更快看到回复
- 上下文管理
- 不能无限带历史消息
- 消息状态管理
- 正在生成、已完成、失败、重试中
- 异常处理
- 网络中断、模型报错、限流
面试加分点
如果你能讲到:
- 消息去重
- 多轮上下文裁剪
- 代码块渲染
- AbortController 停止请求
- 乐观更新
那就已经比很多候选人强很多了。
28. 什么是流式响应?前端为什么要做流式渲染?
面试回答
流式响应就是服务端不是等整个结果都生成完再一次性返回,而是边生成边把内容一段段传给前端。
好处
- 更快的感知速度
- 用户先看到一部分内容,而不是一直转圈
- 更符合聊天产品体验
- 便于做停止生成、增量渲染
前端怎么做
常见方案:
- SSE
fetch+ReadableStream- WebSocket
前端拿到每一段内容后,持续拼接到当前回答中,并触发视图更新。
关键实现点
- 正确处理 chunk 边界
- 控制滚动到底部
- 支持停止生成
- 断流时要有失败兜底
- 渲染 markdown 时避免频繁全量重算
常见追问
- SSE 和 WebSocket 怎么选?
- 为什么很多 AI 聊天产品喜欢流式响应?
29. 什么是 RAG?前端需要懂到什么程度?
面试回答
RAG 是 Retrieval-Augmented Generation,中文一般叫"检索增强生成"。
它的核心思路是:
- 用户提问
- 系统先去知识库里检索相关内容
- 把检索结果作为上下文拼给模型
- 模型基于这些资料生成回答
为什么需要 RAG
因为大模型本身不是你的私有知识库,它可能:
- 不知道企业内部数据
- 知识过时
- 容易胡编
RAG 可以让回答更贴近你自己的文档和业务数据。
前端面试里需要懂到什么程度
你不一定要会搭建向量库,但至少要知道:
- 检索结果不是模型自己"记住"的,而是先查再答
- embedding 是把文本变成向量,便于相似度检索
- 前端通常负责:
- 查询入口
- 检索结果展示
- 引用来源展示
- 生成状态展示
常见追问
- RAG 和微调有什么区别?
- 为什么有了 RAG 还是会幻觉?
八、面试收尾建议
30. 面试回答时怎样更像高级工程师?
建议回答方式
每道题尽量按这个顺序讲:
- 定义是什么
- 为什么出现
- 核心原理
- 实际应用场景
- 优缺点 / 边界
- 项目里怎么落地
示例
不要只说:
虚拟列表就是只渲染可视区域。
更好的说法是:
虚拟列表是为了解决大数据量 DOM 渲染导致的首屏慢、滚动卡、内存高等问题。它通过维护可视区域对应的数据窗口,只渲染当前需要展示的部分节点,同时用占位容器保持滚动高度,从而显著降低 DOM 数量和渲染压力。
九、建议你重点反复练习的题
- 事件循环
- Promise / async await
- 闭包 / this
- URL 到页面渲染
- 缓存 / 跨域 / HTTPS
- Vue3 响应式
- React Hooks / useEffect
- Vite vs Webpack
- 首屏优化 / 虚拟列表 / 性能指标
- XSS / CSRF
- AI 聊天应用 / 流式响应 / RAG
十、最后提醒
这份文档的正确用法不是死记硬背,而是:
- 先把答案读懂
- 再用自己的话讲出来
- 最后结合你的项目经历补上"我实际怎么做过"
只要你能把"原理 + 业务场景 + 工程落地"连起来,面试表现会明显提升。