現在國內的兩大框架: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)
浙公網安備 33010602011771號