import Dep from './dep';
export function reactive(data){
if(typeof data === 'object'){
Object.keys(data).forEach(key => {
defineReactive(data,key)
})
}
return data;
}
function defineReactive(data,key){
let val = data[key];
const dep = new Dep();
Object.defineProperty(data,key,{
get(){
dep.depend();
return val
},
set(newVal){
if(newVal === val) return;
val = newVal;
dep.notify();
}
})
if(typeof val === 'object'){
reactive(val)
}
}
- dep.js //收集watcher,通知watcher更新
export default class Dep {
constructor(){
this.subs = [];
}
addSub(watcher){
this.subs = this.subs.filter(item => item !== watcher);
this.subs.push(watcher);
}
depend(){
if(Dep.target){
Dep.target.addDep(this)
}
}
notify(){
this.subs.forEach(watcher => {
watcher.update();
})
}
}
Dep.target = null;
const targetStack = [];
export function pushTarget(target){
if(Dep.target){
targetStack.push(Dep.target)
}
Dep.target = target;
}
export function popTarget(){
Dep.target = targetStack.pop()
}
import Dep, { pushTarget, popTarget} from "./dep";
export default class Watcher{
constructor(getter,options = {}){
const { lazy, watch, callback } = options;
this.getter = getter;
this.deps = [];
this.lazy = lazy;
this.dirty = lazy;
this.watch = watch;
this.callback = callback;
if(!lazy){
this.get();
}
}
get(){
pushTarget(this);
this.value = this.getter();
popTarget();
return this.value;
}
addDep(dep){
this.deps = this.deps.filter(item => item !== dep);
this.deps.push(dep);
dep.addSub(this)
}
depend(){
this.deps.forEach(dep => dep.depend());
}
evaluate(){
this.value = this.get();
this.dirty = false;
}
update(){
if(this.lazy){
this.dirty = true;
}
else if(this.watch){
const oldValue = this.value;
this.get();
this.callback(this.value,oldValue)
}
else {
this.get();
}
}
}
import Dep from "./dep";
import Watcher from "./watcher";
export default function computed(getter){
let def = {};
const computedWatcher = new Watcher(getter,{
lazy: true,
});
Object.defineProperty(def,'value',{
get(){
if(computedWatcher.dirty){
computedWatcher.evaluate();
}
if(Dep.target){
computedWatcher.depend();
}
return computedWatcher.value;
}
})
return def;
}
import Watcher from "./watcher";
export default function watch(getter,callback){
new Watcher(getter,{
watch: true,
callback
})
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<span>名称:</span> <span id="app"></span>
</div>
<div>
<span>数字:</span> <span id="num"></span>
</div>
<div>
<span>computed:</span> <span id="computed"></span>
</div>
</body>
</html>
import { reactive } from './reactive';
import Watcher from './watcher';
import computed from './computed';
import watch from './watch';
window.data = reactive({
num: 1,
detail: {
name: '响应式原理'
}
})
const computedData = computed(() => data.num * 2);
watch(
() => data.num,
(newValue,oldValue) => {
console.log(newValue,oldValue)
}
)
new Watcher(() => {
document.getElementById('app').innerHTML = data.detail.name;
document.getElementById('num').innerHTML = data.num;
document.getElementById('computed').innerHTML = computedData.value;
})
来自 https://juejin.cn/post/6844904120290131982
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?