← 返回题库
前端核心·综合精选

前端面试精选 28 题

HTML/CSS · JavaScript · React · 工程化 · 浏览器 · 性能 · 微前端 · 手写代码 · 软技能,覆盖前端面试最高频考点。

前端HTMLCSSJavaScriptReactWebpackTypeScript浏览器Web Vitals微前端

前端面试精选 28 题

精选前端面试最高频考点:每题「一句话本质 + 完整答案 + 追问弹药」。覆盖 HTML/CSS · JavaScript · React · 工程化 · 浏览器 · 性能 · 微前端 · 手写代码 · 软技能 九大类。完整 130 题见源文档 前端题库/前端面试真题130题完整答案.md,通用考点详答见 前端题库/index.md


一、HTML & CSS(5 题)

1. 语义化的意义

  • 答案:用恰当含义的 HTML 标签(header / nav / article / section / aside / footer)构建页面,而非通篇 div/span
  • 为什么重要
    1. 对开发者友好:代码结构清晰、易维护、团队协作顺畅
    2. 对 SEO 友好:搜索引擎爬虫依赖标签判断内容与权重
    3. 对无障碍友好:屏幕阅读器根据语义标签更好地朗读

2. 标准盒模型 vs IE 盒模型

模型width 含义元素实际占宽
标准盒模型content-boxcontent 的宽度width + padding + border + margin
IE 盒模型border-boxcontent + padding + borderwidth + margin

border-box 在实际开发中更常用——让设置的宽度直接就是元素可见宽度总和,方便布局(尤其百分比宽度和内边距同时存在时)。

3. BFC(块级格式化上下文)

  • 本质:Web 页面的一块独立渲染区域,内部元素布局不影响外部元素
  • 触发条件(任一):根元素、float ≠ noneposition: absolute/fixeddisplay: inline-block/table-cell/flex/gridoverflow ≠ visible
  • 解决的三大问题
    1. 清除浮动(父元素高度塌陷)
    2. 防止外边距重叠(不同 BFC 的 margin 不重叠)
    3. 阻止元素被浮动元素覆盖(自适应两栏布局)

4. 重绘 vs 回流

  • 回流(Reflow):布局/几何信息改变(窗口大小、增删 DOM、改宽高位置)→ 重新计算元素位置和大小
  • 重绘(Repaint):外观改变(颜色、背景色、visibility)但不影响布局 → 重新绘制
  • 如何避免
    • 一次性改 classcssText避免逐条修改样式
    • 多次重排的元素先 display: none,操作完再显示
    • documentFragment 批量操作 DOM
    • 复杂动画用 position: absolute/fixed 脱离文档流
    • 避免 table 布局(小改动可能引起整个表格回流)

5. 移动端适配:rem / vw / 1px 问题

  • rem 方案:JS 动态算视口宽设 html font-size,元素用 rem 等比缩放(手淘 flexible.js)
  • vw/vh 方案vw = 视口宽的 1%,直接 width: 20vw 替代 JS
  • 1px 问题:高 DPR 屏幕 CSS 1px 被渲染成 2~3 物理像素偏粗
    • ❌ 不能直接 transform: scale(0.5) 整个元素(内容和文字一起缩)
    • ✅ 给伪元素画边框再缩放它
.hairline::after {
  content: ''; position: absolute; left: 0; top: 0;
  width: 200%; height: 200%;
  border: 1px solid #ddd;
  transform: scale(0.5);
  transform-origin: 0 0;
  pointer-events: none;
}
@media (-webkit-min-device-pixel-ratio: 3) { /* DPR=3 时 scale(0.333) */ }

二、JavaScript 核心(7 题)

6. 闭包

  • 本质:有权访问另一个函数作用域中变量的函数(典型形式:函数内部嵌套函数并 return)
  • 原理:利用 JS 词法作用域,内部函数引用外部函数的变量,即使外部函数执行完,变量对象也不销毁(因为被内部函数引用)
  • 应用场景
    1. 创建私有变量(模拟私有方法)
    2. 函数柯里化(多参数→单参数链)
    3. 循环中保存变量状态(var 的经典坑,用 IIFE 或 let 解)
  • 缺点:可能内存泄漏 → 退出函数前把不再用的局部变量置为 null

7. 原型与原型链

  • 每个函数有 prototype,指向原型对象;每个对象有 __proto__,指向创建它的构造函数的 prototype
  • 访问对象属性时找不到会沿 __proto__ 向上查,直到 Object.prototype.__proto__ === null ——这就是原型链
  • 三种继承方式对比
    • ES5 组合继承Parent.call(this) + Child.prototype = new Parent()调用两次父构造函数(缺点)
    • ES5 寄生组合继承Parent.call(this) + Child.prototype = Object.create(Parent.prototype) + Child.prototype.constructor = Child ——最理想的 ES5 继承
    • ES6 class extends:本质是寄生组合继承的语法糖

8. 事件循环(Event Loop)宏任务与微任务

⚠️ 「UI 渲染」不是宏任务——它是浏览器在「微任务清空后、下一个宏任务前」择机执行的独立步骤;同理 requestAnimationFrame 也不属于宏/微任务,挂在渲染步骤之前。这两个是最常见的错答点。

类型包含
宏任务(MacroTask)script(整体代码)、setTimeoutsetIntervalsetImmediate(Node)、I/O、MessageChannel、UI 事件回调
微任务(MicroTask)Promise.then/catch/finallyMutationObserverqueueMicrotaskprocess.nextTick(Node,优先级高于微任务

执行流程:执行一个宏任务 → 遇微任务入微队列 → 当前宏任务完清空整个微队列 → 浏览器可能进行 UI 渲染 → 取下一个宏任务 → 循环往复。

9. 深拷贝(含循环引用与边界类型)

function deepClone(obj, hash = new WeakMap()) {
  if (obj === null || typeof obj !== 'object') return obj
  if (obj instanceof Date) return new Date(obj)
  if (obj instanceof RegExp) return new RegExp(obj)
  if (hash.has(obj)) return hash.get(obj)  // 解决循环引用

  const cloneObj = new obj.constructor()
  hash.set(obj, cloneObj)

  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      cloneObj[key] = deepClone(obj[key], hash)
    }
  }
  return cloneObj
}

10. new 操作符原理

function myNew(constructor, ...args) {
  // 1. 创建空对象
  const obj = {}
  // 2. 空对象的原型指向构造函数的 prototype
  Object.setPrototypeOf(obj, constructor.prototype)
  // 3. 构造函数 this 指向新对象并执行
  const result = constructor.apply(obj, args)
  // 4. 构造函数返回对象则返回它,否则返回新对象
  return result instanceof Object ? result : obj
}

11. Promise.all 实现

function promiseAll(promises) {
  return new Promise((resolve, reject) => {
    if (!Array.isArray(promises)) return reject(new TypeError('Arguments must be an array'))
    const results = []
    let count = 0
    if (promises.length === 0) return resolve(results)

    promises.forEach((promise, index) => {
      Promise.resolve(promise).then(value => {
        results[index] = value
        count++
        if (count === promises.length) resolve(results)
      }).catch(reject)
    })
  })
}

12. 防抖(Debounce)与节流(Throttle)的核心区别

防抖(Debounce)节流(Throttle)
触发时机停止触发 N ms 后才执行每 N ms 内最多执行一次
典型场景搜索框输入、resize 结束滚动事件、mousemove、射击游戏子弹

⚠️ 节流实现要点:必须用 Date.now() 时间戳比较(leading + trailing 双触发),而不是简单的 setTimeout——后者无法保证 leading 立即触发。


三、React(2 题)

13. Virtual DOM 与 Diff 算法

  • VDOM 本质:JS 对象,是对真实 DOM 的轻量级抽象
  • 为什么快:JS 层面操作找最小变更,一次性批量更新真实 DOM,减少回流重绘
  • Diff 三原则
    1. 同级比较:不跨层级,O(n)
    2. 不同类型节点:直接删除旧子树重建
    3. 相同类型节点:递归比较属性 + 子节点
  • key 的作用:识别节点可否复用/移动/删除——**key 应稳定且唯一,不要用数组索引(增删元素时索引会变,导致性能问题或状态错乱)

14. Hooks 原理与使用约束

  • 为什么需要 Hooks:HOC / Render Props 嵌套地狱、Class 生命周期混杂无关逻辑、this 指向困扰、不利于 tree-shaking
  • useState vs setState
    • setState 合并更新(浅合并);useStateset 替换更新
    • React 18 之前:合成事件/生命周期中两者异步批处理;React 18 起自动批处理覆盖 Promise/setTimeout
  • useEffect vs useLayoutEffect
    • useEffect 浏览器绘制后异步执行(不阻塞渲染)
    • useLayoutEffect DOM 变更后、绘制前同步执行(用于读/改 DOM 并立即生效)
  • Hooks 原理:React 内部为每个组件维护链表存储 Hooks;调用顺序决定位置 → Hooks 不能在条件/循环/嵌套函数中调用

四、工程化(4 题)

15. Webpack Loader 与 Plugin 的区别

  • Loader:转换器,处理非 JS/JSON 模块(.css / .vue / 图片),把它们转为有效模块
  • Plugin:扩展器,监听 webpack 全生命周期广播的事件,通过钩子执行更广泛任务(打包优化、资源管理、环境变量注入)

16. HMR(热更新)原理

⚠️ 纠偏:早期 webpack-hot-middleware 用的是 JSONP,现代 webpack-dev-server 已改为 fetch/XHR 拉取 chunk(带 webpackHotUpdate 回调)。答 JSONP 会被认为停留在老版本。

  1. 文件监听:webpack 监听文件变化,重新编译打包,代码保存到内存
  2. 通知webpack-dev-server 通过 WebSocket 与浏览器建立长连接,通知新模块 hash
  3. 请求更新:浏览器端 HMR runtime 根据 hash 通过 fetch/XHR 向服务器拉取 hot-update.json(更新清单)+ hot-update.js(增量模块代码),执行回调完成替换
  4. 模块替换:HMR runtime 执行模块替换,通知应用代码执行回调(module.hot.accept),实现无刷新更新

17. Webpack 构建流程(七步)

  1. 初始化参数:合并配置文件与 Shell 参数
  2. 开始编译:初始化 Compiler 对象,加载插件,执行 run
  3. 确定入口:根据 entry 找所有入口文件
  4. 编译模块:从入口出发,调用 Loader 处理,再找依赖模块递归处理
  5. 完成模块编译:得到每个模块翻译后内容 + 依赖关系图
  6. 输出资源:组装成 chunk,每个 chunk 转文件加入输出列表
  7. 输出完成:确定输出路径与文件名,写入文件系统

18. TypeScript 核心:interface vs type + 工具类型

  • interface vs type
    • interface 可重复声明(声明合并),type 不能
    • interfaceextends 继承,type 用交叉类型 &
    • type 可定义联合类型 (|)、元组、基本类型别名——更灵活
    • 官方推荐优先 interface,无法满足需求时用 type
  • 工具类型实现
    type Partial<T> = { [P in keyof T]?: T[P] }
    type Pick<T, K extends keyof T> = { [P in K]: T[P] }
    type Readonly<T> = { readonly [P in keyof T]: T[P] }
    type Record<K extends keyof any, T> = { [P in K]: T }
    

五、浏览器与网络(3 题)

19. 从输入 URL 到页面显示的完整过程(八步)

  1. URL 解析:判断搜索关键字还是网址
  2. DNS 解析:浏览器缓存 → OS Hosts → 本地 DNS → 根/顶级/权威 DNS
  3. TCP 三次握手:建立可靠连接
  4. HTTP/HTTPS 请求:浏览器发请求报文;HTTPS 多 TLS 握手
  5. 服务器处理并返回响应:状态码 + 响应头 + 响应体
  6. 浏览器解析响应:判断重定向等;HTML 开始解析渲染
  7. TCP 四次挥手(短连接);HTTP/1.1+ 默认 Connection: keep-alive 长连接
  8. 浏览器渲染:HTML → DOM 树、CSS → CSSOM 树 → Render 树 → Layout → Paint → Composite

20. 浏览器缓存机制(强缓存 + 协商缓存)

  • 强缓存:直接从本地缓存读,不与服务器通信
    • Expires(HTTP/1.0,绝对时间,受本地时间影响)
    • Cache-Control: max-age=3600(HTTP/1.1,相对时间,优先级更高
  • 协商缓存:发请求让服务器判断缓存是否可用,可用返回 304 用本地缓存
    • Last-Modified + If-Modified-Since(秒级精度)
    • ETag + If-None-Match(基于内容指纹,比 Last-Modified 更精确

21. XSS 与 CSRF

  • XSS(跨站脚本):恶意脚本注入网页,其他用户浏览时执行
    • 防御:输入过滤 + 输出转义(HTML 实体编码)、CSP、CookieHttpOnly
  • CSRF(跨站请求伪造):诱导用户访问恶意网站,利用其登录状态发起恶意请求
    • 防御:Token 验证、验证 Referer、敏感操作二次验证(验证码)

六、性能(1 题)

22. Core Web Vitals(核心 Web 指标)

指标含义阈值
LCP(Largest Contentful Paint)最大内容绘制(加载性能)≤ 2.5s
INP(Interaction to Next Paint)交互到下一次绘制(已 2024-03-12 取代 FID≤ 200ms(第 75 百分位)
CLS(Cumulative Layout Shift)累积布局偏移(视觉稳定性)≤ 0.1
FCP / TTI / TBT辅助指标

RUM(Real User Monitoring):用 Performance API 收集真实用户数据上报到监控平台(Sentry/自研);熟练使用 Chrome DevTools 的 Performance / Lighthouse / Network 面板进行瓶颈分析。


七、微前端(1 题)

23. 微前端核心价值、主流方案与核心问题

  • 核心价值
    • 技术栈无关:不同团队用不同框架
    • 独立开发部署:降低耦合、提升迭代速度
    • 增量升级:老项目逐步重构而非重写
  • 主流方案
方案隔离体验改造成本适用
iframe最强异构老系统嵌入(体验扣分)
qiankun(single-spa + HTML Entry)好(JS 沙箱 + 样式隔离)存量渐进迁移首选
Module Federation中高新建 / 同技术栈 / 运行时共享
wujie(无界)很强强隔离可接受
Web Components强(Shadow DOM)组件级复用(不是发布权工具)
  • 核心问题:样式隔离(CSS Module / Shadow DOM / BEM)、JS 沙箱(Proxy 沙箱 / 快照沙箱)、应用通信(全局事件总线 / URL 传参 / 共享状态)

完整微前端工程实战(含 15 条坑、迁移六阶段、组件库 12 坑)见 微前端迁移与自研组件库实战智慧中台项目


八、手写代码精选(4 题)

24. 手写 Event Bus(发布-订阅)

class EventBus {
  constructor() { this.events = {} }
  on(event, listener) {
    (this.events[event] || (this.events[event] = [])).push(listener)
  }
  emit(event, ...args) {
    (this.events[event] || []).forEach(listener => listener(...args))
  }
  off(event, listener) {
    if (!this.events[event]) return
    this.events[event] = this.events[event].filter(l => l !== listener)
  }
  once(event, listener) {
    const wrapper = (...args) => {
      listener(...args)
      this.off(event, wrapper)
    }
    this.on(event, wrapper)
  }
}

25. 手写 compose(函数组合)

const compose = (...funcs) => {
  if (funcs.length === 0) return arg => arg
  if (funcs.length === 1) return funcs[0]
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

26. 手写 Redux 的 createStore

function createStore(reducer, preloadedState, enhancer) {
  if (enhancer) return enhancer(createStore)(reducer, preloadedState)
  let state = preloadedState
  let listeners = []
  const getState = () => state
  const dispatch = (action) => {
    state = reducer(state, action)
    listeners.forEach(listener => listener())
    return action
  }
  const subscribe = (listener) => {
    listeners.push(listener)
    return () => { listeners = listeners.filter(l => l !== listener) }
  }
  dispatch({ type: '@@redux/INIT' })
  return { getState, dispatch, subscribe }
}

27. Promise 手写核心(链式调用)

  • then 链式调用:每次返回新的 Promise,状态由上个 then 的返回值决定
    • 返回普通值:直接 resolve
    • 返回 Promise:等待其完成
    • 抛出错误:直接 reject
  • 完整实现涉及:状态机(pending/fulfilled/rejected)、异步任务(process.nextTick/微任务)、值穿透(then 的参数不是函数时忽略)

九、软技能(1 题)

28. STAR 法则回答「技术难题」

  • S(情境):项目背景、时间压力、团队规模
  • T(任务):你需要解决的具体技术问题(用一句话说清)
  • A(行动):调研方案 → 设计 → 编码 → 测试 → 复盘(讲你做了什么、为什么这么做,不要只讲结果)
  • R(结果):用数据说话——性能提升百分比、Bug 数下降、团队采纳度

关键点

  • 不要编造业务增长数字(面试官会追问口径)——研发效能数据最可信(自己的流水线出来的)
  • 必须主动补「代价/边界」——最容易拉开档次的地方;只会吹收益的人一看就没真扛过

附:通用速记卡

问题一句话回答
性能优化第一步是什么?先定预算再优化——没目标就优化叫瞎忙;预算必须能进 CI 才算可信
React Hooks 为什么不能在条件中调用?React 内部按调用顺序维护 Hooks 链表,条件调用会破坏顺序对应关系
微前端解决了什么问题?多团队独立发布权(组织协作问题),不是性能问题
Promise.all 失败时怎么处理?任意一个 reject 即整体 reject,且不等待其他进行中的 Promise
强缓存 vs 协商缓存选谁?内容稳定用强缓存(Cache-Control);常变动用协商缓存(ETag 更精确)

完整 130 题(带 12 张图解)见源文档 前端题库/前端面试真题130题完整答案.md;通用考点详答见 前端题库/index.md;AI/Agent 面试真题见 AI 面试精选;系统设计与场景题见 系统设计精选