现在国内的两大框架:vue、react。对于这两个框架,相信大家多多少少都接触过,对于vue而言,有一个很重要的特点,那就是响应式。vue2的响应式采用的是ES5的Object.defineproperty对数据进行劫持。而vue3则是采用ES6的Proxy对数据进行劫持。想要了解vue3的响应式就必须了解Proxy。

一、Proxy的认识
Proxy是ES6新增的,它是一个类,是用于帮助我们创建一个代理对象,如果我们需要监听对象的操作,那么我们可以通过Proxy先创建一个代理对象,之后对该对象的所有操作都通过代理来完成。他与Object.defineProperty最大的区别就在于Object.defineProperty直接监听对象的属性,proxy是监听整个代理对象。

二、Proxy的基本使用

创建一个对象

const obj = {
name:'cj',
age:18
}
再创建Proxy代理对象

const objProxy = new Proxy(obj,{})
参数一:需要代理的对象

参数二:捕获器,对代理对象的属性进行访问、赋值等操作的时候触发,与Object.defineproperty的存取描述符类似。如果为空对象,就只有set、get这两个默认捕获器,并且不会有过多的操作,get捕获器就直接返回访问属性的值,set捕获器就将新的值赋值给访问属性。

示例:

const objProxy = new Proxy(obj,{})

console.log(objProxy.name) //'cj'
console.log(objProxy.age) //18

objProxy.name = 'wx'
objProxy.age = 20

//对代理对象操作后,代理对象就会对原对象进行操作
console.log(obj.name) //'wx'
console.log(obj.age) //20
注意:Proxy只能代理对象(Object、Function、Array),非对象值无法进行代理。Proxy也只能够代理对象的基本操作,无法代理对象的复合操作。什么是基本操作?什么又是复合操作?

const obj = {
name:'cj',
bar(){
console.log('bar')
}
}
const objProxy = new Proxy(obj,{})

function foo() { console.log('foo') }
const fooProxy = new Proxy(foo,{
apply(){ //apply是对函数调用进行拦截
//...
}
})

objProxy.name; //基本操作
fooProxy(); //基本操作

objProxy.bar() //复合操作

上面访问代理对象的属性、调用函数就是基本操作。调用对象里的方法就是复合操作,它可以分为两步:第一步是访问对象的方法,第二步是调用该方法。

三、Proxy捕获器的使用
Proxy捕获器用来对代理对象属性进行访问、赋值等操作时的一个捕获。与Object.defineproperty的存取描述符类似。下面我们就认识一下常用的四个捕获器的基本使用。

const objProxy = new Proxy(obj,{
//get操作符
get:function(target,key){
console.log(`监听到访问${key}属性`,target)
return target[key] //返回访问属性的值
},
//set操作符
set:function(target,key,newValue){
console.log(`监听到给${key}属性设置值`,target)
tarset[key] = newValue //将属性最新值,赋值给代理对象属性
}
//has操作符
has:function(target,key){
console.log(`监听到使用in操作符${key}`,target)
return key in target
}
//delete操作符
deleteProperty:function(){
console.log(`监听到使用delete操作符${key}`,target)
delete target[key]
}
})

console.log(objProxy.name)
console.log(objProxy.age)

objProxy.name = 'wx'
objProxy.age = 20

//in操作符
console.log('name' in objProxy) //true
//delete操作符
delete objProxy.name

Proxy的13种捕获器:
handler.get():属性读取操作的捕捉器。
handler.set():属性设置操作的捕捉器。
handler.has():in 操作符的捕捉器。
handler.deleteProperty():delete 操作符的捕捉器。
handler.getPrototypeOf():Object.getPrototypeOf 方法的捕捉器。
handler.setPrototypeOf():Object.setPrototypeOf 方法的捕捉器。
handler.isExtensible():Object.isExtensible 方法的捕捉器。
handler.preventExtensions():Object.preventExtensions 方法的捕捉器。
handler.getOwnPropertyDescriptor():Object.getOwnPropertyDescriptor 方法的捕捉器。
handler.defineProperty():Object.defineProperty 方法的捕捉器。
handler.ownKeys():Object.getOwnPropertyNames 方法和Object.getOwnPropertySymbols 方法的捕捉器。
handler.apply():函数调用操作的捕捉器。(函数也是一个对象,这里就对函数调用时进行监听)
handler.construct():new 操作符的捕捉器。(函数执行new操作符的时候进行监听)
总结:
Proxy除了set、get捕获器能监听对象属性,还有其它的操作符,一共有13种。
使用Proxy创建的代理对象进行操作的好处是,可以不用直接通过Object.defineproperty去操作原对象,通过Object.defineproperty直接操作原对象就会将对象原本的数据属性描述符变成了访问属性描述符
Object.defineproperty没有类似于has、deleteProperty等这样的捕获器,只有存取属性描述符(set、get)

posted on 2023-03-19 22:02  Godfather-twq  阅读(169)  评论(0编辑  收藏  举报