使用 Object.defineProperty() 实现 (类似 Vue 2)
我们将创建一个简单的响应式系统,其中包括数据的响应式转换、依赖收集和更新触发:
class Dep {
constructor() {
this.subscribers = new Set();
}
depend() {
if (activeUpdate) {
this.subscribers.add(activeUpdate);
}
}
notify() {
this.subscribers.forEach(sub => sub());
}
}
function reactive(obj) {
Object.keys(obj).forEach(key => {
let internalValue = obj[key];
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
dep.depend();
return internalValue;
},
set(newVal) {
const changed = internalValue !== newVal;
internalValue = newVal;
if (changed) {
dep.notify();
}
}
});
});
return obj;
}
let activeUpdate = null;
function autorun(update) {
function wrappedUpdate() {
activeUpdate = wrappedUpdate;
update();
activeUpdate = null;
}
wrappedUpdate();
}
// 使用示例
const state = reactive({ count: 0 });
autorun(() => {
console.log(`The count is: ${state.count}`);
});
state.count++; // 输出: The count is: 1
使用 Proxy
实现 (类似 Vue 3)
使用Proxy
来实现更现代、更灵活的响应式系统
function reactive(target) {
const handler = {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver);
track(target, key);
return result;
},
set(target, key, value, receiver) {
const oldValue = target[key];
const result = Reflect.set(target, key, value, receiver);
if (oldValue !== value) {
trigger(target, key);
}
return result;
}
};
return new Proxy(target, handler);
}
let currentEffect = null;
const effectStack = [];
const targetMap = new WeakMap();
function track(target, key) {
if (currentEffect) {
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let dep = depsMap.get(key);
if (!dep) {
depsMap.set(key, (dep = new Set()));
}
dep.add(currentEffect);
}
}
function trigger(target, key) {
const depsMap = targetMap.get(target);
if (depsMap) {
let dep = depsMap.get(key);
if (dep) {
dep.forEach(effect => effect());
}
}
}
function effect(fn) {
const effectFn = () => {
cleanup(effectFn);
currentEffect = effectFn;
effectStack.push(effectFn);
fn();
effectStack.pop();
currentEffect = effectStack[effectStack.length - 1];
};
effectFn();
}
function cleanup(effectFn) {
// 清理所有与该effect相关联的依赖
}
// 使用示例
const state = reactive({ count: 0 });
effect(() => {
console.log(`The count is now: ${state.count}`);
});
state.count++; // 输出: The count is now: 1