Vue2响应式原理:
let obj = {
name: "Jack",
age: 18,
hobby: {
name1: 'basketball',
name2: 'pingpang'
}
}
// let obj = [1, 3, 5, 7, 9]
function defineReactive(obj, key, value) {
// 当需要监听的属性对应的值也是引用类型,则还需要再次遍历监听,这样才可以监听到该引用类型中属性的变化
observe(value)
Object.defineProperty(obj, key, {
get() {
console.log(`Get: ${key}`)
return value
},
set(newVal) {
console.log('newval', newVal, 'value', value);
if (newVal !== value) {
console.log(`Set: ${newVal}`)
value = newVal
}
}
})
}
function observe(obj) {
if (typeof obj !== 'object' || !obj) return;//排除null类型和基本类型
Object.keys(obj).forEach(key => defineReactive(obj, key, obj[key]))
}
observe(obj)
obj.age //Get: age
obj.age = 88;//newval 88 value 18 //Set: 88
obj.hobby.name1 //Get: hobby //Get: name1
obj.hobby.name2 = 'football'//Get: hobby //newval football value pingpang //Set: football
obj.sex = 'man'//无法监听 不会触发任何的get和set 由于添加的属性在初次遍历所有属性添加监听之后,所以无法监听
// obj[0]=888 //newval 88 value 1 //Set: 888 但通过这种方式修改或添加的属性,是无法和页面中绑定的数据同步响应的。
// obj.length=10//无法监听 不会触发任何的get和set
//obj[5]=100//无法监听 不会触发任何的get和set
在 Vue2的响应式原理中,Object.defineProperty存在以下一些缺陷:
1.对于一个已经创建好的对象,如果后续通过直接赋值的方式新增属性,无法将这个新属性变为响应式的。
2.直接通过下标修改数组元素的值,不会触发响应式更新。
3.通过修改数组的长度也无法触发响应式更新。
4.当需要对一个对象的深层属性进行响应式监听时,需要递归地使用 Object.defineProperty 去定义每个属性,这可能会导致性能问题,特别是对于大型复杂的对象结构