前言
大家好,我是木斯佳。
相信很多人都感受到了,在AI浪潮的席卷之下,前端领域的门槛在变高,纯粹的"增删改查"岗位正在肉眼可见地减少。曾经热闹非凡的面经分享,如今也沉寂了许多。但我们都知道,市场的潮水退去,留下的才是真正在踏实准备、努力沉淀的人。学习的需求,从未消失,只是变得更加务实和深入。
这个专栏的初衷很简单:拒绝过时的、流水线式的PDF引流贴,专注于收集和整理当下最新、最真实的前端面试资料。我会在每一份面经和八股文的基础上,尝试从面试官的角度去拆解问题背后的逻辑,而不仅仅是提供一份静态的背诵答案。无论你是校招还是社招,目标是中大厂还是新兴团队,只要是真实发生、有价值的面试经历,我都会在这个专栏里为你沉淀下来。专栏快速地址

温馨提示:市面上的面经鱼龙混杂,甄别真伪、把握时效,是我们对抗内卷最有效的武器。
面经原文内容
📍面试公司:腾讯音乐
🕐面试时间:2026年5月27日
💻面试岗位:前端一面
📝面试体验:问了很多底层,没有手撕
❓面试问题:
- 自我介绍
- 为什么选择前端这个方向?
- 一个专业的前端的开发需要掌握的技术体系有哪些?
- 你自己觉得哪部分学的最好?
- 说一下对虚拟DOM的理解
- 虚拟DOM存储在哪里?
- 虚拟DOM和真实DOM哪个更高效?原因是什么?
- 真实DOM存储在哪里?
- 浏览器渲染一个页面的流程,简单的说一下
- 项目具体介绍
- 虚拟滚动的原理
- 流式输出底层原理
- 应用场景题:一个多轮对话助手应用,然后假如说聊了一整天,聊的非常多,可能会存在内存泄露问题怎么解决?
- 什么是浏览器的同源限制策略?为什么要有这个限制?
- 跨域问题怎么解决?
- 箭头函数和普通函数有什么区别?
- 在前端存储数据有哪些方式?
- 平常手写代码多还是AI写的多?你是怎么看待AI去写代码这件事情?
- 你认为AI写的好还是你写的好?你用的AI工具是哪些?觉得哪个最好?为什么?
来源:牛客网正在卷的废话选手很能干
💡 木木有话说(刷前先看)
中规中矩的前端面试,基本上所有面试题已经在之前的合集内覆盖了。作为高频考点收录吧。
📝 腾讯音乐前端一面·深度解析
🎯 面试整体画像
| 维度 | 特征 |
|---|---|
| 面试风格 | 底层原理型 + 场景应用型 + 基础全面型 |
| 难度评级 | ⭐⭐⭐(三星,虚拟DOM存储位置、内存泄露场景题有深度) |
| 考察重心 | 虚拟DOM原理、浏览器渲染、虚拟滚动、流式输出、跨域、存储 |
| 特殊之处 | "虚拟DOM存储在哪里""真实DOM存储在哪里"是非常细节的追问 |
🔍 逐题深度解析
五、说一下对虚拟DOM的理解
回答思路:虚拟DOM是用JS对象描述真实DOM树的结构。
核心要点:
- 本质:JS对象,包含tag、props、children等属性
- 作用:通过diff算法找到最小变更,批量更新真实DOM
- 优势:减少直接操作真实DOM的次数,提升性能
- 劣势:初次渲染多一层映射,内存占用
javascript
// 虚拟DOM对象示例
{
type: 'div',
props: { id: 'app', className: 'container' },
children: [
{ type: 'h1', props: {}, children: ['Hello'] }
]
}
六、虚拟DOM存储在哪里
回答思路 :虚拟DOM存储在JS堆内存中。
详细解释:
- 虚拟DOM是JS对象,由JS引擎在堆内存中分配
- 存在于**RAM(内存)**中,而非DOM树所在的渲染引擎内存区域
- 每个组件实例维护自己的虚拟DOM树
- React中,Fiber节点也存储在堆内存中,构成了Fiber树
追问点:虚拟DOM的存储位置是JS堆,真实DOM的存储位置是渲染引擎的C++对象。
七、虚拟DOM和真实DOM哪个更高效
回答思路 :没有绝对的高效,取决于场景。
| 场景 | 虚拟DOM | 真实DOM |
|---|---|---|
| 首次渲染 | 慢(多一层映射) | 快(直接渲染) |
| 少量更新 | 慢(diff开销) | 快 |
| 大量频繁更新 | 快(批量更新) | 慢(频繁重排重绘) |
结论 :虚拟DOM的价值不在于"比真实DOM快",而在于将多次DOM操作合并为一次,在动态UI场景下提升性能。
八、真实DOM存储在哪里
回答思路 :真实DOM存储在浏览器渲染引擎的C++对象中。
详细解释:
- 浏览器由C++编写,DOM节点对应C++对象
- 存储在渲染进程的内存中
- 不同于JS堆,JS操作DOM需要跨语言调用(JS → C++)
九、浏览器渲染页面的流程
回答思路:参考之前面经。
流程:
- 解析HTML → DOM树
- 解析CSS → CSSOM树
- 合成渲染树(Render Tree)
- 布局(Layout/Reflow):计算几何信息
- 分层(Layer):生成图层树
- 绘制(Paint):生成绘制指令
- 分块(Tiling):分成图块
- 光栅化(Rasterize):图块转位图
- 合成(Composite):GPU合成显示
十一、虚拟滚动的原理
回答思路:只渲染可视区域的DOM节点。
核心:
- 计算可视区域能容纳的节点数
- 监听滚动,计算起始索引
- 只渲染
[startIndex, startIndex + visibleCount]的节点 - 用占位(padding或绝对定位)撑高滚动条
javascript
function VirtualList({ items, itemHeight, containerHeight }) {
const [startIndex, setStartIndex] = useState(0)
const visibleCount = Math.ceil(containerHeight / itemHeight)
const handleScroll = (e) => {
const scrollTop = e.target.scrollTop
setStartIndex(Math.floor(scrollTop / itemHeight))
}
const visibleItems = items.slice(startIndex, startIndex + visibleCount)
const paddingTop = startIndex * itemHeight
return (
<div onScroll={handleScroll} style={{ height: containerHeight, overflow: 'auto' }}>
<div style={{ paddingTop, height: items.length * itemHeight }}>
{visibleItems.map(item => <div style={{ height: itemHeight }}>{item}</div>)}
</div>
</div>
)
}
十二、流式输出底层原理
回答思路 :基于HTTP的分块传输 (Chunked Transfer Encoding)或SSE。
底层原理:
- 服务端设置
Transfer-Encoding: chunked,数据分块发送 - 客户端通过
ReadableStream逐块接收 - SSE:服务端设置
Content-Type: text/event-stream,连接保持打开
javascript
// 客户端流式接收
const response = await fetch('/api/stream')
const reader = response.body.getReader()
const decoder = new TextDecoder()
while (true) {
const { done, value } = await reader.read()
if (done) break
const chunk = decoder.decode(value)
console.log('收到:', chunk)
}
十三、多轮对话内存泄露问题及解决
问题分析:长对话中,历史消息不断累积,DOM节点和JS对象越来越多,导致内存占用增长。
解决方案:
| 策略 | 说明 |
|---|---|
| 限制消息数量 | 只保留最近N条消息,超出时移除早期消息 |
| 消息回收 | 移出可视区的DOM节点从DOM树中移除 |
| 上下文压缩 | 将早期消息生成摘要,替代原始消息 |
| 虚拟滚动 | 只渲染可视区域的消息,而不是全部 |
| WeakMap/WeakSet | 使用弱引用存储DOM关联数据,便于垃圾回收 |
javascript
// 限制消息数量
const MAX_MESSAGES = 200
function addMessage(message) {
setMessages(prev => {
const newMessages = [...prev, message]
if (newMessages.length > MAX_MESSAGES) {
return newMessages.slice(-MAX_MESSAGES)
}
return newMessages
})
}
十四、同源限制策略及原因
定义:协议、域名、端口三者相同才为同源。
原因:防止恶意网站通过脚本窃取用户数据(如读取另一个标签页的cookie、localStorage)。
十五、跨域解决方案
| 方案 | 原理 | 适用场景 |
|---|---|---|
| CORS | 服务端设置Access-Control-Allow-Origin |
最常用 |
| JSONP | <script>不受同源限制 |
仅GET |
| 代理 | 同源请求转发到目标API | 开发环境 |
| postMessage | 跨窗口通信 | iframe |
| WebSocket | 不受同源限制 | 实时通信 |
十六、箭头函数和普通函数的区别
| 维度 | 箭头函数 | 普通函数 |
|---|---|---|
this |
静态绑定(定义时继承外层) | 动态绑定(调用时决定) |
arguments |
无 | 有 |
new调用 |
不能 | 可以 |
prototype |
无 | 有 |
十七、前端存储数据的方式
| 方式 | 容量 | 特点 |
|---|---|---|
| localStorage | 5-10MB | 永久,同步 |
| sessionStorage | 5-10MB | 标签页关闭清除 |
| IndexedDB | >250MB | 异步,支持索引 |
| Cookie | 4KB | 自动携带,有过期时间 |
| CacheStorage | 取决于配额 | Service Worker配套 |
十八~十九:AI coding相关
如何看待AI写代码:
- AI是辅助工具,能提高效率,但不能替代思考
- 需要审查AI生成的代码,理解其逻辑
- AI适合写重复性代码、生成测试、调试错误
- 核心架构和关键逻辑仍需人工把控
AI写的好还是你写的好:
- 简单重复性任务:AI写得好(快、少bug)
- 复杂业务逻辑、边界条件处理:人工写得好
- 最佳实践:AI写初稿,人工review优化
📚 知识点速查表
| 知识点 | 核心要点 |
|---|---|
| 虚拟DOM | JS对象描述DOM,存在JS堆内存 |
| 真实DOM | C++对象,存在渲染引擎内存 |
| DOM效率 | 首渲慢,大量更新快(批量合并) |
| 浏览器渲染 | 解析→布局→分层→绘制→光栅化→合成 |
| 虚拟滚动 | 可视区渲染,占位撑高 |
| 流式输出 | 分块传输,ReadableStream读取 |
| 内存泄露 | 限制消息数、虚拟滚动、上下文压缩 |
| 同源策略 | 协议+域名+端口,防XSS/CSRF |
| 跨域 | CORS、JSONP、代理、postMessage |
| 箭头函数 | this静态绑定,不能new,无arguments |
| 前端存储 | localStorage/sessionStorage/IndexedDB/Cookie |
📌 最后一句:
腾讯音乐面试。面试官问到了虚拟DOM存在哪里、真实DOM存在哪里这样非常细节的问题,说明他不满足于"会用",而要考察你是否理解底层机制。多轮对话内存泄露的场景题,则是把底层知识放到真实业务中检验。