1126605465
2023/02/28阅读:31主题:自定义主题1
vue2响应式原理核心Object.definedProperty
vue2 的数据响应式原理核心的是Object.definedProperty,通过它可是实现对数据的监听拦截,但 vue2 响应式数据并不只是单单靠它完成的,本文只介绍 Object.definedProperty,及实现简单的数据监听.
Object.definedProperty 介绍
Object.defineProperty()的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性,并且返回这个对象.
let obj ={}
Object.defineProperty(obj,'name',{value:'小名'})
console.log(obj)
//输出结果 {name: '小名'}
//它的功能类似于 直接obj.name='小名'
//它的优点在于该方法具有更详细的配置参数
Object.definedProperty 参数
Object.defineProperty(obj,key,desc)有三个参数:
obj 为操作的对象,
key 为对象中的属性名,
desc 为对应属性的具体配置,是一个对象格式.
let obj={}
Object.defineProperty(obj,'属性名',{
value:'属性值', //设置属性值 不能与get()set()同时使用
writable:true, //该属性值是否可编辑 不能与get()set()同时使用
configurable:true, //该属性是否能删除
enumerable:true, //该属性是否能枚举
get(){
return value //读取该属性会触发get,并返回一个val,默认undefined
},
set(newVal){
value=newVal //设置新值 参数为修改值
}
})
Object.definedProperty 使用
let num=12
let obj = { }
Object.defineProperty(obj, 'age', {
get() {
console.log('触发get函数,取值', num)
return num
},
set(newVal) {
console.log('触发set函数,设置新值', newVal)
num = newVal
}
})
console.log(obj.age);
obj.age=16
//控制台输出如下图.可以看到无论是读取还是修改,对象中的属性已经被监听

Object.definedProperty 封装
通过上述使用案例,我们学习学习了如何监听数据的实时变化,但是有一个弊端,就是一次只能监听对象中的一个属性值,想在vue中监听data中所有的数据,还需要进行进一步封装,下面演示一个简易版的封装.
//先封装一下Object.definedProperty
function defineNative(obj, key, val){
//接收三个参数 对象,属性名,属性值
if (arguments.length === 2) {
//属性值可以不传,根据对象[属性名获取]
val = obj[key]
}
if (val instanceof Object) {
//这里是检测 对象的属性是否又是一个对象
//如果是需要递归,不理解可以往下看
new Observer(val)
}
这里调用Object.definedProperty
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
console.log('调用读取数值', val)
return val
},
set(newVal) {
console.log('调用设置数值', newVal)
val = newVal
}
})
}
//在封装一个类 用遍历数据 循环调用上面的方法
class Observer {
constructor(obj) {
this.value = obj
//判断数据类型
if (typeof obj === 'Array') {//数组
} else {//对象
// 获取obj中所有的key
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineNative(obj, keys[i])
}
}
}
}
//下面检验一下 封装是否正确
let test= new Observer
let test = new Observer({
name: '张三',
age: 18,
obj: {
name: '子对象'
}
})
console.log(test.value.name);
test.value.name = '李四'
console.log(test.value.age);
test.value.age = 66
console.log(test.value.obj);
test.value.obj.name='修改子对象'
下面数控制台输出 可以看到,三次读取修改都触发了我们的监听,而且就算属性值是对象也可以触发监听.这也就是vue2中双向数据绑定的数据监听部分的原理.
小彩蛋 如果我们读取或者修改一个,不存在的初始值会怎么样?
//上述代码省略...
test.obj.test='不存在的初始值'
console.log(test.obj.test)
控制台只打印了一个我们的赋值,并没有触发set get函数,现在你是否明白为什么在项目中,有时我们修改一些data中不存在的变量时(没有初始值的变量),明明数据已经变了,可是页面的显示的值并没有发生变化的问题了吗.
vue2的响应式数据,并不只是单单靠Object.defineProperty,通过上文叙述,我们只做到了监听数据的变化,并没有在数据变化时执行额外的操作,真正的响应式,还需要结合发布订阅模式,在数据变化时,执行对节点的操作,从而实现页面更新,达到响应效果.
作者介绍