文章目录
Vue3为什么要用Proxy替代defineProperty
先导知识:Object.defineProperty()和Proxy
Object.defineProperty()
// Object.defineProperty() 方法直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象
Object.defineProperty(obj, prop, descriptor)
// obj 需要定义属性的对象。
// prop 需被定义或修改的属性名。
// descriptor 需被定义或修改的属性的描述符,Object类型
// 添加属性,允许添加任何类型
var user = {};
Object.defineProperty(user,"name",{
value:"mkbird",
// 设置允许被修改,默认为false
writable:true
})
Object.defineProperty(user,"isSlow",{
value:true
})
Object.defineProperty(user,"sayHi",{
value:function () { console.log("Hi !") }
})
Object.defineProperty(user,"age",{
value:18
})
descriptor下有几个属性
- writable是否允许被修改,默认为false,不允许
- enumerable属性是否可以被枚举,默认为false,支持
- configurable是否属性可以被删除和重新定义特性,默认false不允许
- get,获取值的时候的方法,类型为
function
,获取值的时候会被调用,不设置时为undefined
- set,设置值的时候的方法,类型为
function
,设置值的时候会被调用,undefined
当使用了getter或setter方法,不允许使用writable和value这两个属性
Proxy
Proxy为JS中的代理,用来实现对代理对象的拦截和自定义
相当于在外界访问对象前,要先经过代理的处理
// target为要代理的对象
// handler为操作
const p = new Proxy(target, handler)
handler有下列几个属性
- get(target, propKey, receiver):拦截某个属性的读取操作
- target为目标对象
- propKey为属性
- receiverproxy 实例本身(可选)
var p = new Proxy(user,{
get:function(target,property,receiver){
if(property === 'name'){
console.log('name被读取');
}
}
})
p.name// name被读取
- set(target, propKey, value,receiver)
- value为属性值,其他和上面一样
var p = new Proxy(user,{
get:function(target,property,receiver){
if(property === 'name'){
console.log('name被读取');
}
},
set:function(target,property,value,receiver){
console.log('set监控到对象中有属性被修改');
console.log(property,value);
// name ls
}
})
p.name='ls'// set监控到对象中有属性被修改
// 注意,p作为代理被修改,并不会改变原来对象的属性值
Object.defineProperty与Proxy区别
- Proxy监听对象;Object.defineProperty监听具体属性
- Proxy可以监听数组的变化,拦截方法也多
- Proxy返回的是一个新对象,我们只能操作这个新对象,不会影响旧对象的属性;Object.defineProperty直接影响
ES5中,通过defineProperty()的set进行监听
user={
name:'zs',
age:12
}
// 通过defineProperty()进行监听
Object.defineProperty(user,'name',{
set:function(){
console.log('name改变');
}
})
user.name='ls'
// name改变
ES6中,通过Proxy实现
var user = new Proxy({},{
set(target,key,value){
}
})
为什么要替代替代
defineProperty只能对单例属性做监听
Vue2中基于defineProperty中的descriptor,对data中的属性做了遍历+递归,为每个属性设置了getter和setter
所以Vue2中只能对data中预定义过的属性错处响应,在Vue2中使用下标的方式直接修改一个值或者添加一个预先不存在的对象属性无法做到setter监听
Proxy代理对象
Proxy监听是针对一个对象,这个对象的所有操作都会进入监听,这样可以完全代理所有属性,带来很大的性能提升和代码优化
响应式是懒惰的
Vue2中,对于一个深层嵌套的对象,要劫持它内部的变化,需要递归遍历这个对象
Vue3中,Proxy并不能监听到深层属性的变化,它的处理方式是在getter中递归响应,真正做到了谁变换,谁响应