实现思路
- 数据劫持:利用
Object.defineProperty()
方法对数据对象的属性进行劫持,在 get
操作中收集依赖,在 set
操作中触发依赖更新。例如:
function reactive(obj) {
Object.keys(obj).forEach(key => {
let value = obj[key];
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
// 收集依赖
track(key);
return value;
},
set(newValue) {
if (newValue === value) return;
value = newValue;
// 触发依赖更新
trigger(key);
return true;
}
});
});
return obj;
}
- 依赖收集与管理:创建一个依赖管理器,使用
WeakMap
来存储数据对象和对应的依赖集合。例如:
const targetMap = new WeakMap();
function track(key) {
const target = getCurrentTarget();
if (!target) return;
let depsMap = targetMap.get(target);
if (!depsMap) {
depsMap = new Map();
targetMap.set(target, depsMap);
}
let dep = depsMap.get(key);
if (!dep) {
dep = new Set();
depsMap.set(key, dep);
}
dep.add(target);
}
function trigger(key) {
const target = getCurrentTarget();
if (!target) return;
const depsMap = targetMap.get(target);
if (!depsMap) return;
const dep = depsMap.get(key);
if (dep) {
dep.forEach(effect => effect());
}
}
- 副作用函数(Watcher):定义副作用函数,在函数执行时将自身设置为当前依赖,执行完毕后清除当前依赖。例如:
let activeEffect;
function effect(fn) {
const effectFn = () => {
activeEffect = effectFn;
fn();
activeEffect = null;
};
effectFn();
return effectFn;
}
function getCurrentTarget() {
return activeEffect;
}
优势场景
- 轻量级应用:在一些对性能要求极高且功能相对简单的轻量级前端应用中,自定义机制可以根据具体需求进行精简优化,避免Vue原生机制带来的一些不必要的开销,例如复杂的组件化系统和指令系统。
- 特定数据结构:当处理一些特殊的数据结构,如大型数组的频繁操作时,自定义机制可以针对数组操作进行定制化的优化,而Vue原生机制在处理数组时可能存在性能瓶颈,因为其需要对数组的一些方法进行额外的包装以实现响应式。
- 与现有系统集成:在与一些遗留系统或特定框架集成时,自定义响应式机制可以更好地适应现有系统的架构和接口,避免与现有系统中已有的数据处理逻辑产生冲突,而Vue原生机制可能因为其设计理念和运行机制与现有系统不兼容。