// 要实现的效果: 当obj、info中的属性发生改变时,用到对应属性的函数都会再调用
const obj = {
name: 'zerus',
age: 18,
height: 160,
movies: ['不能说的秘密', '大灌篮', '头文字D'],
}
const info = {
province: '广东省',
address: '深圳市',
subInfo: {
address: '火星',
}
}
let activeReactiveFn = null
const reactiveMap = new WeakMap()
class Depend {
constructor() {
this.reactiveFns = new Set()
}
depend() {
if (activeReactiveFn) {
this.reactiveFns.add(activeReactiveFn)
}
}
notify() {
this.reactiveFns.forEach(fn => fn())
}
}
function getDepend(target, key) {
let map = reactiveMap.get(target)
if (!map) {
map = new Map()
reactiveMap.set(target, map)
}
let depend = map.get(key)
if (!depend) {
depend = new Depend()
map.set(key, depend)
}
return depend
}
function reactive(obj) {
return new Proxy(obj, {
get: function (target, key, receiver) {
console.log(target, key)
const depend = getDepend(target, key)
depend.depend()
return Reflect.get(target, key, receiver)
},
set: function (target, key, newValue, receiver) {
const depend = getDepend(target, key)
Reflect.set(target, key, newValue, receiver)
depend.notify()
},
deleteProperty(target, key) {
const depend = getDepend(target, key)
Reflect.deleteProperty(target, key)
depend.notify()
}
})
}
function watchFn(fn) {
activeReactiveFn = fn
fn()
activeReactiveFn = null
}
const objProxy = reactive(obj)
const infoProxy = reactive(info)
watchFn(function () {
console.log(objProxy.name, '-----obj.name --- 1')
console.log(objProxy.name, '-----obj.name --- 2')
})
watchFn(function () {
console.log(infoProxy.address, '-----info.address --- ')
})
objProxy.name = '大帅哥'
infoProxy.address = '北京市'
delete objProxy.name
watchFn(function () {
console.log(objProxy.xxx, '-----objProxy.xxx --- ')
})
objProxy.xxx = '新的属性xxx'
objProxy.xxx = '和人呵呵呵呵'
Vue2的响应式原理也很简单,把reactive部分用Object.defindedProptery实现就好了
// 使普通的对象变成响应式对象
function reactive(obj) {
Object.keys(obj).forEach(key => {
let value = obj[key]
Object.defineProperty(obj, key, {
get: function () {
const depend = getDepend(obj, key)
depend.depend()
return value
},
set: function (newValue) {
const depend = getDepend(obj, key)
value = newValue
depend.notify()
}
})
})
return obj
}