-
执行上下文与闭包的底层原理 (⭐⭐⭐⭐)
- 请结合“词法作用域(Lexical Scope)”和“执行上下文栈(ECS)”解释闭包是如何产生的?
- 闭包会导致内存泄漏吗?V8 引擎是如何处理闭包引用的变量回收的?
-
事件循环(Event Loop)深度剖析 (⭐⭐⭐⭐)
- 描述浏览器与 Node.js(特别是 v11 版本前后)在 Event Loop 处理上的差异。
- 宏任务(MacroTask)与微任务(MicroTask)的执行顺序,requestAnimationFrame 和 requestIdleCallback 在其中的位置是什么?
-
原型链与继承终极方案 (⭐⭐⭐)
- 手写 ES5 的寄生组合式继承。
- ES6 class 的 super() 到底做了什么?它和 ES5 的继承有何本质区别?
-
V8 垃圾回收机制 (GC) (⭐⭐⭐⭐)
- 讲一下 V8 的新生代(Scavenge 算法)和老生代(Mark-Sweep & Mark-Compact)回收策略。
- 什么情况下会出现内存泄漏?如何使用 Chrome Memory 面板排查?
-
Promise 核心标准 (A+ Spec) (⭐⭐⭐⭐⭐)
- Promise 的状态流转是怎样的?.then 的链式调用是如何实现的(返回新 Promise)?
- 如何中断一个 Promise 链?
-
WeakMap 与 WeakSet (⭐⭐⭐)
- 它们与 Map/Set 的区别是什么?为什么说它们是“弱引用”?
- 在 Vue3 响应式原理或 DOM 节点元数据存储中有哪些应用场景?
-
迭代器(Iterator)与生成器(Generator) (⭐⭐⭐)
- async/await 的实现原理是什么?(请口述如何用 Generator + Co 自动执行器模拟 async)。
🦕 模块二:TypeScript
考察点:不再是简单的类型定义,而是类型推导、泛型编程和类型体操。
-
泛型(Generics)与约束 (⭐⭐⭐)
- 解释泛型约束 T extends U 的作用。
- 如何在函数中限制泛型参数必须包含某些属性?
-
高级类型工具原理 (⭐⭐⭐⭐)
- 请手写实现 TS 内置工具类型:Partial, Pick<T, K>, Omit, Readonly。
-
infer 关键字与条件类型 (⭐⭐⭐⭐⭐)
- 解释 infer 的作用。
- 实战题:如何编写一个类型工具,提取 Promise 内部的返回类型?(例如 UnwrapPromise<Promise> 得到 string)。
-
逆变(Contravariance)与协变(Covariance) (⭐⭐⭐⭐⭐)
- 在 TypeScript 中,函数参数和返回值的类型兼容性遵循什么原则?(口诀:参数逆变,返回值协变),请举例说明。
-
Discriminated Unions (可辨识联合) (⭐⭐⭐)
- 在 Redux 的 Action 定义或复杂状态管理中,如何利用字面量类型进行类型守卫(Type Guard)?
-
unknown vs any vs never (⭐⭐⭐)
- unknown 和 any 的区别是什么?
- never 类型在“穷尽性检查(Exhaustiveness checking)”中的应用。
⚛️ 模块三:框架原理 (以 React 为主,兼顾 Vue)
考察点:源码级理解,不再停留在生命周期背诵,而是关注 Diff、调度、状态与复用。
-
Virtual DOM 与 Diff 算法 (⭐⭐⭐⭐)
- React: 解释 Fiber 架构解决了什么问题?Diff 算法中的 Key 到底起了什么作用?(O(n) 复杂度的前提)。
- Vue: Vue2 的双端比较与 Vue3 的最长递增子序列(LIS)算法有何不同?
-
状态更新机制 (Batching) (⭐⭐⭐⭐)
- React 的 setState 是同步还是异步的?在 React 18 的 Automatic Batching 中有什么变化?
- Vue 的 nextTick 原理是什么?它是如何利用微任务队列合并 DOM 更新的?
-
Hooks 实现原理 (⭐⭐⭐⭐⭐)
- 为什么 React Hooks 不能在条件语句或循环中调用?(链表结构与顺序依赖)。
- useMemo 和 useCallback 真的能提升性能吗?什么时候通过它们优化反而是负优化?
-
响应式原理对比 (⭐⭐⭐⭐)
- 详细对比 Vue2 (Object.defineProperty) 与 Vue3 (Proxy) 的响应式实现差异。
- Proxy 相比 defineProperty 解决了哪些痛点(如数组监听、属性增删)?
-
组件通信与复用 (⭐⭐⭐)
- React 的 HOC (高阶组件) vs Render Props vs Hooks,各自的优缺点是什么?
-
React Scheduler (时间切片) (⭐⭐⭐⭐⭐)
- React 是如何通过 MessageChannel 实现时间切片的?为什么不直接用 setTimeout?
- 解释 Concurrent Mode(并发模式)下的“中断”与“恢复”机制。
🛠️ 模块四:前端工程化
考察点:构建工具链的深度与广度,模块化标准,性能优化手段。
-
Webpack 构建流程与原理 (⭐⭐⭐⭐)
- 简述 Webpack 的打包流程(Init -> Make -> Seal -> Emit)。
- Loader 和 Plugin 的本质区别是什么?请描述一下你写过的一个 Plugin 是如何介入构建周期的(Tapable 钩子)。
-
HMR (热更新) 原理 (⭐⭐⭐⭐⭐)
- Webpack HMR 是如何通过 WebSocket 通信将更新推送到浏览器的?浏览器收到更新后如何替换模块而不需要刷新页面?
-
Vite vs Webpack (⭐⭐⭐⭐)
- Vite 为什么在开发环境这么快?(基于 Native ESM + esbuild)。
- Vite 在生产环境为什么要用 Rollup 打包?
-
模块化标准 (CommonJS vs ESM) (⭐⭐⭐⭐)
- CommonJS 的动态加载与 ESM 的静态分析有什么区别?
- 为什么 Tree-Shaking 必须基于 ESM?它是如何判定“无用代码”的(副作用/Side Effects)?
-
Babel 原理 (⭐⭐⭐)
- Babel 是如何将 ES6 代码转换为 ES5 的?(Parse -> Transform -> Generate)。
- 解释 AST(抽象语法树)在其中的作用。
-
大型项目构建优化 (⭐⭐⭐⭐)
- 面对一个构建速度慢的大型项目,你有哪些优化手段?(DLL, Cache, Thread-loader, Module Federation 等)。
🌐 模块五:浏览器与网络
考察点:全链路性能、安全攻防、协议细节。
-
从输入 URL 到页面渲染全过程 (硬核版) (⭐⭐⭐⭐⭐)
- 请详细描述 DNS 解析、TCP 握手、TLS 握手、HTTP 缓存策略、CRP(关键渲染路径)、重排重绘。
- 追问:如果页面白屏时间过长,你如何通过 Chrome Performance API 定位是网络问题还是 JS 执行问题?
-
HTTP 协议进化史 (⭐⭐⭐⭐)
- HTTP/1.1 的队头阻塞 (Head-of-line blocking) 是什么?
- HTTP/2 的多路复用 (Multiplexing) 和头部压缩 (HPACK) 原理。
- HTTP/3 (QUIC) 是如何基于 UDP 解决 TCP 层面的队头阻塞问题的?
-
跨域解决方案 (⭐⭐⭐)
- CORS 的简单请求与预检请求 (Options) 的触发条件。
- Nginx 反向代理解决跨域的配置原理。
-
前端安全 (XSS & CSRF) (⭐⭐⭐⭐)
- XSS: 存储型 vs 反射型 vs DOM 型。React/Vue 默认是如何防御 XSS 的?
- CSRF: 原理是什么?SameSite Cookie 属性如何防御 CSRF?
- CSP (内容安全策略) 的作用是什么?
-
浏览器缓存策略 (⭐⭐⭐⭐)
- Cache-Control (Strong Cache) vs ETag/Last-Modified (Negotiation Cache)。
- Service Worker 在缓存策略中的应用(PWA)。
✍️ 模块六:手写代码 & 算法
考察点:P6 必须具备极强的 Coding 能力,要求代码规范、考虑边界情况。
核心手写题 (高频):
- 手写 Promise.all / Promise.race / Promise.allSettled (⭐⭐⭐⭐)
- 手写防抖 (Debounce) 与节流 (Throttle) (⭐⭐⭐) - 要求:支持立即执行、取消功能。
- 手写深拷贝 (DeepClone) (⭐⭐⭐⭐) - 要求:解决循环引用(WeakMap)、处理 Symbol/Date/RegExp 类型。
- 手写发布订阅模式 (EventEmitter) (⭐⭐⭐) - 要求:on, emit, off, once。
- 手写 call / apply / bind (⭐⭐⭐⭐)
- 手写 new 操作符 / instanceof 实现 (⭐⭐⭐)
- 手写并发控制调度器 (⭐⭐⭐⭐⭐) - 题目:实现一个 Scheduler 类,限制同时运行的异步任务数量(如最多 2 个)。
- 手写数组扁平化 (flat) / 数组去重 (⭐⭐⭐)
常见算法题 (前端偏向):
- LRU 缓存算法 (⭐⭐⭐⭐) - 使用 Map + 双向链表实现。
- 树形结构与列表互转 (⭐⭐⭐⭐) - 扁平数组转 Tree,Tree 转扁平数组。
- 大数相加 (⭐⭐⭐) - 处理超过 JS Number 精度的大整数运算。
- 版本号排序 (⭐⭐⭐) - 如 ['1.45.0', '1.5', '6', '3.3.3.3.3.3']。
🏗️ 模块七:架构与软技能
考察点:系统设计能力、项目复盘能力、技术视野。
-
设计模式实战 (⭐⭐⭐⭐)
- 你在项目中用过哪些设计模式?请举例。(单例模式-Axios实例、观察者模式-事件总线、策略模式-表单验证、代理模式-Proxy)。
-
前端性能监控体系搭建 (⭐⭐⭐⭐⭐)
- 如何设计一个 SDK 自动上报错误(JS Error, Promise Reject, 资源加载失败)?
- 如何计算 FCP, LCP, CLS 等核心指标?(PerformanceObserver)。
- 如何实现白屏检测?
-
微前端架构 (Micro-Frontend) (⭐⭐⭐⭐)
- 对比 iframe, single-spa, qiankun, Module Federation 的优缺点。
- 如何解决微前端中的样式隔离和 JS 沙箱隔离问题?
-
虚拟列表 (Virtual Scroll) (⭐⭐⭐⭐)
- 面对 10 万条数据渲染,如何设计虚拟滚动方案?核心计算逻辑是什么?
-
项目复盘与难点 (必问) (⭐⭐⭐⭐⭐)
- 问题范例:“介绍一个你做过的最复杂的项目,难点在哪里?你是如何解决的?如果现在重构,你会怎么改进?”
- 提示:P6 必须能讲出“方案选型”、“性能瓶颈突破”、“工程化改造”等层面的难点,而不是简单的业务逻辑堆砌。
💡 给 P6 候选人的建议:
- 深度优先:不要背诵定义,要看源码,看规范。面试官问“是什么”,你要回答“为什么”和“怎么实现的”。
- 场景驱动:所有的技术都是为了解决业务问题。回答问题时,尽量结合实际项目场景来举例。
- 手写代码:白板编程是 P6 面试的杀手锏,务必熟练掌握上述“手写代码”模块,尤其是并发控制和深拷贝。