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

温馨提示:市面上的面经鱼龙混杂,甄别真伪、把握时效,是我们对抗内卷最有效的武器。
面经原文内容
📍面试公司:腾讯WXG(微信事业群)
🕐面试时间:近期
💻面试岗位:暑期前端一面
❓面试问题:
- 自我介绍
- 算法题:最长递增子序列,对比版本号
- 实习项目中遇到的难点是什么?如何解决的?
- 提到了用AI迭代改代码?具体怎么做的?怎么检查AI写的代码的?(问了好些记不得了)
- 批量请求与缓存策略怎么实现的?
- 提到了SessionStorage,sessionstorage和localstorage的区别?
- 这些缓存可以无限存吗(应该是想让我说indexDB)
- 项目拷打,暗黑亮色模式主题切换怎么实现的?
- 项目里有登录功能吗?怎么做的?
- 提到了cookie,cookie有哪些属性?
- SameSite是什么用的?JS可以获取cookie吗?有效期如果后端想让他无效怎么实现?
- 组件库项目有什么比较复杂的组件,怎么实现的?
- 只用过Vue框架是吧,别的有了解吗(没有)
- Vue2和Vue3的数据双向绑定区别?
- 现在还在实习吗?要实习到多久?
来源:牛客网 RedCrazy
💡 木木有话说(刷前先看)
我感觉五一回来后,基本上都是暑期实习多一些,难度适中,不是很难啊。有需要的同学可以继续关注。
📝 腾讯WXG暑期前端一面·深度解析
🎯 面试整体画像
| 维度 | 特征 |
|---|---|
| 面试风格 | 算法+项目+八股均衡型 + 实战追问型 |
| 难度评级 | ⭐⭐⭐(三星,算法+项目深度较关键) |
| 考察重心 | 动态规划算法、项目难点、缓存策略、登录鉴权、Vue响应式 |
| 特殊之处 | 围绕AI迭代代码、批量请求缓存等实战细节追问 |
🔍 逐题深度解析
二、算法题
最长递增子序列(LIS)
题目:给定一个整数数组,找出其中最长的严格递增子序列的长度。
解法:动态规划 + 贪心+二分(最优解O(n log n))
javascript
function lengthOfLIS(nums) {
const tails = [] // tails[i]表示长度为i+1的递增子序列的最小尾数
for (const num of nums) {
// 二分查找第一个大于等于num的位置
let left = 0, right = tails.length
while (left < right) {
const mid = Math.floor((left + right) / 2)
if (tails[mid] < num) {
left = mid + 1
} else {
right = mid
}
}
tails[left] = num
}
return tails.length
}
时间复杂度 :O(n log n)
空间复杂度:O(n)
对比版本号
题目:比较两个版本号的大小(如"1.2.3"和"1.2.4")
javascript
function compareVersion(version1, version2) {
const v1 = version1.split('.')
const v2 = version2.split('.')
const maxLen = Math.max(v1.length, v2.length)
for (let i = 0; i < maxLen; i++) {
const num1 = i < v1.length ? parseInt(v1[i]) : 0
const num2 = i < v2.length ? parseInt(v2[i]) : 0
if (num1 !== num2) {
return num1 > num2 ? 1 : -1
}
}
return 0
}
四、用AI迭代改代码:具体做法与代码检查
回答思路:面试官追问"具体怎么做的"和"怎么检查AI写的代码",说明想听实际操作细节,而非空泛概念。
具体做法:
- 需求拆解:将复杂需求拆分成小任务,逐个让AI完成
- 上下文注入 :在Cursor/Copilot中,通过注释或
@workspace让AI理解项目结构 - 迭代生成:先生成骨架代码,再逐步完善细节和边界条件
- 规范约束 :通过
.cursorrules或AGENTS.md文件,约束AI遵循项目代码风格
代码检查方法:
- 肉眼Review:重点关注边界条件、空值处理、类型安全
- 单元测试:让AI同时生成单元测试,验证正确性
- 静态分析:运行ESLint、TypeScript检查
- 对比验证:将AI生成的代码与手写实现做性能对比
- 安全扫描:检查是否有XSS漏洞、硬编码密钥等
markdown
<!-- .cursorrules 示例 -->
## 代码规范
- 使用TypeScript,禁止使用any
- 函数必须有明确的参数类型和返回类型
- 异步操作使用async/await,避免.then链式调用
- 每个组件必须有Props接口定义
五、批量请求与缓存策略
回答思路 :核心是请求去重 + 缓存复用。
javascript
class RequestCache {
constructor() {
this.cache = new Map()
this.pending = new Map() // 正在请求中的Promise
}
async fetch(url, options = {}) {
const cacheKey = `${url}_${JSON.stringify(options)}`
// 命中缓存
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey)
}
// 请求去重:相同请求只发一次
if (this.pending.has(cacheKey)) {
return this.pending.get(cacheKey)
}
const promise = fetch(url, options)
.then(res => res.json())
.then(data => {
this.cache.set(cacheKey, data)
this.pending.delete(cacheKey)
// 设置过期时间(如5分钟)
setTimeout(() => this.cache.delete(cacheKey), 5 * 60 * 1000)
return data
})
this.pending.set(cacheKey, promise)
return promise
}
}
批量请求 :使用Promise.all或Promise.allSettled并发请求。
六、sessionStorage和localStorage的区别
| 维度 | sessionStorage | localStorage |
|---|---|---|
| 生命周期 | 标签页关闭即清除 | 永久存储(需手动清除) |
| 作用域 | 同源+同标签页 | 同源 |
| 容量 | 5-10MB | 5-10MB |
七、缓存可以无限存吗
答案 :不可以。localStorage和sessionStorage都有5-10MB上限。超出上限会抛出QuotaExceededError。
面试官提示:想引导你说IndexedDB。
IndexedDB特点:
- 容量大(通常>250MB,用户授权后可更大)
- 异步API,不阻塞主线程
- 支持索引、事务、游标
javascript
// IndexedDB存储大数据的示例
const request = indexedDB.open('MyDB', 1)
request.onsuccess = (event) => {
const db = event.target.result
const transaction = db.transaction(['store'], 'readwrite')
const store = transaction.objectStore('store')
store.put({ id: 1, largeData: bigData })
}
八、暗黑亮色模式主题切换实现
方案1:CSS变量(推荐)
css
:root {
--bg-color: #ffffff;
--text-color: #333333;
}
.dark {
--bg-color: #1a1a1a;
--text-color: #e0e0e0;
}
body {
background: var(--bg-color);
color: var(--text-color);
}
方案2:切换class
javascript
function toggleTheme() {
document.documentElement.classList.toggle('dark')
localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light')
}
方案3:prefers-color-scheme(跟随系统)
css
@media (prefers-color-scheme: dark) {
:root { --bg-color: #1a1a1a; }
}
九、登录功能实现
回答思路:参考之前面经的JWT双token方案。
流程:
- 用户提交账号密码
- 后端验证,返回access_token(短期)和refresh_token(长期)
- 前端存储token(通常access_token在内存,refresh_token在httpOnly cookie)
- 请求拦截器携带
Authorization: Bearer <access_token> - token过期时,用refresh_token刷新,重试原请求
十、cookie属性
回答思路:列举常用属性。
| 属性 | 作用 |
|---|---|
name=value |
键值对 |
Domain |
允许访问cookie的域名 |
Path |
允许访问cookie的路径 |
Expires / Max-Age |
过期时间 |
Secure |
仅HTTPS传输 |
HttpOnly |
禁止JS访问(防XSS) |
SameSite |
防CSRF,取值:Strict/Lax/None |
十一、SameSite的作用、JS能否获取cookie、后端如何让cookie失效
SameSite:控制跨站请求是否携带cookie,用于防御CSRF攻击。
| 取值 | 说明 |
|---|---|
Strict |
完全禁止跨站请求携带cookie |
Lax |
允许部分安全的跨站请求(如链接跳转) |
None |
允许所有跨站请求携带(必须同时设置Secure) |
JS能否获取cookie :如果cookie设置了HttpOnly,JS无法通过document.cookie读取;否则可以。
后端让cookie失效:
- 设置过期时间为过去的时间:
Set-Cookie: name=value; Expires=Thu, 01 Jan 1970 00:00:00 GMT - 或设置
Max-Age=0
十二、组件库中比较复杂的组件及实现
回答思路:选择1-2个复杂组件,说明实现难点。
示例:表格组件
- 虚拟滚动:处理大数据量渲染
- 列宽调整:拖拽改变列宽,实时更新布局
- 排序/筛选:多列排序、自定义筛选函数
- 树形表格:递归渲染、展开/折叠、层级缩进
javascript
// 虚拟滚动核心逻辑
const VirtualTable = ({ data, rowHeight, visibleRows }) => {
const [startIndex, setStartIndex] = useState(0)
const endIndex = startIndex + visibleRows
const visibleData = data.slice(startIndex, endIndex)
const paddingTop = startIndex * rowHeight
return (
<div onScroll={(e) => setStartIndex(Math.floor(e.target.scrollTop / rowHeight))}>
<div style={{ paddingTop, height: data.length * rowHeight }}>
{visibleData.map(row => <div style={{ height: rowHeight }}>{row}</div>)}
</div>
</div>
)
}
十四、Vue2和Vue3数据双向绑定区别
| 维度 | Vue2 | Vue3 |
|---|---|---|
| 实现方式 | Object.defineProperty |
Proxy |
| 监听能力 | 仅get/set | 13种操作(deleteProperty、has等) |
| 数组监听 | 需重写数组方法 | 原生支持 |
| 新增属性 | 需Vue.set |
自动响应 |
| 初始化性能 | 递归遍历所有属性 | 懒递归,访问时才代理 |
📚 知识点速查表
| 知识点 | 核心要点 |
|---|---|
| LIS算法 | 动态规划O(n²) / 贪心+二分O(n log n) |
| 版本号对比 | split('.')后逐段比较,补0对齐 |
| AI代码审查 | 边界条件、单元测试、静态分析、安全扫描 |
| 批量请求缓存 | Map缓存 + pending去重 + 定时过期 |
| 存储区别 | sessionStorage(标签页) / localStorage(永久) / IndexedDB(大容量) |
| 暗黑模式 | CSS变量 + class切换 + prefers-color-scheme |
| cookie属性 | HttpOnly/Secure/SameSite/Domain/Path/Max-Age |
| SameSite | Strict/Lax/None,防CSRF |
| 组件库 | 虚拟滚动、列宽调整、树形表格 |
| Vue响应式 | defineProperty vs Proxy |
📌 最后一句:
腾讯WXG这场一面,开场两道算法题(LIS、版本号)是硬通货,筛掉了代码功底不扎实的候选人;能扛住这场面试,说明你不仅有算法思维,更有从项目实践中沉淀出的工程化经验。这正是WXG这类核心部门最看重的素质。