vue底层如何实现
Vue 底层实现核心机制
Vue 的底层实现主要围绕响应式系统、虚拟 DOM和模板编译三大核心机制展开。以下分模块解析其工作原理:
响应式系统
Vue 2.x 使用 Object.defineProperty 实现数据劫持,通过递归遍历数据对象的属性,将其转换为 getter/setter。当数据被访问或修改时,触发依赖收集和派发更新:
function defineReactive(obj, key) {
let value = obj[key];
const dep = new Dep(); // 依赖管理器
Object.defineProperty(obj, key, {
get() {
if (Dep.target) dep.depend(); // 收集依赖
return value;
},
set(newVal) {
if (newVal === value) return;
value = newVal;
dep.notify(); // 通知更新
}
});
}
Vue 3.x 升级为 Proxy 代理,直接监听整个对象,避免递归性能损耗,并支持动态新增属性:
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
track(target, key); // 依赖收集
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver);
trigger(target, key); // 触发更新
return true;
}
});
}
虚拟 DOM 与 Diff 算法
Vue 将模板编译为虚拟 DOM(VNode),通过对比新旧 VNode 差异最小化 DOM 操作:
- 创建 VNode:描述真实 DOM 的轻量级对象。
- Patch 过程:采用同级比较策略,通过
snabbdom优化算法:- 同层节点通过
key复用 - 差异类型:节点增删、属性更新、文本替换
- 同层节点通过
- 批量更新:异步队列(nextTick)合并多次数据变更。
示例 Diff 核心逻辑:
function updateChildren(parentElm, oldCh, newCh) {
while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
if (sameVnode(oldStartVnode, newStartVnode)) {
patchVnode(oldStartVnode, newStartVnode); // 递归对比子节点
}
// ...其他对比情况(头尾交叉比对)
}
}
模板编译
Vue 模板通过编译器转换为渲染函数:
- 解析阶段:将模板字符串转换为 AST(抽象语法树)。
- 优化阶段:标记静态节点(避免重复渲染)。
- 生成代码:将 AST 转换为可执行的
render函数字符串。
编译结果示例:
// 模板: <div>{{msg}}</div>
function render() {
with(this) {
return _c('div', [_v(_s(msg))]);
}
}
// _c: createElement, _v: createTextVNode, _s: toString
组件化实现
组件实例通过构造函数创建,管理生命周期、数据及父子通信:
- 每个组件对应一个 Watcher 实例,监听数据变化。
- 父子组件通过
$parent/$children建立关联。 - 插槽内容编译为
scopedSlots传递给子组件。
关键初始化流程:
function initInternalComponent(vm, options) {
const opts = vm.$options = Object.create(vm.constructor.options);
opts.parent = options.parent; // 维护组件树关系
opts._componentTag = options.tag;
}
性能优化策略
- 响应式优化:Vue 3 的 Proxy 减少递归,组件级颗粒度追踪。
- 编译时优化:静态节点提升(Hoist Static),避免 Diff 比较。
- 更新策略:异步批处理(nextTick 微任务队列)。
这些机制共同构成 Vue 高效、易用的底层架构。







