面试随记
# AI
“它解决的核心问题,是把我的精力,从重复性和记忆性的工作中解放出来,让我能更专注于创造性和架构性的工作
熟练掌握 Vue3 + TypeScript,具备组件化开发经验,熟悉 Composition API 及常用生态
面试官你好,我是,从事前端开发已经六年了,主要技术栈是 Vue3、TypeScript、UniApp 等
一共任职过两家公司,第一份是毕业到2020年3月,是在郑州从事的外包开发,主要使用uniapp开发app和微信小程序
第二个是在上海,一家自研的流量变现公司,负责前端的所有工作,包括 公司运营的后台管理系统、广告信息流项目以及快应用,微信,支付宝等多个小程序产品
最近也比较关注 AI 与前端结合的应用场景,在项目中也有接入 AI 能力的实践,比如 AI 内容生成和 Prompt 优化等。
希望能加入我们这个新团队,也不断提升自己的技术能力的同时,也能为公司创造实际价值
2
3
4
5
# 一、Vue3 高频八股
# 1️⃣ Vue3 相比 Vue2 的核心升级点是什么?
# ✅ 标准答案:
- 使用 Proxy 替代 Object.defineProperty
- 重写虚拟 DOM(PatchFlag + 静态提升)
- Composition API
- 更好的 Tree Shaking
- Fragment / Teleport / Suspense
- 更好的 TypeScript 支持
# 二、Vue3 性能提升(重点)
# 2️⃣ Vue3 为什么比 Vue2 性能好?
# ✅ 1. 响应式优化(核心)
Vue2 使用:
Object.defineProperty
缺点:
- 不能监听数组索引变化
- 不能监听对象新增属性
- 初始化递归遍历
Vue3 使用:
Proxy
优势:
- 可以监听新增 / 删除属性
- 可以监听数组索引
- 惰性代理(访问时才递归)
- 性能更高
👉 面试加分说法:
Vue3 响应式基于 Proxy + Reflect 实现,采用懒代理机制,避免 Vue2 初始化阶段的深度递归遍历,提高了大型对象的初始化性能。
# ✅ 2. PatchFlag(虚拟DOM优化)
Vue3 在编译阶段会标记动态节点:
<div>{{ msg }}</div>
会被标记为:
PatchFlag.TEXT
更新时:
👉 只更新标记的动态节点 👉 不再进行全量 Diff
Vue2:
- 每次更新都全量对比 VNode
Vue3:
- 只对动态节点做 Diff
性能大幅提升。
# ✅ 3. 静态提升(Static Hoisting)
静态节点只创建一次:
<div>
<p>我是静态</p>
<span>{{ msg }}</span>
</div>
2
3
4
会被提升到 render 外部。
Vue2 每次 render 都重新创建。
Vue3 只创建一次。
# ✅ 4. 事件缓存(Cache Handler)
Vue3 默认缓存事件函数:
Vue2:
<button @click="handleClick">
每次 render 都重新生成函数引用。
Vue3:
会缓存 handler,减少重复创建。
# ✅ 5. Tree Shaking
Vue3 模块化拆分:
import { ref } from 'vue'
只打包用到的 API。
Vue2 是整体打包。
# 三、Vue3 响应式原理
# 3️⃣ Vue3 响应式是怎么实现的?
# 标准回答结构:
- reactive 创建 Proxy
- 依赖收集 track
- 依赖触发 trigger
- effect 副作用函数
核心流程:
effect(() => {
console.log(state.count)
})
2
3
- 读取 count → 触发 track 收集依赖
- 修改 count → 触发 trigger 执行 effect
底层数据结构:
WeakMap → Map → Set
# 四、Composition API 优势
# 4️⃣ 为什么推荐 Composition API?
# 标准答案:
- 逻辑复用更方便
- 避免 mixin 命名冲突
- 更清晰的逻辑分组
- 更好的 TypeScript 支持
- 更适合大型项目
# 五、JS 八股(必须会)
# 5️⃣ 闭包是什么?
函数 + 它能访问的作用域环境。
一般是一个函数返回了一个函数的情形,
- 返回的函数,仍然可以i访问外层函数的局部变量即使外层函数已经执行结束
- 这种访问保持了外层变量的状态,可以实现私有变量或累加器等功能
- 并不是所有返回函数的场景都是闭包,关键是返回的函数引用了外层函数的变量
闭包
常见应用:
- 防抖节流
- 模块封装
- 私有变量
# 6️⃣ 原型链是什么?
对象通过 __proto__ 指向构造函数的 prototype。
查找规则:
对象本身 → prototype → Object.prototype → null
# 7️⃣ Promise 执行机制
- 同步代码先执行
- 微任务(Promise)
- 宏任务(setTimeout)
事件循环顺序:
Promise.all全部成功才成功
Promise.race谁先结束用谁
Promise.any有一个成功就返回
Promise.allSettled全部执行完,不管成功失败
2
3
4
同步 → 微任务 → 宏任务
# 六、性能优化(高频)
# 8️⃣ 前端性能优化手段?
# 资源层面:
- 图片懒加载
- gzip
- CDN
- Tree Shaking
# 代码层面:
- 防抖节流
- 虚拟列表
- keep-alive
- 组件拆分
- 路由懒加载
# Vue 层面:
- v-memo
- v-once
- 合理使用 computed
- 避免深层 watch
# 🎯 最重要:Vue3 性能提升总结模板(必背)
面试回答可直接背:
Vue3 相比 Vue2 性能提升主要体现在三个方面:
第一,响应式系统改为 Proxy,实现惰性代理,解决了 Vue2 无法监听新增属性的问题;
第二,虚拟 DOM 引入 PatchFlag 和静态提升,在编译阶段标记动态节点,更新时只对动态部分进行 Diff;
第三,支持 Tree Shaking,打包体积更小。
整体上 Vue3 在初始化性能、更新性能和包体积方面都有明显提升。
# 一、Vue3 深度题(社招核心)
# 1️⃣ Vue3 响应式原理,和 Vue2 有什么本质区别?
# ✅ 标准结构回答:
Vue3 使用 Proxy + Reflect 实现响应式,相比 Vue2 的 Object.defineProperty 有三个核心提升:
# ① 监听能力增强
Vue2:
- 无法监听新增属性
- 不能监听数组索引
- 需要重写数组方法
Vue3:
- Proxy 可以拦截 get / set / deleteProperty
- 可以监听数组索引变化
- 可以监听属性新增删除
# ② 性能优化(重点说)
Vue2 初始化时会递归遍历对象,深度劫持。
Vue3 是 懒代理机制:
只有在访问对象时才进行递归代理
减少初始化性能消耗。
# ③ 数据结构优化
依赖收集结构:
WeakMap
└─ Map
└─ Set
2
3
- target → key → effect
WeakMap 防止内存泄漏。
# 🎯 面试追问点
- effect 是怎么避免死循环的?
- ref 和 reactive 区别?
- computed 为什么有缓存?
# 2️⃣ Vue3 性能优化点(必背完整版)
你可以这样回答:
Vue3 性能提升主要来自三方面:响应式优化、编译优化、打包优化。
# ① 响应式优化
- Proxy 替代 defineProperty
- 惰性代理
- 更精准的依赖追踪
# ② 编译阶段优化(这是社招重点)
# PatchFlag
Vue3 在编译阶段标记动态节点:
<div>{{msg}}</div>
会被标记为 TEXT 类型。
更新时:
只更新动态节点,不再全量 diff
# 静态提升(Static Hoisting)
静态节点只创建一次。
Vue2 每次 render 都重新创建。
# 事件缓存
Vue3 会缓存事件函数引用,减少 render 过程中函数重新创建。
# ③ Tree Shaking
Vue3 API 按需引入,减少包体积。
# 🎯 加分回答
Vue3 通过“编译时优化”减少运行时计算,这是本质区别。
# 3️⃣ Composition API 为什么更适合大型项目?
社招要回答“痛点”。
# Vue2 痛点:
- 逻辑分散在 data、methods、computed
- mixin 命名冲突
- 逻辑复用困难
# Vue3 优势:
- 按功能组织代码
- 更好的逻辑复用
- 更好 TypeScript 推导
- 更利于拆分业务模块
# 二、真实项目场景题(社招必问)
# 4️⃣ 你做过哪些 Vue 性能优化?
你可以这样答(模板):
在项目中我主要做过以下优化:
- 使用路由懒加载减少首屏加载体积
- 使用 keep-alive 缓存列表页
- 大数据列表使用虚拟滚动
- 避免不必要的深层 watch
- 合理拆分组件,减少重复渲染
- 图片懒加载 + CDN
如果你做过视频项目,可以加:
对大图和视频做了压缩与分片加载优化。
# 三、JS 深度八股(社招必问)
# 5️⃣ 事件循环机制
必须能画流程:
同步任务
↓
微任务(Promise)
↓
宏任务(setTimeout)
2
3
4
5
追问:
- async await 本质?
- nextTick 属于什么?
# 6️⃣ 防抖和节流区别
# 防抖:
触发后延迟执行。事件持续触发时,只在最后一次触发后执行(多用于输入框)
# 节流:
固定时间执行一次。(多用于按钮)
追问:
- 立即执行版本怎么实现?
- Vue 场景怎么用?
GET 是幂等
POST 不是
PUT 是幂等
DELETE 是幂等
2
3
4
# 四、工程化(社招必问)
# 7️⃣ Vite 为什么快?
标准答案:
- 基于 ES Module
- 开发阶段不打包
- 按需加载
- 使用 esbuild 预构建
# 8️⃣ 你如何做打包优化?
- 分包
- 代码分割
- CDN 外链
- gzip
- Tree Shaking
- 图片压缩
# 五、Node 基础(你必须准备)
# 9️⃣ Express 中间件原理?
函数链模型:
(req, res, next)
通过 next 控制流程。
# 🔟 MySQL 索引原理?
- B+ 树
- 主键索引
- 联合索引最左匹配原则
# 六、社招最容易挂的题
# ❓ watch 和 computed 区别?
computed:
- 有缓存
- 基于依赖自动更新
- 适合计算属性
watch:
- 监听变化
- 执行副作用
# ❓ ref 和 reactive 区别?
- ref 用于基本类型
- reactive 用于对象
- ref 本质也是 reactive 包装
| 对比点 | 栈 | 堆 |
|---|---|---|
| 存储内容 | 基本类型 / 引用地址 | 对象 / 数组 |
| 空间大小 | 小 | 大 |
| 分配方式 | 自动分配 | 动态分配 |
| 访问速度 | 快 | 相对慢 |
| 生命周期 | 由函数调用决定 | 由 GC 决定 |
# JS 常见垃圾回收机制
# 1️⃣ 引用计数(早期)
原理:
每个对象有一个引用次数 引用 +1 解除引用 -1 当为 0 时回收
# 2️⃣ 标记清除(现代主流)
现在主流浏览器都用这个。
原理:
- 从根对象(window / global)开始遍历
- 能访问到的标记为“存活”
- 不能访问到的标记为“垃圾”
- 清除未标记对象
优点:
✅ 能解决循环引用问题
# 面试问答
一线城市和二三线城市,通过ip定位获取当前的定位区域,然后配置不同的广告策略
配置的有奖励的三篇30s等,visibilitychange的监听,有的是和app合作,有的是自己页面对接的支付宝提现,
根据第二天广告后台的收益反馈,进行业务调整,
通过deeplink打开第三方app
通过 vite build 后结合 rollup-plugin-visualizer 分析包体积,发现 UI 组件库和图表库占比较大
通过 CDN 外链、按需加载、动态 import 实现代码分割,主包体积从 2.1MB 降到 1.4MB,约下降 30%。
2
3
4
5
6
7
8
9
10
# vue3通信大全(三)—— 全局状态管理库pinia,vuex
https://juejin.cn/post/7397285224379957298?searchId=2026022815382985E6324A99D180ACB9B9
state,
actions,
getters
2
3
4
5
6
# IntersectionObserver
在信息流广告场景中,需要统计广告真实曝光。如果通过 scroll 监听判断元素是否进入视口,会频繁触发计算,性能开销比较大,因此项目中使用了 IntersectionObserver 来实现曝光检测。
具体实现是:当广告组件渲染后,通过 IntersectionObserver 监听广告节点与 viewport 的交叉状态,当元素的 intersectionRatio 超过 50% 时,认为广告进入有效可视区域。为了保证数据准确,我们还增加了曝光停留时间限制,例如停留超过 1 秒才上报曝光埋点。
同时为了避免重复统计,在广告曝光后会取消 observer 监听,并在本地维护曝光缓存,保证同一广告在当前页面只统计一次曝光。点击统计则通过 click 事件进行埋点上报,用于计算广告 CTR 等指标。
在长列表场景下我们还复用了 observer 实例,并在组件销毁时及时取消监听,以避免性能和内存问题
创建 observer
↓
获取需要监听的元素
↓
observer.observe(el)
↓
元素进入视口
↓
触发 callback
↓
根据 dataset 判断执行逻辑
监听完成之后需要取消
observer.unobserve(el)
function observeNewItems() {
const newItems = document.querySelectorAll('.observe-item')
newItems.forEach(el => {
observer.observe(el)
})
}
// 用于保存每个广告的计时器
// key:adId
// value:setTimeout 的 timer
const visibleAds = new Map()
// 创建 IntersectionObserver
const observer = new IntersectionObserver((entries) => {
// entries 是所有状态发生变化的元素
entries.forEach(entry => {
// 当前被监听的 DOM 元素
const el = entry.target
// 从 dataset 中获取广告ID
const adId = el.dataset.adId
// 判断广告是否进入可视区域
// isIntersecting:元素是否进入视口
// intersectionRatio:可见比例
if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
// 广告进入可视区域,开始1秒计时
const timer = setTimeout(() => {
// 如果1秒后广告仍然在 Map 中
// 说明没有离开可视区域
if (visibleAds.has(adId)) {
// 上报广告曝光
reportExposure(adId)
// 取消监听,避免重复统计
observer.unobserve(el)
// 删除计时器记录
visibleAds.delete(adId)
}
}, 1000)
// 保存计时器
visibleAds.set(adId, timer)
} else {
// 如果广告离开视口
// 获取之前的计时器
const timer = visibleAds.get(adId)
if (timer) {
// 清除计时器
clearTimeout(timer)
// 删除记录
visibleAds.delete(adId)
}
}
})
}, {
// threshold = 0.5 表示至少50%进入视口才触发
threshold: [0.5]
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# 首屏加载慢优化
通过 Chrome Performance + Network 分析
使用 动态 import
CDN 外链,将大体积依赖放 CDN
vite配置 external: ['vue','echarts']
路由懒加载
2
3
4
5
6
# 广告曝光统计不准确
可见面积 ≥ 50%
停留时间 ≥ 1 秒
可见面积 ≥ 50%
停留时间 ≥ 1 秒
进入视口
↓
开始1秒计时
↓
如果离开视口 → 取消
↓
1秒后仍然可见 → 统计曝光
2
3
4
5
6
7
8
9
10
11
12
13
1 收集用户反馈
2 查看监控日志 sentry
3 复现问题
4 Chrome DevTools 排查
5 查看接口请求
6 查看错误日志
7 定位代码
2
3
4
5
6
7
# 广告封装难度
不同厂商 API 不一致
创建广告方式不同
事件回调不同
加载方式不同
统一广告 SDK 封装
业务层
↓
广告封装层
↓
厂商SDK
广告填充率提高
代码可维护性提升
多个快应用项目可以复用
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 你对公司有什么想要了解的
目前团队架构是什么样的,主要在开发什么项目
上班时间
我如果有幸入职了,我需要负责什么业务
2
3
4
5
我想做一个语音识别的网页,输入语音,调用windows电脑的funasr,然后调用大模型接口,回答语音输入的问题,
model_dir = "FunAudioLLM/Fun-ASR-Nano-2512"
model = AutoModel(
model=model_dir,
vad_model="fsmn-vad",
vad_kwargs={"max_single_segment_time": 30000},
device="cuda:0",
)
2
3
4
5
6
7
8
9
# 看视频学习,
# 要自信,声音洪亮
低代码平台,
1000w表格渲染,使用canvas花的,然后二进制
2
3
4

使用github的工作流,上传git之后自动推送到服务器