前端面试全题库(2026 终极版)

12 阅读19分钟

前端面试全题库(2026 终极版)

初级 / 中级 / 高级分级 + 逐题超详细解析


一、JavaScript 核心

🔰 初级(1–3 年)

1. var / let / const 的区别?

详细解析:

  1. 作用域不同

    • var函数级作用域,只受函数限制,不受 {} 限制。
    • let / const块级作用域if / for / while{} 内有效。
  2. 变量提升

    • var:存在变量提升,可以在声明前使用(值为 undefined)。
    • let / const:存在提升,但进入暂时性死区 TDZ,声明前使用会报错。
  3. 重复声明

    • var:允许重复声明,后面覆盖前面。
    • let / const:同一作用域不允许重复声明。
  4. 赋值与修改

    • var / let:可以先声明后赋值,也可重新赋值。
    • const声明时必须赋值,赋值后不能修改内存地址,但引用类型内部可修改。

最佳实践: 默认使用 const,需要变的用 let,尽量不用 var


2. JS 数据类型有哪些?存储区别?

详细解析:

7 种基本类型(值类型): StringNumberBooleanUndefinedNullSymbolBigInt

1 种引用类型: Object(包含 ArrayFunctionDateRegExp 等)

存储区别:

  • 基本类型:存在栈内存,值直接保存,赋值是深拷贝。
  • 引用类型:地址存在栈,真实内容存在堆内存,赋值是传地址。

判断方法:

  • typeof:判断基本类型(除 nullobject
  • instanceof:判断引用类型
  • Object.prototype.toString.call(value):最准确

3. == 和 === 的区别?

详细解析:

  • === 严格相等:先比较类型,类型不同直接 false;类型相同再比较值。

  • == 宽松相等:会先进行隐式类型转换,再比较值。转换规则:

    1. 字符串与数字 → 字符串转数字
    2. 布尔值 → 转数字
    3. null == undefinedtrue
    4. 对象与基本类型 → 对象转原始类型

注意:

  • NaN === NaNfalse,判断用 Number.isNaN()
  • Object.is(NaN, NaN)true

最佳实践: 项目中一律使用 ===


4. 数组常用方法,哪些改变原数组?

详细解析:

不改变原数组(常用):

  • map:遍历返回新数组
  • filter:过滤返回新数组
  • reduce:累计计算
  • concat:拼接
  • slice:截取
  • forEach:仅遍历

改变原数组:

  • push / pop
  • shift / unshift
  • splice
  • sort
  • reverse

📌 中级(3–5 年)

5. 原型与原型链详解?

详细解析:

1)原型 prototype:每个函数都有 prototype 显式原型,是一个对象,存放共享属性和方法。

2)__proto__:每个对象都有 __proto__ 隐式原型,指向其构造函数的 prototype

3)原型链:对象通过 __proto__ 向上查找属性 / 方法,直到 null,这条链叫原型链。

4)作用:

  • 实现继承
  • 方法共享,节省内存
  • 实现 JS 面向对象

经典关系:

对象.__proto__ === 构造函数.prototype
构造函数.prototype.constructor === 构造函数

6. this 指向完整规则?

详细解析:

1)默认绑定:全局 / 独立函数调用,非严格模式 → window;严格模式 → undefined

2)隐式绑定:对象方法调用 → 谁调用指向谁

3)显式绑定call / apply / bind → 指向第一个参数

4)new 绑定new Fn() → 指向新创建的实例对象

5)箭头函数没有自己的 this,继承外层作用域的 this,且无法被修改。

优先级: new > 显式绑定 > 隐式绑定 > 默认绑定


7. 闭包是什么?应用与缺点?

详细解析:

定义: 函数嵌套函数,内部函数引用了外部函数的变量 / 参数,就形成闭包。

作用:

  1. 私有化变量,避免全局污染
  2. 形成模块化
  3. 柯里化、防抖节流保存状态
  4. 工厂函数、迭代器

缺点: 变量常驻内存,使用不当会造成内存泄漏

解决:

  • 不用时手动解除引用 fn = null
  • 避免在循环中创建闭包

8. 浏览器事件循环完整机制?

详细解析:

执行顺序:

  1. 执行全局同步代码
  2. 执行微任务队列(清空所有)
  3. 执行渲染(若需要)
  4. 一个宏任务执行
  5. 回到步骤 2,循环

微任务(优先级高): Promise.then / catch / finallyqueueMicrotaskasync / awaitMutationObserver

宏任务: scriptsetTimeoutsetInterval、I/O、UI 渲染、requestAnimationFrame

经典面试题口诀: 同步先跑,微任务全清,再跑一个宏任务。


9. 浅拷贝与深拷贝?实现方式?

详细解析:

浅拷贝: 只复制第一层,深层引用类型共享地址。实现:

  • Object.assign
  • 展开运算符 {...obj}
  • Array.prototype.slice / concat

深拷贝: 递归复制所有层级,完全独立。实现:

  1. JSON.parse(JSON.stringify(obj)):缺点是不能复制函数、undefined、Symbol、循环引用
  2. 手写递归深拷贝(处理循环引用、函数、Date 等)

🚀 高级(5 年 +/ 架构)

10. Promise A+ 规范与原理?

详细解析:

三大状态:

  • pending → 初始
  • fulfilled → 成功
  • rejected → 失败

状态一旦改变,不可逆

核心方法:

  • then:返回新 Promise,支持链式
  • catch:捕获异常
  • finally:无论如何都执行

静态方法:

  • Promise.all:全部成功才成功,一个失败即失败
  • Promise.race:谁先完成就用谁
  • Promise.allSettled:全部返回结果(不管成败)
  • Promise.resolve / reject

手写要点:

  • 状态管理
  • 发布订阅(存成功 / 失败回调)
  • 微任务模拟
  • 链式调用返回新 Promise

11. async / await 原理?

详细解析:

本质: async / awaitGenerator + 自动执行器 的语法糖。

执行流程:

  1. async 函数返回一个 Promise
  2. await 后面通常是 Promise
  3. 等待 Promise resolve 后继续执行
  4. 异常需要用 try / catch 捕获

优点:

  • 同步写法,解决回调地狱
  • 代码可读性极高

12. 手写防抖(详细带注释)

/**
 * 防抖:频繁触发时,只在最后一次触发后 delay 毫秒执行
 * @param {Function} fn 执行函数
 * @param {number} delay 延迟毫秒
 * @returns {Function}
 */
function debounce(fn, delay) {
  let timer = null;
  return function(...args) {
    // 清除之前的定时器
    if (timer) clearTimeout(timer);
    // 重新计时
    timer = setTimeout(() => {
      fn.apply(this, args);
      timer = null;
    }, delay);
  };
}

场景: 搜索输入、窗口 resize、表单验证


13. 手写节流(详细带注释)

/**
 * 节流:固定时间内只执行一次
 * @param {Function} fn
 * @param {number} interval
 * @returns {Function}
 */
function throttle(fn, interval) {
  let lastTime = 0;
  return function(...args) {
    const now = Date.now();
    if (now - lastTime >= interval) {
      lastTime = now;
      fn.apply(this, args);
    }
  };
}

场景: 滚动加载、高频点击、游戏射击


14. V8 垃圾回收机制?

详细解析:

分代回收:

  • 新生代:存活时间短,使用 Scavenge 复制算法
  • 老生代:存活时间长,使用 Mark-Sweep(标记清除)+ Mark-Compact(标记整理)

垃圾回收流程:

  1. 根节点遍历(全局、调用栈)
  2. 标记可达对象
  3. 清除未标记对象
  4. 整理内存(减少碎片)

常见内存泄漏:

  • 意外全局变量
  • 闭包滥用
  • 未清理的定时器 / 事件监听
  • DOM 引用未释放

二、CSS 模块

🔰 初级

1. 标准盒模型与怪异盒模型?

详细解析:

标准盒模型(content-box)

box-sizing: content-box
width = content 宽度

怪异盒模型(border-box)

box-sizing: border-box
width = content + padding + border

项目中通用:

* {
  box-sizing: border-box;
}

2. CSS 选择器优先级?

详细解析:

优先级权重公式(从高到低):

!important > 行内样式 > ID > 类/属性/伪类 > 元素/伪元素

计算规则:

  • 行内:1000
  • ID:100
  • 类 / 属性 / 伪类:10
  • 元素 / 伪元素:1

注意:

  • 权重相同,后写的覆盖先写的
  • 继承样式优先级最低
  • !important 尽量少用,难以覆盖

3. 水平垂直居中 3 种方法?

详细解析:

1)flex(最常用)

.parent {
  display: flex;
  justify-content: center;
  align-items: center;
}

2)绝对定位 + transform

.parent { position: relative; }
.child {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

3)grid

.parent {
  display: grid;
  place-items: center;
}

📌 中级

4. BFC 原理、触发条件、应用?

详细解析:

BFC:块级格式化上下文,独立渲染区域,内部布局不影响外部。

触发条件(任一):

  • float 不为 none
  • position: absolute / fixed
  • overflow 不为 visible
  • display: inline-block / flex / grid / table-cell

应用:

  1. 清除浮动,解决高度塌陷
  2. 解决垂直方向 margin 重叠
  3. 两栏自适应布局

5. flex 核心属性?

详细解析:

容器属性:

  • flex-direction:主轴方向
  • justify-content:主轴对齐
  • align-items:交叉轴对齐
  • flex-wrap:是否换行
  • align-content:多行对齐

项目属性:

  • flex-grow:放大比例
  • flex-shrink:缩小比例
  • flex-basis:基础宽度
  • flex:缩写 flex: 1 最常用
  • align-self:自身单独对齐

6. 重排 reflow 与重绘 repaint?

详细解析:

重排(布局): 元素几何尺寸、位置变化 → 重新计算布局 → 性能消耗大

重绘(样式): 颜色、背景等变化,不影响布局 → 消耗较小

触发重排:

  • 窗口 resize
  • 增删 DOM
  • 修改宽高、边距、定位
  • 获取 offsetTop / scrollLeft 等(强制同步布局)

优化:

  • 使用 transform / opacity(合成层,不触发重排)
  • 批量修改 DOM(先隐藏再修改)
  • 读写分离
  • 使用文档碎片 DocumentFragment

🚀 高级

7. 层叠上下文与 z-index?

详细解析:

层叠上下文: 相当于一个 3D 栈,控制元素垂直堆叠顺序。

创建条件:

  • position 不为 static 且 z-index 不为 auto
  • opacity < 1
  • transform / filter 不为 none
  • flex 子项且 z-index 不为 auto

层叠等级(从下到上):

  1. 背景与边框
  2. 负 z-index
  3. 块级 / 行内 / 浮动
  4. z-index: 0 / auto
  5. 正 z-index

注意: 子元素 z-index 只在父层叠上下文内比较。


8. CSS 模块化方案对比?

详细解析:

1)CSS Modules

  • 编译生成唯一哈希类名
  • 无全局污染
  • 适合 React 项目

2)Scoped CSS

  • Vue 默认
  • 原理:添加 data-v-hash 属性选择器
  • 子组件根元素受父 scoped 影响

3)CSS-in-JS

  • styled-components / emotion
  • 动态性极强
  • 缺点:运行时开销、调试稍难

4)BEM 命名

  • 手动规范命名
  • 无工具依赖

三、Vue 模块

🔰 初级

1. Vue2 生命周期?

详细解析:

创建阶段:

  • beforeCreate:数据观测未开始
  • created:能访问 data/methods,常用于异步请求

挂载阶段:

  • beforeMount:模板编译完成,未挂载
  • mounted:DOM 已生成,可操作 DOM

更新阶段:

  • beforeUpdate
  • updated

销毁阶段:

  • beforeDestroy:清除定时器、事件监听
  • destroyed

2. v-if 与 v-show 区别?

详细解析:

v-if:

  • 真正的销毁 / 重建
  • 切换开销大
  • 初始不渲染
  • 可配合 template
  • 适合不频繁切换

v-show:

  • 只是 display: none
  • 初始渲染开销大
  • 频繁切换优先用 v-show

3. Vue 组件通信 7 种?

详细解析:

  1. 父 → 子:props
  2. 子 → 父:$emit
  3. 父子链parent/parent / children(不推荐)
  4. 跨级:provide / inject
  5. 兄弟:eventBus
  6. 全局:Vuex / Pinia
  7. 边界attrs/attrs / listeners

📌 中级

4. Vue2 响应式原理?

详细解析:

核心: Object.defineProperty

遍历对象属性,劫持 get(收集依赖)、set(触发更新)。

缺点:

  1. 无法监听对象新增 / 删除属性
  2. 无法监听数组下标修改length 修改

解决方案:

  • Vue.set(target, key, value)
  • Vue.delete
  • 重写数组 7 个方法:push / pop / shift / unshift / splice / sort / reverse

5. Vue3 响应式原理?

详细解析:

核心: Proxy + Reflect

  • 代理整个对象,而非单个属性
  • 支持监听新增 / 删除属性
  • 支持监听数组下标、length
  • 支持嵌套对象懒监听

优势:

  • 性能更好
  • 更完整
  • 支持 Map / Set / WeakMap 等

6. v-for 中 key 的作用?为什么不能用 index?

详细解析:

作用: 给 Diff 算法提供唯一标识,让 Vue 精准复用节点,减少 DOM 操作。

为什么不要用 index:

  • 数组顺序变化时,index 会变
  • 导致节点错误复用、渲染错乱
  • 列表带状态(复选框、输入框)时必出问题

最佳实践: 使用后端返回的唯一 id。


🚀 高级

7. Vue Diff 算法核心逻辑?

详细解析:

原则:

  • 只做同层比较,不跨级
  • 深度优先

双端比较流程:

  1. 旧头 ↔ 新头
  2. 旧尾 ↔ 新尾
  3. 旧头 ↔ 新尾
  4. 旧尾 ↔ 新头
  5. 建立映射表,快速查找

优化:

  • 尽量复用 DOM
  • 移动而非删除重建
  • key 是关键

8. Composition API 优势?

详细解析:

  1. 逻辑复用更优雅:替代 mixin,无命名冲突、来源清晰
  2. 代码组织更聚合:按功能组织,而非按 options 分片
  3. TS 类型推导友好:无复杂的 this 类型问题
  4. 更好的 tree shaking:按需引入,体积更小
  5. 无生命周期混乱,逻辑可独立提取

9. Vue 项目性能优化?

详细解析:

编码层面:

  • v-show 替换频繁切换 v-if
  • v-for 必加 key,避免 index
  • 计算属性缓存复杂计算
  • 防抖节流处理高频事件

打包层面:

  • 路由懒加载
  • 异步组件
  • 图片懒加载
  • 开启 gzip
  • splitChunks 拆分 vendor

运行层面:

  • 虚拟列表处理长列表
  • 销毁时清除定时器 / 监听
  • 使用 keep-alive 缓存页面

四、React 模块

🔰 初级

1. 类组件 vs 函数组件?

详细解析:

类组件:

  • 有 state、生命周期、this
  • 代码量大
  • 逻辑复用麻烦(HOC、render-props)

函数组件:

  • 简洁、无 this 困扰
  • Hooks 后可完全替代类组件
  • 性能更好,更容易被优化

趋势: 全面拥抱函数组件 + Hooks。


2. state 与 props 区别?

详细解析:

props:

  • 父组件传入
  • 只读,不可修改
  • 用于父子通信

state:

  • 组件内部私有
  • 可修改,setState 异步更新
  • 修改后触发重渲染

原则: 单向数据流:父 → 子


3. React 合成事件?

详细解析:

React 不使用原生事件,而是自己封装合成事件 SyntheticEvent

优势:

  1. 浏览器兼容性抹平
  2. 事件委托到 document,减少内存开销
  3. 批量更新,性能优化
  4. 事件对象可复用(池化)

注意:

  • 异步中要取事件值需 event.persist()
  • 原生事件与合成事件可共存但要注意执行顺序

📌 中级

4. useEffect 完整机制?

详细解析:

useEffect(() => {
  // 执行副作用
  return () => {
    // 清除副作用(下一次执行前 or 卸载)
  }
}, [依赖])

依赖规则:

  • 无依赖数组:每次渲染都执行
  • 空数组 []:仅挂载、卸载执行
  • 有依赖:依赖变化执行

常见用途:

  • 数据请求
  • 事件监听
  • 订阅
  • DOM 操作

5. Hooks 规则?

详细解析:

  1. 只在顶层调用:不能在循环、条件、嵌套函数中调用
  2. 只在 React 函数组件 / 自定义 Hook 中调用
  3. 依赖数组必须真实:必须包含所有外部变量

违反规则会导致状态混乱、闭包陷阱。


6. React.memo / useMemo / useCallback?

详细解析:

React.memo:

  • 缓存组件
  • 浅比较 props
  • 避免子组件不必要重渲染

useMemo:

  • 缓存计算结果
  • 避免重复计算
const value = useMemo(() => compute(a, b), [a, b])

useCallback:

  • 缓存函数引用
  • 传给子组件时避免重渲染
const fn = useCallback(() => {}, [])

🚀 高级

7. Fiber 架构解决了什么?

详细解析:

旧架构问题: 同步递归渲染,一旦开始无法中断,大量计算会阻塞主线程 → 页面卡顿。

Fiber 解决:

  1. 可中断、可恢复、可优先级调度
  2. 把渲染拆分成小 Fiber 单元
  3. 基于链表遍历(child / sibling / return)
  4. 支持时间切片,给浏览器渲染留时间
  5. 支持并发特性:Suspense、Transitions

8. React vs Vue 核心差异?

详细解析:

响应式:

  • Vue:基于 Proxy 自动收集依赖,精确更新
  • React:基于状态不可变,标记更新,全量对比调和

编写方式:

  • Vue:模板 + 选项式 / 组合式
  • React:JSX 全 JS

更新机制:

  • Vue:push 式更新,精准
  • React:pull 式,需要手动优化(memo 等)

生态定位:

  • Vue:渐进式,易用优先
  • React:灵活强大,工程化优先

五、TypeScript 模块

🔰 初级

1. TS 相比 JS 的优势?

详细解析:

  1. 静态类型检查:编译时发现错误,减少线上 Bug
  2. 智能提示与重构:IDE 支持极强,大型项目必备
  3. 可读性与可维护性:类型即文档
  4. 面向对象更完善:接口、泛型、装饰器
  5. 兼容 ES 最新特性,编译可指定目标版本

2. TS 基础类型?

详细解析:

原始:stringnumberbooleanundefinednull

特殊:anyunknownvoidnever

引用:objectarraytupleenum

any vs unknown:

  • any:关闭类型检查,不安全
  • unknown:安全,必须类型判断后使用

📌 中级

3. interface vs type 区别?

详细解析:

interface:

  • 描述对象 / 类
  • 支持 extends 继承
  • 支持自动合并
  • 适合公共 API 定义

type:

  • 更强大,支持联合、交叉、元组、工具类型
  • 不可重复定义
  • 适合复杂类型组合

通用建议:

  • 定义对象 / 类用 interface
  • 复杂类型、工具类型用 type

4. 泛型作用与示例?

详细解析:

作用: 不预先指定类型,在使用时动态指定,实现类型安全 + 复用

function identity<T>(arg: T): T {
  return arg;
}

const str = identity<string>('abc');
const num = identity(123); // 自动推导

常见:Promise<T>Array<T>useState<T>


🚀 高级

5. 内置工具类型原理?

详细解析:

Partial<T>        // 所有属性可选
Required<T>       // 所有属性必选
Readonly<T>       // 只读
Pick<T, K>        // 挑选部分属性
Omit<T, K>        // 排除部分属性
Exclude<T, U>     // 从 T 排除 U
Extract<T, U>     // 提取 T 与 U 交集
ReturnType<T>     // 获取函数返回值类型

基于映射类型条件类型实现。


6. 类型守卫?

详细解析:

用于缩小类型范围,让 TS 精准判断。

1)typeof

if (typeof val === 'string') {}

2)instanceof

if (val instanceof Date) {}

3)in

if ('name' in obj) {}

4)自定义类型谓词

function isUser(user: any): user is User {
  return user && typeof user.id === 'number';
}

六、工程化

🔰 初级

1. npm / yarn / pnpm 区别?

详细解析:

npm:

  • 官方
  • 早期依赖地狱、嵌套严重
  • npm5 后 package-lock.json

yarn:

  • 并行安装、缓存、lock 稳定

pnpm:

  • 基于硬链接 + 符号链接
  • 速度极快、极省空间
  • 严格依赖,避免幽灵依赖

趋势: 现代项目优先 pnpm。


2. Loader vs Plugin?

详细解析:

Loader:

  • 模块转换器
  • 处理非 JS 文件:css、ts、图片、vue
  • 执行在 module 解析阶段

Plugin:

  • 扩展 webpack 能力
  • 基于事件钩子
  • 打包优化、资源管理、注入变量

📌 中级

3. Webpack 构建流程?

详细解析:

  1. 初始化:读取配置,实例化 Compiler
  2. 开始编译runmake
  3. 构建依赖图:从 entry 开始,递归依赖,使用 loader 转译
  4. 生成 chunk:根据依赖关系分组
  5. 输出 bundle:写入文件系统

核心钩子:entryOptioncompilemakesealemit


4. Vite 为什么快?

详细解析:

开发环境:

  • 基于原生 ES Module(ESM)
  • 不打包,浏览器按需请求
  • esbuild 预构建依赖,极快

生产环境:

  • 使用 Rollup 打包
  • 输出产物更优

优势:

  • 冷启动极快
  • 热更新秒级
  • 配置简单

🚀 高级

5. Tree Shaking 原理与条件?

详细解析:

原理: 基于 ES Module 静态结构分析,移除未引用代码。

条件:

  1. 必须是 ESM(import / export)
  2. production 模式
  3. 无副作用(sideEffects: false
  4. 代码不被动态引用

6. 微前端核心思想?

详细解析:

目标:

  • 多技术栈共存
  • 独立开发、独立部署
  • 运行时隔离

核心能力:

  1. 路由分发
  2. JS 沙箱(快照 / Proxy)
  3. 样式隔离(CSS Modules / Shadow DOM)
  4. 应用间通信

代表: qiankun、single-spa、Module Federation


七、网络

🔰 初级

1. GET vs POST?

详细解析:

语义:

  • GET:获取资源,安全、幂等
  • POST:提交资源,非幂等

参数:

  • GET:URL 中,长度受限
  • POST:请求体,容量大

缓存:

  • GET 可被缓存
  • POST 默认不缓存

安全: 都不安全,都需 HTTPS。


2. HTTP 状态码?

详细解析:

1xx:信息 2xx:成功(200) 3xx:重定向(301/302/304) 4xx:客户端错(400/401/403/404) 5xx:服务端错(500/502/504)


📌 中级

3. 强缓存 vs 协商缓存?

详细解析:

强缓存: 不发请求,直接读缓存

  • Cache-Control: max-age=xxx
  • Expires

协商缓存: 发请求,服务端验证

  • Last-Modified / If-Modified-Since
  • ETag / If-None-Match

返回 304 则用缓存


4. 跨域原因与解决方案?

详细解析:

原因: 浏览器同源策略(协议、域名、端口一致),防止 CSRF/XSS。

解决方案:

  1. CORS(服务端配置)
  2. JSONP(仅 GET)
  3. 代理服务器(webpack devServer、nginx)
  4. postMessage
  5. WebSocket

🚀 高级

5. HTTP/1.1 / HTTP/2 / HTTP/3?

详细解析:

HTTP/1.1:

  • 长连接
  • 队头阻塞
  • 多个 TCP 连接

HTTP/2:

  • 多路复用(单连接多流)
  • 头部压缩 HPACK
  • 服务器推送

HTTP/3:

  • 基于 QUIC(UDP)
  • 彻底解决队头阻塞
  • 0-RTT 握手

6. HTTPS 流程?

详细解析:

  1. 客户端发起请求
  2. 服务端返回证书
  3. 客户端验证证书合法性
  4. 客户端生成随机预主密钥
  5. 用公钥加密发给服务端
  6. 双方计算出会话密钥
  7. 后续通信对称加密

八、安全

🔰 初级

1. XSS 攻击?

详细解析:

跨站脚本攻击,注入恶意脚本,窃取 Cookie、伪造请求、劫持账号。

分类:

  • 存储型(存入数据库)
  • 反射型(URL 参数)
  • DOM 型(前端直接渲染)

2. CSRF 攻击?

详细解析:

跨站请求伪造,利用用户登录态,在第三方网站发起请求,执行未授权操作。


📌 中级

3. XSS 防御?

详细解析:

  1. 输入过滤
  2. 输出转义(< → <)
  3. CSP 内容安全策略
  4. HttpOnly Cookie
  5. SameSite Cookie

4. CSRF 防御?

详细解析:

  1. CSRF Token
  2. SameSite=Strict/Lax
  3. 验证 Referer / Origin
  4. 敏感操作二次验证

🚀 高级

5. CSP 工作原理?

详细解析:

通过 HTTP 头或 meta 标签,限制资源加载来源:

  • 限制脚本、样式、图片、字体
  • 禁止内联脚本
  • 禁止 eval

大幅降低 XSS 危害。


九、算法与数据结构

🔰 初级

1. 数组去重?

详细解析:

// ES6
[...new Set(arr)]

// 遍历
function unique(arr) {
  const res = [];
  const map = {};
  for(let v of arr) {
    if(!map[v]) {
      map[v] = true;
      res.push(v);
    }
  }
  return res;
}

2. 冒泡排序?

function bubbleSort(arr) {
  let len = arr.length;
  for(let i = 0; i < len - 1; i++) {
    for(let j = 0; j < len - i - 1; j++) {
      if(arr[j] > arr[j + 1]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
      }
    }
  }
  return arr;
}

复杂度 O(n²)


📌 中级

3. 有效的括号?

function isValid(s) {
  const stack = [];
  const map = { ')': '(', '}': '{', ']': '[' };
  for(let c of s) {
    if(!map[c]) stack.push(c);
    else {
      if(stack.pop() !== map[c]) return false;
    }
  }
  return stack.length === 0;
}

4. 两数之和?

function twoSum(nums, target) {
  const map = new Map();
  for(let i = 0; i < nums.length; i++) {
    const diff = target - nums[i];
    if(map.has(diff)) {
      return [map.get(diff), i];
    }
    map.set(nums[i], i);
  }
  return [];
}

O(n)


🚀 高级

5. 快速排序?

function quickSort(arr) {
  if(arr.length <= 1) return arr;
  const pivot = arr[0];
  const left = [];
  const right = [];
  for(let i = 1; i < arr.length; i++) {
    if(arr[i] < pivot) left.push(arr[i]);
    else right.push(arr[i]);
  }
  return [...quickSort(left), pivot, ...quickSort(right)];
}

平均 O(nlogn)


6. 反转链表?

function reverseList(head) {
  let prev = null;
  let cur = head;
  while(cur) {
    const next = cur.next;
    cur.next = prev;
    prev = cur;
    cur = next;
  }
  return prev;
}