大前端高频面试题:3000道题拆成知识格与实战答案
2026/9/18 1:42:16 网站建设 项目流程

简介:面向大前端求职者与前端工程师的高频面试题库,覆盖互联网大厂常考知识点,既适合面试前集中复习,也可作为面试官出题和团队培训的参考。压缩包内共1个pdf文件,大小约8.37MB,全文1000多页,下载后可在电脑或平板上随时查阅。目录按计算机基础、HTML5与CSS3、JavaScript、TypeScript、Vue、React、Node.js、生态工具、图形图像3D、WebRTC与WebSocket、数据结构与算法、微前端等模块展开,收录3000道高频题并附答案解析。每道题不只给结论,还讲清原理与实现思路,如进程与线程、死锁条件、虚拟内存、TCP与UDP、OSI七层模型、GET与POST、事务ACID、二分查找与冒泡排序优化,并延伸至WebRTC的RTP/RTCP、WebSocket压缩扩展、Web Audio API调度等进阶主题。已有347人学习,适合按章节查漏补缺,系统建立大前端知识框架。

1. 3000 道题的价值不在数量,在于它把大前端切成了可核对的知识格

面试前一周翻出「3000 道高频面试题」的人,通常栽在同一个地方:题看得完,答不出来。原因不是记性差,是这些题按 JS、CSS、框架、工程化、网络、浏览器混排在一起,没有权重、没有验证、也没有和你简历里的项目对上号。真正有效的用法是把它当成一张清单用:先用目标岗位的 JD 反推每个知识域该占多少题,再把每道题拆成「一句话结论 + 一段能跑的代码 + 一个我踩过的坑」,最后用限时口述做校验,答不顺的题回炉。

这套流程对正在准备大厂前端面试的初中级工程师最直接,对带人的技术负责人也一样有用——团队内部的题库就是这么攒出来的。下面按知识域划分、单题吃透、模拟实战、题库维护四步往下走,每一步都给出可复现的脚本和配置,而不是让你对着 1000 多页 PDF 漫无目的地刷。

2. 把 3000 道大前端高频面试题切成可复习的模块

2.1 大前端的六个主干域与题量权重

大前端这个词在不同公司指向不同,但落到面试题上,逃不出六个域:JS 语言与运行时、CSS 与布局、浏览器与网络、框架原理、工程化与构建、跨端与可视化。3000 道题按这六个域切完,你会发现分布极不均匀:框架原理和 JS 加起来能占一半,跨端可能只有一两百道。

权重不是题量决定的,是目标岗位决定的。校招和初级岗位更看重语言基础和手写能力,高级岗位更看重工程化决策和性能治理。我一般用下面这张表做初筛,再按 JD 微调:

知识域典型高频题初级/校招占比高级/资深占比
JS 语言与运行时闭包、原型链、事件循环、this 绑定25%15%
CSS 与布局BFC、flex/grid、层叠上下文、移动端适配15%8%
浏览器与网络缓存策略、跨域、HTTP/2、渲染流水线18%18%
框架原理Vue3 响应式、diff 算法、hooks 闭包陷阱22%22%
工程化与构建Vite/Webpack、Tree Shaking、Monorepo、CI12%22%
跨端与可视化小程序、大屏自适应、Canvas/WebGL8%15%

注意跨端与可视化这一栏,很多人直接跳过。但凡简历里写过「数据大屏」或者「多端复用」,面试官一定会追问自适应方案和渲染性能,这一块的投入产出比其实很高。

2.2 别按题号刷,按「考点指纹」合并同类题

3000 道题里有大量重复。「Vue3 中 ref 和 reactive 的区别」和「reactive 与 ref 在使用上有什么不同」是同一道题,只是换了个说法。先做去重,能把有效题量压到一半以下,复习时间立刻省出来。

做法是把题干归一化成一个粗指纹:去掉「请说一下」「谈谈」「是什么」这类提问套话,再剥掉标点,取前若干字符做 key。下面这段脚本读一个 JSON 题目清单,输出重复度最高的若干组:

import json, re from collections import defaultdict # 提问套话 + 高频修饰词,归一化时先剔除 NOISE = re.compile(r"(请|简单|详细|说一下|谈谈|是什么|有哪些|区别|原理|面试题|高频)") def fingerprint(title: str) -> str: s = NOISE.sub("", title) s = re.sub(r"[^\u4e00-\u9fa5a-zA-Z0-9]", "", s) # 只保留中英文数字 return s[:12] # 粗指纹,宁可多分组 questions = json.load(open("questions.json", encoding="utf-8")) buckets = defaultdict(list) for item in questions: buckets[fingerprint(item["title"])].append(item) for fp, group in sorted(buckets.items(), key=lambda x: -len(x[1]))[:10]: print(len(group), fp, [g["title"] for g in group][:3])

NOISE决定了归一粒度,去掉得越多,分组越粗;[:12]是经验值,太短会把不相干的题并到一起,太长又会漏掉真正的重复。questions.json每项至少要有titledomain两个字段,domain 来自上一节的六域划分。输出结果里len(group) > 1的组,人工挑一版留下,其余标记为dup_of,后续统计题量时不再计入。

提示:指纹只用来找候选重复,最终合并一定要人工过一遍。见过把「Vue3 的 diff」和「React 的 diff」并成一组的情况,原理完全不同。

2.3 权重表怎么落地:从 JD 反推复习顺序

知道每个域有多少题之后,还要知道该给哪个域多分时间。我的做法是把三到五份目标岗位的 JD 存成纯文本,直接统计关键词命中次数,用得越多说明这个域越核心:

# jd/ 目录下放目标岗位的 JD 文本,统计各能力关键词出现次数 for kw in 性能优化 微前端 大屏 SSR Node 工程化 可视化 Canvas; do printf "%-8s %s\n" "$kw" "$(grep -ro "$kw" jd/ | wc -l)" done

grep -ro-o保证按出现次数计数而不是按行数,-r递归整个目录。跑出来的数字直接对应复习优先级:命中高的域先做,命中为 0 的域可以放到最后。

再给每个域做一次 1 到 5 分的自评掌握度,复习顺序就是「权重 ÷ 掌握度」从高到低排。这个排序每周重算一次,比固定计划表灵活得多。真正拉开差距的往往不是最难的题,而是权重高、你又恰好答不利索的那几个域。

3. 单题吃透:大前端面试题答案的三层写法与可验证的代码

3.1 一道题的答案应该有三层

第一层是一句话结论,面试官问完你先给判断;第二层是机制解释,说清运行时或框架层面发生了什么;第三层是边界条件和你踩过的坑。只背第一层的人,一被追问就露馅;只讲第二层的人,面试官会怀疑你没写过业务代码;三层都有,才算把这道题收进自己的知识格。

拿「闭包」举例:结论是「函数持有对外部作用域的引用,使外部变量在函数返回后仍不被回收」;机制是词法作用域在函数创建时确定,V8 里通过 Context 对象保存被引用的变量;边界是循环里用var注册事件会全部输出同一个值、以及长生命周期闭包导致的内存驻留。多数人只答前两层,第三层才是区分度所在。

3.2 用可运行代码验证 JS 与浏览器类题目

事件循环这类题,背结论没用,因为不同运行环境的细节不一样。把下面这段代码在浏览器和 Node 里各跑一遍,顺序差异本身就是面试素材:

// 事件循环顺序验证:同步 -> 微任务 -> 宏任务 console.log('1 script start') setTimeout(() => console.log('2 setTimeout'), 0) Promise.resolve().then(() => console.log('3 promise then')) queueMicrotask(() => console.log('4 queueMicrotask')) console.log('5 script end') // 输出顺序:1 5 3 4 2

Promise.thenqueueMicrotask都进微任务队列,按入队顺序执行;setTimeout属于宏任务,要等当前轮微任务队列清空才轮到它,所以即使延时写 0 也排在最后。

浏览器和 Node 在这里基本一致,差异出现在setImmediatesetTimeout(fn, 0)的主模块执行顺序上——Node 里两者顺序并不确定,取决于当次循环启动耗时。面试时能主动说出「主模块内不确定、在 I/O 回调里 setImmediate 稳定优先」,比复述一遍宏微任务定义有力得多。

3.3 布局题怎么验证:Vue3 + Element Plus 大屏自适应

自适应大屏是简历上的高频项目,也是高频追问点。方案无非两类:rem/vw 的流式缩放,和按设计稿整体transform: scale()的等比缩放。固定设计稿、元素位置不能重排的大屏用后者更稳:

// useScreenScale.js —— 按 1920x1080 设计稿等比缩放 import { ref, onMounted, onUnmounted } from 'vue' export function useScreenScale(design = { width: 1920, height: 1080 }) { const scale = ref(1) const style = ref({}) function resize() { const { innerWidth: w, innerHeight: h } = window // 取宽高比中较小的那个,保证设计稿完整可见、不裁切 const s = Math.min(w / design.width, h / design.height) scale.value = s style.value = { width: `${design.width}px`, height: `${design.height}px`, transform: `scale(${s})`, transformOrigin: 'left top', // 必须写,否则以中心缩放导致定位全错 position: 'absolute', left: `${(w - design.width * s) / 2}px`, // 水平居中留白 top: `${(h - design.height * s) / 2}px` } } onMounted(() => { resize() window.addEventListener('resize', resize) }) onUnmounted(() => window.removeEventListener('resize', resize)) return { scale, style } }

Math.min而不是分别算宽高比例,是为了避免非等比例拉伸把圆形压成椭圆。transformOrigin必须设成left top,否则缩放中心在元素正中,配合绝对定位的偏移量会全部算错——这是最常见的一个坑。

再往下的加分点是 Element Plus 的下拉框、日期选择器在缩放容器里会飘:transform会让元素创建新的包含块,Popper 计算偏移时拿到的是缩放后的getBoundingClientRect(),视觉位置就对不上。解法是把弹层通过teleport挂到 body 外层,或者给弹层容器单独写一个反缩放系数。能把这句说出来,说明方案是真跑过的。

3.4 框架原理题:背诵式答法和加分答法的差距

同一个问题,答法的层次差别很大:

题目背诵式答法加分答法
ref 和 reactive 区别ref 用 .value,reactive 不用ref 用 RefImpl 包装,为了在 Proxy 无法代理基本类型时仍能追踪;解构 reactive 对象会丢失响应性
key 的作用帮助 diff 识别节点列表就地复用时,key 决定了节点能否复用;用 index 做 key 在插入排序场景下会引发状态错位
Vue3 diff双端比较无 key 用 patch 长度差,有 key 先做首尾预处理,再对剩余部分求最长递增子序列,减少 DOM 移动
v-if 与 v-show一个销毁一个隐藏结合v-if的编译期提升和v-show的初始渲染成本,说明频繁切换场景该选哪个

把这张表填满,框架原理这一域基本就稳了。填的过程本身就是复习:写不出加分答法的地方,就是需要回去读源码或写 demo 的地方。

4. 模拟实战:手写题、场景题和 Agent 方向新题怎么串成一场

4.1 手写题的三个模板覆盖八成

手写题看着多,其实模板就那么几个。防抖节流和深拷贝练熟,剩下的多半是它们的变体:

// 1) 防抖:wait 毫秒内重复触发只执行最后一次 function debounce(fn, wait = 300, immediate = false) { let timer = null return function (...args) { if (timer) clearTimeout(timer) if (immediate && !timer) fn.apply(this, args) // 首次立即执行 timer = setTimeout(() => { timer = null if (!immediate) fn.apply(this, args) }, wait) } } // 2) 节流:每 wait 毫秒最多执行一次,trailing 保证最后一次不丢 function throttle(fn, wait = 300, trailing = true) { let last = 0, timer = null return function (...args) { const now = Date.now() if (now - last >= wait) { last = now fn.apply(this, args) } else if (trailing && !timer) { timer = setTimeout(() => { last = Date.now(); timer = null fn.apply(this, args) }, wait - (now - last)) } } }

面试官最容易追问的两点,一是this和参数透传——所以两处都用了fn.apply(this, args)而不是直接fn();二是取消能力,防抖要补一个cancel方法挂到返回函数上,节流要处理trailing为 true 时最后一次触发的时机。写的时候主动说出来,比等他问再补要强。

深拷贝同理,能自己说出循环引用用WeakMap缓存、Date/RegExp/Map/Set要单独分支、函数不拷贝只能引用传递,这题就算过了。别背一个二十行的万能函数,说清取舍更值钱。

4.2 场景题:性能优化要按指标说话

回答性能优化最忌讳罗列手段。正确的骨架是「指标 → 定位 → 手段 → 验证」,先说盯的是 LCP、INP 还是 CLS,再说怎么测出来的,最后才讲改了什么:

手段主要影响指标代价
路由级懒加载 + 分包LCP首屏多一次请求,弱网下可能更慢
图片懒加载 + 现代格式LCP、CLS必须写死宽高,否则布局抖动
长任务切分(时间切片)INP代码复杂度上升,状态管理变麻烦
骨架屏 + 预渲染LCP、CLS构建流程变长,需维护两套结构

后台管理系统类的项目(比如基于 JeecgBoot 的 Vue3 前端)性能瓶颈通常不在首屏而在交互:表格上千行、字典项反复请求、弹窗里嵌套大表单。这类项目讲优化的抓手是虚拟滚动、字典缓存和按需渲染,比讲打包体积更贴合面试官的实际经验。

4.3 前端转 Agent 开发:新题怎么接

现在不少岗位会在最后加一轮和 AI 应用相关的问题,不要求你会训模型,但要求你能把流式响应和工具调用接进界面。最常见的追问是「流式输出怎么实现」,标准答案是 SSE,用fetchReadableStream手写解析比EventSource灵活,因为后者不支持 POST 和自定义请求头:

// 用 fetch + ReadableStream 解析 SSE 流 async function* sseStream(url, payload) { const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }) const reader = res.body.getReader() const decoder = new TextDecoder() let buf = '' while (true) { const { done, value } = await reader.read() if (done) break buf += decoder.decode(value, { stream: true }) const parts = buf.split('\n\n') // SSE 事件之间用空行分隔 buf = parts.pop() // 最后一段可能被截断,留到下一轮 for (const p of parts) { const line = p.split('\n').find(l => l.startsWith('data:')) if (line) yield JSON.parse(line.slice(5).trim()) } } }

decoder.decode(value, { stream: true })不能省,多字节字符可能被切在两个 chunk 之间;parts.pop()保留下来的残片是必须的,否则会丢掉半截 JSON 导致JSON.parse抛错。

再往深一层的问题是渲染:每个 token 都触发一次全量 Markdown 重渲染,长回答会直接卡死主线程。常见做法是按帧合并更新、代码块单独组件化、用AbortController支持中断生成。这些点能讲明白,转 Agent 开发方向这一轮基本不会被卡住。

4.4 排错类问题:白屏、401 和样式错乱怎么答

这类题考的是排查路径,不是答案本身。白屏先看控制台有没有 JS 报错,再看 Network 里主包是否 200、是否被 CDN 缓存了旧版本、路由守卫有没有死循环重定向;401 先确认 token 是否存在、时钟偏移是否导致 JWT 校验失败、刷新 token 的并发请求有没有去重;样式错乱先看是不是微前端子应用的样式没加作用域、全局 CSS 变量被覆盖。

答的时候按「先定位层级,再收敛范围」讲:是构建产物问题、运行时错误、还是网络层问题,三类的排查入口完全不同。能说出用 VSCode 的 JavaScript Debugger 直接 attach 到 Chrome、配好webRoot打断点,比只会开 DevTools 更让面试官放心。

5. 让题库活下来:一题一文件、每天抽题口述

5.1 一题一文件,交给编辑器全局搜索

1000 多页合集最大的问题是没法检索和更新。我的做法是拆成一题一个 Markdown 文件,目录按知识域分层,文件名用短横线连接的考点名,例如framework/vue3-ref-vs-reactive.md。这样在 VSCode 里Ctrl+Shift+F全局搜索「响应式」,跨文件命中一次全出来,比翻 PDF 快一个量级。

文件内部固定四段:结论、机制、代码、踩坑。写不出代码段的题,说明还没吃透,直接标#todo,下次优先补。

5.2 每天抽十题做口述训练

看得懂不等于讲得出。用一个脚本每天随机抽十题,看到标题就开口讲 60 秒,讲不顺的记下来:

# 从题库目录随机抽 10 个文件,打印文件路径和首行标题 find ~/interview-bank -name '*.md' \ | sort -R | head -n 10 \ | while read f; do printf "%s\n %s\n" "$f" "$(head -n 1 "$f")" done

GNU 环境用sort -R做随机排序,macOS 上默认的 BSD sort 不支持-R,装 coreutils 后换成gsort -R,或者用awk 'BEGIN{srand()} {print rand(), $0}' | sort -n | cut -d' ' -f2-替代。head -n 1取的是文件第一行标题,所以约定每个文件第一行必须是# 题目,别放注释。

每周把讲不顺的题重新标一遍,两周还没讲顺的,基本就是知识盲区而不是紧张问题,值得回去补源码。

5.3 用调试器核对「页面代码到底是怎么组成的」

面试里被问「你怎么确认这段代码在生产环境真的执行了」,能现场演示比嘴上说强。在.vscode/launch.json里配一个 Chrome attach 配置:

{ "version": "0.2.0", "configurations": [ { "type": "chrome", "request": "launch", "name": "调试本地页面", "url": "http://localhost:5173", "webRoot": "${workspaceFolder}/src", "sourceMaps": true } ] }

webRoot必须指向源码根目录,指错了断点会变灰不可用;sourceMaps依赖构建工具打开 sourcemap,Vite 开发模式默认就有,生产构建要显式开build.sourcemap。打断点之后配合 DevTools 的 Coverage 面板看哪些代码没被执行到,就能回答「这段逻辑是不是死代码」这类追问。

真正把 3000 道题变成资产的动作只有一个:每道题的踩坑那段必须是你自己写的,哪怕只有一行。别人整理的答案只解决「知道」,自己踩过的坑才解决「讲得出来」。

本文还有配套的精品资源,点击获取

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

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

立即咨询