本文围绕 JavaScript 底层原理、Vue、Zustand 状态管理、性能优化等方向进行系统性总结,旨在打造一套具备实战深度与理论广度的前端面试知识体系。
✅ JavaScript 底层知识体系
原型与原型链
JavaScript 是基于原型链继承的语言。每个对象都有一个内部属性 [[Prototype]]
,可通过 __proto__
访问,指向其构造函数的 prototype
对象。
- 实例 →
__proto__
→ 构造函数的prototype
→ Object.prototype → null,构成一条查找路径。 - 函数的
prototype
用于构造实例的共享属性,不等同于实例的__proto__
。 - 判断某属性/方法是否存在于原型链上:
obj.hasOwnProperty(key)
→ false,才是原型链上的。
作用域与作用域链
JavaScript 使用词法作用域,即作用域在函数定义时就已确定。
- 当前作用域访问变量时,会沿着作用域链向外查找,直到全局作用域或找到为止。
- 作用域链本质是多个执行上下文对象的链式连接。
编译与执行阶段(执行上下文)
JavaScript 引擎的运行可分为两个阶段:
-
编译阶段:
- 创建执行上下文(包括变量环境、词法环境)。
- 进行变量和函数声明的"预处理"(即变量提升、函数提升)。
-
执行阶段:
- 逐行执行代码。
- 依赖作用域链、上下文绑定、调用栈等机制运行。
箭头函数 vs 普通函数
区别项 | 普通函数 | 箭头函数(Arrow Function) |
---|---|---|
this 绑定 | 动态,取决于调用方式 | 静态,绑定定义时的 this |
可被 new | 可以 | 不可以,没有 prototype |
arguments | 有自己的 arguments 对象 | 没有,继承自上层函数 |
使用场景 | 通用,适合构造函数 | 回调、事件处理器、函数式操作更适合 |
变量提升原理
变量和函数在执行前会被"提前声明":
ini
console.log(a); // undefined
var a = 10;
原因在于 JS 引擎在编译阶段会分离变量声明和赋值。let/const
虽然也会"被处理",但处于"暂时性死区"(TDZ),使用前无法访问。
⚙️ 性能优化策略与页面生命周期
优化点不仅限于渲染性能,更包括资源利用、状态更新、网络请求等多方面。
状态更新性能优化
状态更新引起组件重新渲染,Zustand 等轻量状态库通过选择性订阅、浅比较和不可变更新机制,避免不必要的 re-render:
ini
const { bears, fishes } = useStore(
state => ({ bears: state.bears, fishes: state.fishes }),
shallow
);
- 结合
useMemo
、useCallback
等 React Hooks 降低计算负担。 - 使用
combine
拆分状态,配合 selector 精准订阅。
页面渲染与加载优化
- 懒加载 + 动态 import(
React.lazy
+Suspense
) - 虚拟列表(如
react-window
)用于大数据渲染 requestAnimationFrame
驱动动画渲染,防止阻塞主线程- 使用 Web Worker 将计算密集型任务放入独立线程
事件机制优化
- 事件委托:利用冒泡机制,减少 DOM 绑定数量
focus/blur
无法冒泡,需使用focusin/focusout
替代- 避免嵌套冒泡引发重复处理,及时
stopPropagation()
🔧 Zustand 状态管理机制与性能体系
Zustand 是一个无 Provider、轻量、强性能的 React 状态库,天然适配中大型项目中的模块化与性能需求。
状态一致性保证
- 不可变性原则:更新总是返回新状态(可借助 immer 中间件简化)
- 细粒度订阅机制:组件只监听所需状态
- 中间件机制:支持日志、持久化、异步、状态组合等功能
javascript
import { create } from "zustand";
import { persist } from "zustand/middleware";
const useStore = create(persist(
(set) => ({
count: 0,
increase: () => set((state) => ({ count: state.count + 1 }))
}),
{
name: "count-storage",
getStorage: () => localStorage
}
));
与 Immer 的结合(不可变性 + 直观语法)
ini
import { produce } from "immer";
const cart = produce(originalCart, draft => {
draft.items[0].quantity = 3;
});
状态持久化
通过 persist
中间件可将状态自动写入 localStorage
或自定义存储机制,无需依赖 Provider 即可使用全局状态。
🧠 深度 JS 底层机制与工程知识
堆与栈
- 栈:存放原始类型、函数调用栈等,访问快,空间小。
- 堆:存储引用类型对象,GC 扫描维护,访问慢,空间大。
DOM 操作与生命周期控制
DOM 操作 API:
- 插入:
appendChild
,insertBefore
- 移除:
remove
,removeChild
- 修改:
setAttribute
,textContent
,innerHTML
检测 DOM 完成:
- 使用
DOMContentLoaded
、MutationObserver
- 脚本写在
<body>
最底部,保证 DOM 先加载
事件冒泡与事件捕获
事件处理机制包括三个阶段:
- 捕获阶段
- 目标阶段
- 冒泡阶段
通过 addEventListener(type, handler, useCapture)
控制绑定阶段。
进程与线程
- 进程:浏览器每个标签页是独立进程
- 线程:每个进程包含主线程(UI + JS)和渲染、事件、GC、WebWorker 线程
- JS 运行在主线程,单线程模型,但通过异步(微任务/宏任务)模拟并发
哈希算法原理
- 通过哈希函数将任意长度数据映射为固定长度值
- 常用于数据查重、数据索引、Token 等场景
- 需具备:抗碰撞性 、不可逆性 、高分布性
算法复杂度(Big O)
- 时间复杂度:衡量执行耗时,如 O(1)、O(n)、O(n²)
- 空间复杂度:衡量内存占用,如递归时 O(n) 栈空间
🔐 通信安全与跨端同步机制
即时通讯的消息同步策略
-
消息存储:服务端使用数据库 + 消息队列缓存结构(如 Redis Stream),客户端本地可使用 IndexedDB 或持久化状态库。
-
多端同步:
- 使用设备唯一标识(如 token、设备 id)
- WebSocket 长连接配合 Sync 标记拉取未读
- 本地使用时间戳 + 乐观更新方式补齐丢失内容
会话与身份验证机制
-
Session + Cookie:
- 服务端生成 SessionId 存于内存或数据库
- 客户端通过 Cookie 自动携带
-
JWT 认证:
- Token 无需存储服务端状态,解耦服务端压力
- 使用 HMAC 或 RSA 签名,防止篡改
- 适用于分布式认证或移动端多端登录
🧩 其他重点面试话题补充
-
延迟渲染 :结合
IntersectionObserver
、节流等手段按需渲染 -
组件通信方案:
- 父子:
props
- 跨层级:Context API / 状态管理库(Zustand、Redux)
- 异步通信:发布-订阅模式(EventBus)
- 父子:
-
常见设计模式:
- 单例:共享全局对象
- 工厂:生成 UI 或状态结构
- 代理:懒加载、权限控制
- 发布-订阅:组件间解耦通信