在 vue 的 2.x 版本中⽤ object.defineProperty 来实现双向数据绑定原理,⽽在 vue3.0 版本中⽤Proxy 这个对象来代替 object.defineProperty 实现数据的双向绑定。这俩种数据双向绑定都是基于数据劫持来实现的。
1.defineProperty
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
语法
- Object.defineProperty(obj, prop, descriptor)
参数
- obj : 要定义属性的对象。
- prop:要定义或修改的属性的名称或 Symbol 。
- descriptor:要定义或修改的属性描述符对象。
返回值
- 被传递给函数的对象。
<script>
let obj = {x:100}
let obj2 = {y:200}
// 不可枚举 无法更改
Object.defineProperty(obj2,'x',{
// value:18,
get(){
console.log('有人读取')
// person.age
return obj.x
},
set(value){
console.log('有人修改value,值为',value)
obj.x =value
return number
}
// 通过obj2操作obj的x 相当于data数据代理vm
})
// 控制台
console.log(Object.keys(obj))
console.log(obj)
</script>
利用 object.defineProperty进行数据劫持也有缺点
1.数组的以下几个方法不会触发 其中的set:
{
push
pop
shift
unshift
splice
sort
reverse
}
Vue 把这些方法定义为变异方法 (mutation method),指的是会修改原来数组的方法。与之对应则是非变异方法 (non-mutating method),例如 filter, concat, slice 等,它们都不会修改原始数组,而会返回一个新的数组。
2.必须先将对象的key值遍历后在逐个添加,增加了一层嵌套
Object.keys(obj).forEach(key => {
Object.defineProperty(obj, key, {
// ...
})
})
2.Proxy
核心:
- 通过Proxy代理:拦截对data任意属性的任意(13种)操作,包括对属性值的读写,属性的添加,属性的删除等
- 通过Reflect反射:动态对被代理对象的相应数值进行特定的操作。
Proxy对象参数
- handler:包括捕捉器的占位符对象,可译为处理器对象。用来监视数据的变化,里面有监视的方法
- target:目标对象
- traps:类似于捕获器
Reflect对象
- 反射对象,反射操作,简单来说,将代理对象相关的属性和属性值的返回。
!只能调用其静态方法无法构造 配合handler使用
响应式实现代码例子:
setup() {
const uesr = {
name: 'jzy',
age: 20,
school: {
name: 'Jimei',
},
const proxyUser = new Proxy(uesr, {
// handler.get()用于拦截对象的读取属性操作
get(target, prop) {
console.log('get方法调用了')
return Reflect.get(target, prop)
// 通过反射对象将数据反射出去
},
// 修改目标对象属性值/为目标对象添加新的属性
set(target, prop, val) {
console.log('set方法调用了')
return Reflect.set(target, prop, val)
},
})
console.log(proxyUser.name)
// 通过代理对象更新目标对象上的某个属性值
proxyUser.name = 'JiangZhengyang'
// proxyUser.gender = '男'
console.log(proxyUser.name)
// delete proxyUser.age
console.log(proxyUser)
},
输出:
3.proxy相较于object.defineProperty的优势
- 直接监听对象⽽⾮属性
- 直接监听数组的变化
- 拦截⽅式较多(有 13 种⽅式)
apply 、construct、defineProperty、deleteProperty、
get、getOwnPropertyDescriptor、getPrototypeOf、has、isExtensible
ownKeys、preventExtensions、set、setPrototypeOf
- Proxy 返回⼀个新对象,可以只操作新对象达到⽬的,⽽ Object.defineProperty 只能遍历对象属性
Proxy 可以被认为是 Object.defineProperty()
的升级版。外界对某个对象的访问,都必须经过这层拦截。因此它是针对整个对象,而不是对象的某个属性,所以也就不需要对keys 进行遍历。