前言
小夥伴們大家好。前面一篇文章中我們對ES6中的Proxy進行了一個簡單的分享。通過學習我們知道Proxy可以對對象進行攔截,進而可以根據業務需要做一些對應的邏輯處理。我們還知道Vue3.0對資料劫持做了一個很大的優化其中用到的就是Proxy。在文章的結尾我們還整理出了Proxy提供的支援攔截操作的一些執行個體方法。本章我們就抽取幾個常用的攔截方法進行一個分享。
get(target, propKey, receiver)
看過上一篇文章的小夥伴應該都注意到了:在我們代碼案例中用到最多的攔截方法就是get和set了。但并沒有對這些方法進行一個詳細的說明。
- get(target, propKey, receiver)方法用于攔截對象的屬性讀取,也就是說當我們通過Proxy的執行個體去通路對象的屬性時會優先進入到get方法中。
- get方法接收三個參數:target:要攔截的目标對象,propKey:目标對象中的屬性, receiver(可選):Proxy執行個體本身(嚴格的說應該是操作行為所針對的對象),第三個參數用到的場景很少,一般都是前兩個參數比較多。
- get方法是可以支援繼承的。将以一個小案例示範。
let obj = {name:'Yannis'}
let proxy = new Proxy(obj,{
get(target, key, receiver){
console.log(target);
console.log(key);
return 'Hello '+ target[key];
}
});
obj.name;
// {name:'Yannis'} target要攔截的對象
// name key:正在通路的對象的屬性
// 'Hello Yannis' 當我們通路對象屬性時,攔截器自動加了個Hello字首
// get方法是可以支援繼承
let proxy = new Proxy({},{
get(target,key){
return 'Hello Proxy'
}
});
let obj = Object.create(proxy);
obj.name;//'Hello Proxy'
obj.age;//'Hello Proxy'
//obj本身是沒有這兩個屬性的,但由于繼承了proxy,是以會走到proxy的get方法中,是以不管通路obj的什麼屬性,始終都會傳回'Hello Proxy'
// get方法的第三個參數
let obj = {name:'Yannis'}
let proxy = new Proxy({},{
get(target, key, receiver){
return receiver;
}
});
proxy.name === proxy;//true
//這裡我們在get中直接傳回了第三個參數,當通過proxy執行個體通路對象屬性時,發現對象的屬性跟proxy的執行個體是相等的。這也印證了第三個參數是Proxy執行個體本身這一說法
set(target, key, value)
Proxy的set方法也是比較常用的一個攔截方法。
- set方法主要是用來攔截對象屬性的設定用的,即當我們通過Proxy執行個體給對象屬性指派時會進入到set攔截裡。該方法傳回一個布爾值
- set方法接收4個參數,target:攔截的目标對象,propKey:目标對象的屬性,value:要給目标屬性設定的新值,receiver(可選):Proxy執行個體本身
- set方法大多用于對屬性的合法校驗或者添加一些額外的處理邏輯。
//假如Person對象有個age屬性,那麼年齡應該是一個數字,并且不能太大也不能太小,當使用者輸入年齡的時候我們就可以用set方法來進行攔截校驗
let person = {age: 1}
let proxy = new Proxy(person,{
set(target,key,value){
//隻對age屬性進行處理
if(key === 'age'){
if(!Number.isInteget(value)){
throw new TypeError('The age is not an integer')
}
if(value<=0 || value>150){
throw new RangeError('The age is incorrect')
}
}
target[key] = value;//将新值賦給target的key屬性
return true;
}
})
person.age = 50;//true
person.age='Yannis';//報錯
person.age = 200;//報錯
has(target, key)
has()方法用來攔截HasProperty操作,即判斷對象是否具有某個屬性時,這個方法會生效。典型的操作就是in運算符。
- has方法接收兩個參數:target:目标對象,key:需要查詢的屬性名,傳回值為布爾類型
- has方法攔截的是HasProperty操作而不是HasOwnProperty操作,也就是說has方法不判斷一個屬性是本身的屬性還是繼承來的屬性
- has方法攔截對for…in循環是不生效的
// 隐藏對象的某些屬性不被in發現,比如帶下劃線的屬性
let obj = {
_a:'a',
_b:'b',
c:'c',
d:'d'
}
let proxy = new Proxy(obj,{
has(target,key){
if(key[0] === '_'){
return false
}
return key in target;
}
})
'_a' in proxy;//false
'_b' in proxy;//false
'c' in proxy;//true
'd' in proxy;//true
ownKeys(target)
ownKeys方法跟has方法類似也是跟對象屬性操作相關的,但是ownKeys是用來攔截擷取對象屬性的方法。它主要是攔截如下幾個擷取屬性的方法:另外需要注意的是:在使用Object.keys()方法是,有三類屬性會被ownKeys方法自動過濾
- Object.getOwnPropertyNames(proxy)
- Object.getOwnPropertySymbols(proxy)
- Object.keys(proxy)
- for…in循環
- 該方法傳回一個數組。數組的元素為對象所有自身屬性的屬性名,而Object.keys()的傳回結果僅包括目标對象自身的可周遊屬性。
- ownKeys方法隻接收一個參數target,要攔截的目标對象
- 目标對象上不存在的屬性
- 屬性名為Symbol類型的值
- 不可周遊的屬性(enumerable為false)
//還是以隐藏對象的下劃線屬性為例
let obj= {
_a: 'a',
_b: 'b',
c: 'c',
d: 'd'
};
let proxy = new Proxy(obj, {
ownKeys (target) {
return Reflect.ownKeys(target).filter(key => key[0] !== '_');
}
});
for (let key of Object.keys(proxy)) {
console.log(key);
}
// c
// d
deleteProperty(target, propKey)
deleteProperty 方法用于攔截删除屬性的操作,傳回值為布爾類型。如果該方法抛出錯誤或者傳回false,目前屬性就無法被delete指令删除。
- 該方法接收兩個參數target:目标對象和propKey:對象對應的屬性名
//還是以對象的下劃線屬性為例
let obj= {
_a: 'a',
_b: 'b',
c: 'c',
d: 'd'
};
let proxy = new Proxy(obj, {
deleteProperty(target, key) {
if(key[0] === '_'){
throw new Error('Can not delete the private property')
}
delete target[key]
return true;
}
});
delete proxy['c'];// true
delete proxy['_a'];// Error: Can not delete the private property
總結
關于Proxy執行個體一些常用的攔截方法就分享到這裡了,個人認為用到最多的就是get和set的兩個方法了。除了上面分享的這幾個方法外,還有很多攔截方法,感興趣的小夥伴可以結合上篇文章的整理自行探索一下。
喜歡的小夥伴歡迎點贊留言加關注哦!