vue-computed的简单实现:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<input id="index--input" value="">
</div>
data: <p id="index--p"></p>
computed: <p id="index--computed"></p>
</body>
<script type="text/javascript">
function Deb() {
this.subs = []
this.addSub = function (cb) {
this.subs.push(cb)
}
this.notify = function (value) {
this.subs.forEach(cb => {
cb(value)
})
}
}
function defineReactive(obj, key, value) {
let deb = new Deb()
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
console.log('get method called')
if(window.cb){
deb.addSub(window.cb)
}
return value
},
set(v) {
console.log('set method called')
if(v === value){
return
}else {
value = v
deb.notify(v)
}
}
})
}
function observer(obj) {
for(let key in obj){
let value = obj[key]
if(typeof value === 'object'){
observer(value)
}
defineReactive(obj, key, value)
}
}
function Watcher(obj, key, cb) {
window.cb = cb
let value = obj[key]
window.cb = null
}
obj = {
name: 'jack',
age: 23,
value: '',
address: {
country: 'usa',
county: 'newYork'
}
}
observer(obj)
new Watcher(obj, 'value', function (value) {
document.getElementById('index--p').innerHTML = value
})
// simple computed
function defineComputed(obj, key, constructor) {
let value = null
let computed = true
let deb = new Deb()
let callback = function () {
computed = false
deb.notify(obj[key])
console.log(value)
}
window.cb = callback
value = constructor.call(obj)
window.cb = null
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
if(window.computedCallback){
deb.addSub(window.computedCallback)
}
console.log('computed')
if(!computed){
console.log('dependencies changed, evaluating...')
value = constructor.call(obj)
computed = true
}
return value
},
set(v) {
}
})
}
function computedWatcher(obj, key, callback) {
window.computedCallback = callback
let value = obj[key]
window.computedCallback = null
}
defineComputed(obj, 'detail', function () {
return `${this.name}-${this.age}-${this.value}`
})
new computedWatcher(obj, 'detail', function (value) {
console.log('computed property changed')
document.getElementById('index--computed').innerHTML = value
})
window.onload = function () {
window.addEventListener('input', function (event) {
obj.value = event.target.value
})
}
</script>
</html>