观察者模式
- 观察者模式包含 subject(观察目标) 和 watcher(观察者) 两类对象。一个 subject 通常对应着多个 watcher,subject 的状态发生变化,所有 watcher 都会收到通知。
- 观察者是知道 subject 的,subject 一直保持对观察者进行记录。(而发布订阅模式的发布者和订阅者不知道对方的存在,它们只有通过消息代理进行通信。)
- 观察者模式大多数时候是同步的,而发布-订阅模式大多数时候是异步的
代码
可以直接运行调试
let data
let active
let onChanged = (cb) => {
// 把响应回调的函数临时存在 active
active = cb
// 首次主动调用回调函数
active()
// 调用后将其置为 null,以免重复依赖
active = null
}
class Dep {
deps = new Set()
depend() {
if (active) {
// 添加观察者
this.deps.add(active)
}
}
notify() {
// 通知所有观察者
this.deps.forEach((dep) => dep())
}
}
let ref = (initValue) => {
let value = initValue
// 每个变量独享一个 dep 对象
let dep = new Dep()
return Object.defineProperty({}, 'value', {
get() {
// 读取是添加观察者
dep.depend()
return value
},
set(newVal) {
value = newVal
// 写入后通知所有观察者
dep.notify()
},
})
}
// reactive
data = ref(1)
// dom
const iptEl = document.querySelector('#ipt')
const resultEl = document.querySelector('#result')
iptEl.addEventListener('input', (e) => {
data.value = e.target.value
})
onChanged(() => {
resultEl.innerHTML = data.value
})
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vue Reactive</title>
<style>
.container {
margin: 100px auto;
width: 500px;
}
</style>
</head>
<body>
<div class="container">
<label for="ipt">input</label>
<input type="text" id="ipt" value="1" />
<br />
<br />
<label for="result">value</label>
<span id="result"></span>
</div>
<script src="./index.js"></script>
</body>
</html>