vue中的双向绑定是通过数据代理实现的,利用了Object.defindPropety()这个方法实现的(Vue2.x),这个方法重新定义了对象获取属性值(get)和设置属性值(set)
1.Object.defindProperty()
defindProperty(obj,prop,descriptor),这个方法有三个参数,第一个参数obj就是要定义的对象,第二个参数prop是对象的某个属性值,用字符串表示,第三个参数descriptor是用来控制prop的,先重点介绍第三个参数,它传入一个对象,对象包括以下的属性值:
value:给prop属性赋值
enumerable:控制属性是否可枚举,默认是false(控制该属性可否被遍历)
writeable:控制属性是否可以被修改,默认是false
configurable:控制属性是否可以被删除,默认是false
get():当程序读取prop属性的时候,get函数(getter)就会被调用
set():当程序修改prop属性的时候,set函数(setter)就会被调用
let number = 18
let person = {
name: '张三',
gender: '男'
}
Object.defineProperty(person, 'age', {
get() {
console.log('有人读取了age属性')
return number
},
set(value) {
console.log(`有人修改了age,值是${value}`)
number = value
}
})
console.log(person.age)
person.age = 20
console.log(person.age)
运行结果:
有人读取了age属性
18
有人修改了age,值是20
有人读取了age属性
20
2.数据代理
数据代理就是通过一个对象去代理另外一个对象中属性的操作(读/写),下面通过defineProperty方法实现一下数据代理:
let obj = {
x:100,
y:200
}
let obj2 = {}
Object.defineProperty(obj2, 'x', {
get() {
return obj.x
},
set(value) {
obj.x = value
}
})
Object.defineProperty(obj2, 'y', {
get() {
return obj.y
},
set(value) {
obj.y = value
}
})
console.log(`修改前obj2.x-->${obj2.x}`)
console.log(`修改前obj2.y-->${obj2.y}`)
obj2.x = 150
obj2.y = 120
console.log(`修改后obj.x-->${obj.x}`)
console.log(`修改后obj.y-->${obj.y}`)
通过obj2去代理obj属性的读取/修改,运行结果如下:
修改前obj2.x-->100
修改前obj2.y-->200
修改后obj.x-->150
修改后obj.y-->120
3.Vue中的数据代理
vue中的数据代理是通过vm实例对象来代理data对象中属性的读取和修改,这样的好处就是更加方便的操作data中的数据,基本的原理如下:
通过Object.defindProprerty()方法把data所有属性都添加到vm实例对象上,为添加到vm实例对象的每一个属性都指定一个getter/setter,在getter和setter内部去读写data中对应的属性。
<template>
<div id="app">
<h1>姓名:{{name}}---年龄:{{age}}</h1>
</div>
</template>
<script>
export default {
data() {
return {
name: '张三',
age:18
}
}
}
</script>
模拟Vue2.x响应式过程
let data = {
name:'张三',
age:18
}
Object.defineProperty(data,'name',{
get(){ //有人读取name时调用
return data.name
},
set(value){ //有人修改name时调用
console.log('有人修改了name属性,我发现了,我要去更新界面!')
data.name = value
}
})
Object.defineProperty(data,'age',{
get(){ //有人读取age时调用
return data.age
},
set(value){ //有人修改age时调用
console.log('有人修改了age属性,我发现了,我要去更新界面!')
data.age = value
}
})
每当要修改的Vue中data对应的属性值,就会触发vm中对应属性的set方法,同时去更新View层视图的值,这就是Vue中的响应式原理,但是defindProperty()方法中没有定义属性值添加/删除的方法,当要往data中添加或者删除的时候,defindProerty()无法完成响应式,在Vue3会完善改进这个问题。但在Vue2也提供了完整的解决方案,可通过Vue.set()/this.$set()添加属性,Vue.delete()/this.$delete()删除属性
总结:通过本文学习,我们知道了vue2.x数据的响应式是通过数据代理完成的,而数据代理主要核心就是Object.defindProperty()这个方法