vue3响应式原理使用Proxy(配合反射Reflect)
// Proxy与
// 简易版本
// const data = {
// name: 'zhangsan',
// age: 20,
// }
const data = ['a', 'b', 'c']
const proxyData = new Proxy(data, {
get(target, key, receiver) {
// 只处理本身(非原型的)属性
const ownKeys = Reflect.ownKeys(target)
if (ownKeys.includes(key)) {
console.log('get', key) // 监听
}
return Reflect.get(target, key, receiver)
},
set(target, key, val, receiver) {
// 重复的数据,不处理
if (val === target[key]) {
return true
}
const result = Reflect.set(target, key, val, receiver)
console.log('set', key, val)
// console.log('result', result) // true
// result是布尔值
return result // 是否设置成功
},
deleteProperty(target, key) {
const result = Reflect.deleteProperty(target, key)
console.log('delete property', key)
// console.log('result', result) // true
return result // 是否删除成功
}
})
function reactive(target = {}) {
if (typeof target !== 'object' || target == null) {
return target
}
const proxyConf = {
get(target, key, receiver) {
const ownKeys = Reflect.ownKeys(target)
if (ownKeys.includes(key)) {
console.log('get', key)
}
const result = Reflect.get(target, key, receiver)
return reactive(result)
},
set(target, key, val, receiver) {
if (val === target[key]) {
return true
}
const ownKeys = Reflect.ownKeys(target)
if (ownKeys.includes(key)) {
console.log('已有的 key', key)
} else {
console.log('新增的 key', key)
}
const result = Reflect.set(target, key, val, receiver)
console.log('set', key, val)
return result
},
deleteProperty(target, key) {
const result = Reflect.deleteProperty(target, key)
console.log('delete property', key)
return result
}
}
const observed = new Proxy(target, proxyConf)
return observed
}
const data = {
name: 'zhangsan',
age: 20,
info: {
city: 'beijing',
a: {
b: {
c: {
d: {
e: 100
}
}
}
}
}
}
const proxyData = reactive(data)
proxyData.info.city1 = '北京'
console.log(proxyData)
Vue2响应式原理defineProperty
function updateView() {
console.log('视图更新')
}
const oldArrayProperty = Array.prototype
const arrProto = Object.create(oldArrayProperty)[
('push', 'pop', 'shift', 'unshift', 'splice')
].forEach((methodName) => {
arrProto[methodName] = function () {
updateView()
oldArrayProperty[methodName].call(this, ...arguments)
}
})
function defineReactive(target, key, value) {
observer(value)
Object.defineProperty(target, key, {
get(value) {
return value
},
set(newValue) {
if (newValue !== value) {
observer(newValue)
value = newValue
updateView()
}
}
})
}
function observer(target) {
if (typeof target !== 'object' || target === null) {
return target
}
if (Array.isArray(target)) {
target.__proto__ = arrProto
}
for (let key in target) {
defineReactive(target, key, target[key])
}
}
const data = {
name: 'zhangsan',
age: 20,
info: {
address: '北京'
},
nums: [10, 20, 30]
}
observer(data)
data.nums.push(4)