Vue 的数据响应式原理是什么?
Vue 的数据响应式原理是通过 Object.defineProperty 或 Proxy 来实现的。Vue 在初始化时会对 data 对象中的属性进行递归遍历,使用 Object.defineProperty 将这些属性转换为 getter 和 setter。当数据发生变化时,setter 会通知依赖该数据的视图进行更新。
使用object.defineProperty
js
// 属性对应的依赖函数,设置函数集合(依赖可能不是一个函数)
const targetMap = new Map<string, Set<Function>>();
// 暂存当前需要收集的副作用函数
let activeEffect: Function | null = null;
function oberserver<T>(data: T) {
if (!data || typeof data !== "object") return;
for (const item in data) {
// 忽略原型链上的属性
if (Object.prototype.hasOwnProperty.call(data, item)) continue;
let initValue = data[item];
// 递归处理对象属性
oberserver(initValue);
Object.defineProperty(data, item, {
get() {
if (activeEffect) {
// 获取当前属性对应的依赖函数
let depsSet = targetMap.get(item);
// 如果不存在则创建
if (!depsSet) {
depsSet = new Set<Function>();
// 添加依赖函数
targetMap.set(item, depsSet);
}
// 添加依赖函数
depsSet.add(activeEffect);
}
return initValue;
},
set(newValue) {
if (newValue === initValue) return;
initValue = newValue;
const deps = targetMap.get(item);
deps?.forEach((fn) => {
fn();
});
},
});
}
return data;
}
// 收集依赖函数
function collect(...fn: Function[]) {
fn.forEach((fun) => {
activeEffect = fun;
fun();
activeEffect = null;
});
}使用proxy
js
const handler = {
get(target, key, receiver) {
console.log(`get ${key}`);
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
console.log(`set ${key}: ${value}`);
return Reflect.set(target, key, value, receiver);
}
};
const observed = new Proxy({}, handler);