前端开发面试深挖 15 题
每题都拆成「平淡回答 → 追问逻辑 → 高分示范」三层,看清面试官到底在追什么。
题目为高频真实问法;①②③ 三层答案为模拟示范,非真实面经
① 简历常见平淡回答
「JS 是单线程的,同步任务先执行,异步任务放进队列,等同步执行完再从队列里取出来跑。」
为什么不够:只背了定义,没说清宏任务与微任务的执行顺序,也没有任何工程场景,面试官无法判断你到底踩没踩过坑。
② 面试官追问逻辑
③ 深挖后可量化的高分示范
一次 tick 先清空微任务队列再取一个宏任务,所以 then 回调一定早于零毫秒的 setTimeout。做批量上传状态条时,我用同步循环更新 200 个文件的进度,主线程卡死 3.2 秒;改成 20 个一批合并进微任务、再由 requestAnimationFrame 收敛渲染后,掉帧时间降到 0.4 秒。最后点出边界:微任务里递归会饿死渲染,所以我加了 5 层深度上限。
① 简历常见平淡回答
「闭包就是函数里面套函数,内部函数可以访问外部的变量。」
为什么不够:定义是背的,没有说清闭包解决了什么问题、代价是什么,也没有真实场景支撑。
② 面试官追问逻辑
③ 深挖后可量化的高分示范
我会先说机制:函数持有外层作用域引用,让变量的生命周期脱离调用栈。场景是我们埋点 SDK 需要为每条事件保存一次性的上下文,我用闭包封装 reportId 与重试次数,外部改不到,避免了全局污染。代价我也讲:闭包持有 DOM 引用曾导致一个已卸载的弹窗没被回收,我用 Performance 面板的堆快照定位后,在销毁钩子里手动置空解决。
① 简历常见平淡回答
「深拷贝就是把对象完全复制一份,改新的不影响旧的,用递归就能实现。」
为什么不够:没提循环引用、没提特殊类型处理,面试官一听就知道你没真正写过生产级的工具函数。
② 面试官追问逻辑
③ 深挖后可量化的高分示范
我先说边界:JSON 方案会丢掉 undefined、函数和 Date,只能用于纯数据。我的实现用 WeakMap 缓存已拷贝对象解决循环引用,对 Date、RegExp、Map、Set 分别走各自的构造分支,其余对象走递归。补一句权衡:递归在层级过深时会爆栈,所以线上我优先用 structuredClone,只有需要兼容旧浏览器时才回退到自己的实现。
① 简历常见平淡回答
「依赖数组里放了什么变量,这个变量变了 effect 就重新执行,不写就是每次都跑。」
为什么不够:只描述了现象,没说清依赖项的比较规则,也没提闭包陷阱这个高频翻车点。
② 面试官追问逻辑
③ 深挖后可量化的高分示范
React 每轮渲染用 Object.is 浅比较前后依赖。如果依赖放内联对象,引用每次都变就会死循环。闭包陷阱的根因是 effect 函数捕获了当轮渲染的 state 快照,解法是用 setState 的函数式更新或者用 ref 保存最新值。我线上遇到过列表下拉加载时 page 永远是 1,就是因为把 fetch 函数写在组件内但没用 useCallback 包装,导致闭包锁死了旧 page。
① 简历常见平淡回答
「虚拟 DOM 是把真实 DOM 变成 JS 对象,比直接操作真实 DOM 快很多。」
为什么不够:「比原生快」是个流传很广的误解。面试官一听就知道你没读过源码,也没做过真正的性能压测。
② 面试官追问逻辑
③ 深挖后可量化的高分示范
虚拟 DOM 从来不比精心优化的原生 DOM 快,它解决的是性能下限和跨平台抽象,让开发者用声明式写代码的同时不至于掉进频繁重排的坑。Diff 算法用三个假设把 O(n³) 降到 O(n):同层比较、唯一 key、类型不同直接替换整棵树。我们后台曾把一个 5000 行的虚拟表格从全量 Diff 改为基于 key 的增量局部更新,首屏渲染耗时从 680ms 降到 45ms。
① 简历常见平淡回答
「我会先开 Lighthouse 跑个分,然后开 Gzip、做路由懒加载、把大图压缩一下。」
为什么不够:像背优化清单。没有区分网络层、解析层和渲染层,没有给出指标 baseline,也没有讲优先级排序。
② 面试官追问逻辑
③ 深挖后可量化的高分示范
我按「量化基线 → 网络层 → 资源层 → 渲染层」四步排查。先看 Performance 面板把 FCP、LCP、TTI 拆开:如果 TTFB 慢优先排查 CDN 缓存命中率与 DNS 预解析;如果是 LCP 慢,往往是大图或主 bundle 阻塞。我们之前一个 B 端工作台 LCP 4.8 秒,排查发现是 iconfont 和富文本编辑器打进了主包。我用 webpack-bundle-analyzer 拆分后做路由级 dynamic import,主 bundle 从 2.4MB 降到 380KB,配合 WebP 与预加载关键字体,LCP 降至 1.4 秒。
① 简历常见平淡回答
「我们用 qiankun,子应用挂在主应用里,用 postMessage 通信,样式用 scoped CSS。」
为什么不够:技术选型只说了名字,没有解释为什么要微前端、遇到了什么坑,样式隔离的真正边界也没讲清。
② 面试官追问逻辑
③ 深挖后可量化的高分示范
我们因为 3 个老系统技术栈不统一(Vue2/React16/React18)采用 qiankun。通信层用主应用派发的全局 event-bus,限制只传递必要的用户鉴权 token 和语言偏好,避免业务状态强耦合。样式隔离没用 shadow DOM 因为 AntD 的 Select 下拉挂在 body 会丢失全局变量,我们最终采用类名前缀 + PostCSS 插件在编译期自动给子应用所有选择器注入命名空间。公共依赖用 module federation 共享 React 运行时,子应用体积减少了 40%。
① 简历常见平淡回答
「可以用分页,或者用虚拟列表,只渲染可视区域的几条。」
为什么不够:虚拟列表很多人都听过,但关键在于不定高怎么算、快速滚动白屏怎么破、动态高度测量缓存怎么做。
② 面试官追问逻辑
③ 深挖后可量化的高分示范
核心是「可视区计算 + 缓冲区预渲染 + 位置缓存」。对不定高列表,我用二分查找预估位置,渲染后用 ResizeObserver 动态获取真实高度并写回 positions 数组,同时更新 offsetSum。为解决快速滚动白屏,我上下各加了 5 个 item 的 buffer 区,并开启 will-change: transform 提升为独立合成层。在支持的浏览器上配合 CSS content-visibility: auto 做外层跳过,10 万条数据帧率稳定在 58fps 以上。
① 简历常见平淡回答
「用 Sentry 捕获错误,React 里用 ErrorBoundary 包一下,页面就不会白屏。」
为什么不够:异常捕获只说了工具名。上报风暴怎么办?异步错误 ErrorBoundary 抓不到怎么办?SourceMap 泄露怎么防?
② 面试官追问逻辑
③ 深挖后可量化的高分示范
我们分「全景捕获 → 客户端聚合 → 降级兜底」三层。window.onerror 配合 unhandledrejection 兜底异步异常,组件层用三级 ErrorBoundary:全局级跳友好错误页、模块级显示重试卡片、卡片级静默降级。上报层做了客户端指纹去重,相同 error.stack 5 秒内只上报一次并累加计数,超过阈值触发降频采样。SourceMap 仅在内网自建的符号化服务上解析,禁止上传到公网,兼顾了排查效率与代码安全。
① 简历常见平淡回答
「代码 push 到 GitLab,触发 runner 跑 build 和 test,成功后部署到服务器。」
为什么不够:流程太粗。没有讲缓存机制、质量门禁、灰度发布和回滚策略,听不出做过严谨的团队工程治理。
② 面试官追问逻辑
③ 深挖后可量化的高分示范
我们的 GitHub Actions 流水线拆成四个阶段:Lint & TypeCheck(门禁,2 分钟超时)、并行跑 Vitest 单元测试、打包构建、灰度发布。缓存上我们针对 pnpm store 和 next 缓存做了 hash 校验,冷启动 6 分钟降到 1 分 40 秒。环境配置通过独立的安全密钥管理注入,构建产物用镜像打包做到一次构建多环境运行。部署支持一键回滚到上一个稳定版本的静态资源 hash,全流程 90 秒内完成。
① 简历常见平淡回答
「做过内部 UI 库,用 Storybook 写 demo,用 npm 发包,改动加版本号就行。」
为什么不够:没有讲 Design Token 体系、无障碍访问(a11y)、按需引入打包,以及破坏性更新的渐进废弃策略。
② 面试官追问逻辑
③ 深挖后可量化的高分示范
我们服务 8 个业务线的组件库遵循三大原则:第一,样式全部基于 CSS 变量构筑的 Design Token,暗黑模式切换只需改根节点 class;第二,API 变更严格遵循 SemVer,废弃属性通过控制台 console.warn 发出带迁移文档链接的警告,保留两个大版本后再移除;第三,构建产物同时输出 ESM 并保留原始副作用标记 package.json:sideEffects,防止 Tree-shaking 失效。上线半年后跨项目的视觉走查问题从 20 多个降到 2 个。
① 简历常见平淡回答
「我当时觉得这个方案更好,就在会上说了几次,最后还是推下去了,上线后效果还不错。」
为什么不够:没说清反对意见到底是什么、你怎么说服的、最后拿什么衡量,全程只有结论没有过程,面试官抓不到你的影响力。
② 面试官追问逻辑
③ 深挖后可量化的高分示范
背景:订单列表首屏 4.2 秒,团队习惯性加机器,我提议改成接口聚合加虚拟滚动,测试同学以改动大、风险高强烈反对。我没有硬推,用一周做了灰度原型,用 A/B 数据说明首屏可到 1.6 秒、接口请求数从 27 个降到 6 个,先在 5% 流量验证零报错再全量。结果:首屏稳定在 1.6 秒,季度服务器成本降了 18%。复盘我会补一句:如果重来,我第一天就把测试同学拉进方案评审,能省掉两周返工。
① 简历常见平淡回答
「大家各有道理,我会沟通一下,最后听领导的。」
为什么不够:没有立场也没有方法,面试官看不出你能否独立推进问题。
② 面试官追问逻辑
③ 深挖后可量化的高分示范
一次是优惠券叠加规则,产品要求前端实时算,后端希望下发放缓存。我先问清目标:他们要的是结算页不出错,不是实时性。于是我提了折中方案——前端做乐观计算给即时反馈,最终金额以接口返回为准并给出差异提示。方案落地后结算页报错率从 0.7% 降到 0.05%。我的原则是先把冲突翻译成共同目标,再谈实现。
① 简历常见平淡回答
「有一次发布后页面白屏,我紧急回滚了,后来修好了。」
为什么不够:没有时间线、没有影响面、没有复盘动作,显得没真正处理过重大故障。
② 面试官追问逻辑
③ 深挖后可量化的高分示范
去年 11 月一次发布后,商品详情页白屏 23 分钟,影响约 4.6 万次访问。表面原因是一个可选的埋点 SDK 抛错阻断了渲染,根因是我们的入口没有做第三方脚本隔离,也没有灰度。我当场回滚并补了两件事:第三方脚本统一走 try-catch 沙箱加载;发布流程强制 5% 灰度观察 10 分钟。此后 8 个月同类事故为零。
① 简历常见平淡回答
「原来的发展空间有限,想找个更能成长的平台。」
为什么不够:这是模板答案,既没有事实支撑,也容易让面试官怀疑稳定性。
② 面试官追问逻辑
③ 深挖后可量化的高分示范
我在上一家把中台组件库从 0 做到覆盖 6 条业务线,但后续主要是维护,能接触的技术挑战变小了。我想要的下一步是参与从性能到体验都能闭环决定的产品,而你们的前端团队直接对业务指标负责,这与我想做的事一致。同时我会说明:过去两年我只换过一次工作,不是频繁跳槽的人。