通过监听数据的变化,实现响应式。

1. vue2 通过​​Object.defineProperty​​ 实现监听

  1. ​Object.defineProperty​​精确地添加或修改对象的属性
Object.defineProperty(target, key, {
get() {
return value
},
set(newValue) {
value = newValue
}
})

​Object.definePropery​​ 的缺点:


  • 深度监听需要一次性递归
  • 无法监听数组
  • 无法监听新增属性和删除属性

  1. 实现数据监听
function updateView() {
console.log('视图更新');
}

// 重新定义原型,重写方法数组实现监听
const originalProto = Array.prototype;
const arrayProto = Object.create(originalProto); // 先克隆一份Array的原型出来
['push', 'pop', 'shift', 'unshift', 'slice', 'splice'].forEach(item => {
arrayProto[item] = function () {
// 执行原始操作
originalProto[item].call(this, ...arguments);
updateView();
}
});

// 定义属性
function defineReactive(target, key, value) {
// 深度监听, 例如这种修改 data.info.msg = 'mmm' 需要递归监听
observe(value)

Object.defineProperty(target, key, {
get() {
return value
},
set(newValue) {
if (newValue !== value) {
// 设置新值深度监听 data.name = { n: 1 } ; data.name.n = 2 新的值需要监听
observe(newValue)
// value一直存在闭包中,再get就能获取到
value = newValue
// 触发更新
updateView()
}
}
})
}

// 监听函数
function observe(target) {
if (typeof target !== 'object' || target === null) {
// 不是对象或数组
return target
}

// 监听数组
if (Array.isArray(target)) {
console.log('target', target);
target.__proto__ = arrayProto
}

// 重新定义属性
for (const key in target) {
defineReactive(target, key, target[key])
}
}

// 准备数据
const data = {
name: '名字',
age: 23,
info: {
msg: 233
},
nums: [1, 2, 3]
}


observe(data)

// 测试
data.name = 'list'
// data.name = { n: 1 }
// data.name.n = 2
data.age = 22
data.info.msg = 'mm'
data.nums.push(2)

2. vue3 通过​​proxy​​ 实现监听


  1. ​const p = new Proxy(target, handler)​​ 创建一个对象的代理,从而实现基本操作的拦截和自定义
  2. 实现数据监听

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('key 监听', key) // 监听
}
const result = Reflect.get(target, key, receiver)
console.log('get', key, result);
// **如何提升性能: 只在get 使用的时候进行递归
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, result);
return result //是否设置
},
deleteProperty(target, key) {
const result = Reflect.deleteProperty(target, key)
console.log('delete', key, result);
return result //是否删除成功
}
}

// 生成代理对象
const observed = new Proxy(target, proxyConf)
return observed
}

const data = {
name: 'zhangsan',
age: 20,
info: {
city: 'beijing',
a: {
b: {
c: {
d:
1
}
}
}

},

}
const proxyData = reactive(data)

console.log('proxyData', proxyData.info.a);