ES6中的Proxy與Reflect
1、Proxy,顧名思義為『代理』,主要為目標對象創建的」代理對象「,用來對目標對象的默認操作進行攔截,值得注意的是,要想使攔截起作用,必須使用「代理對象」來調用這些默認行為。
(1)set(target,prop,val),對對象屬性的賦值操作進行攔截。
(2)get(target,prop),對對象屬性的訪問進行攔截(「.」訪問與表達式訪問)。
(3)deleteProperty(target,prop),攔截刪除對象屬性的操作
(4)ownkeys(target),攔截對象的getOwnPropertyNames操作
(5)has(target,prop),攔截對對象屬性的「in」操作
(6)defineProperty(target,prop,des)攔截對象的Object.defineProperty操作
(7)getOwnPropertyDescriptor(target)攔截對象的Object.getOwnPropertyDescriptor操作
(8)setPrototypeOf(target)攔截對象的Object.setPrototypeOf操作
(9)getPrototypeOf(target)攔截對象的Object.getPrototypeOf操作
(10)apply(target,thisArgs,args),當目標對象是Function時,攔截方法的調用
(11)contruct(target,args),當目標對象是Function時,攔截被new關鍵字調用創建對象
(12)isExtensiable(target)攔截對象的Object.isExtensiable操作,返回值需要與原對象的isExtensiable的返回值保持一致。
(13)preventExtensions(target)攔截對象的Object.preventExtensions操作,當原對象的isExtensiable值為false時,返回值只能為fasle,否則報錯。
2、Reflect,顧名思義為「映射」,提供了與Proxy一一對應的默認行為,可以作為攔截的基礎,當需要對象的默認行為進行擴展時,在Proxy中可以先通過Reflect調用其默認操作,在添加額外的功能,Reflect中的方法改善了Object中的某些方法。
Demo:
//Proxy 主要在執行一些操作之前執行一些攔截,但是執行攔截操作的不是對象本身而是Proxy對象,所以也正如它字面上的意思『代理』
//Proxy對象的構造函數的形式 Proxy(target,handler) 第一參數為要攔截的目標對象,第二個操作為要攔截對象的屬性,和對應的行為
var person = {name:lixuan,age:21};
var handler = {
get(target,prop){//對於獲取屬性的攔截
return prop===name?hello:target[prop];
},
set(target,prop,value){//對於設置屬性值的攔截
target[prop]=prop===age?(value>18?value:18):value;
return true;
},
has(target,prop){//對於是否含有某個屬性的攔截 in 操作
if(prop===age){
console.log(age is hidden!);
return false;
}
return prop in target;
},
getPrototypeOf(target){//攔截Object.getPrototypeOf操作
return {x:1};
},
isExtensible(target){//對於目標對象是否可擴展進行攔截,返回值必須保證和不攔截的時候相等。
console.log(is Extensible!);
return true;
},
ownKeys(target){//對於Object.getOwnPropertyNames的攔截
return [hello,world];
},
setPrototypeOf(target,proto){
throw new Error(Changing the prototype is forbidden);
}
};
var proxy = new Proxy(person,handler);
var fn = function(){};
var proxy_fn = new Proxy(fn,{
apply(target,thisArgs,args){
console.log(this is Proxy);//對於將調用、apply、call時的攔截,目標對象必須是方法
}
});
console.log(proxy.name);//hello 因為之前對獲取屬性的方法進行了攔截,所以返回hello
proxy.age = 12;
console.log(proxy.age);//18 在設置屬性值的時候,進行了攔截,若設置的小於18,則設為18;
proxy_fn();//this is Proxy 對fn方法的調用進行了攔截。
console.log(age in proxy);//age is hidden! false 對判斷是否屬性的操作進行了攔截
console.log(Object.getPrototypeOf(proxy));//{ x: 1 }
console.log(Object.isExtensible(proxy));//is Extensible! true
console.log(Object.getOwnPropertyNames(proxy));//[ hello, world ]
//Object.setPrototypeOf(proxy,{}); //報錯
//Proxy.revocable() 創建一個可取消的Proxy實例 返回值為一個Proxy實例和一個取消方法 我自己當前的編輯器不支持
// var [proxy1,revoke] = Proxy.revocable({name:kermit,age:21},handler);
// console.log(proxy1.age);
//Reflect 主要是將Object上的APIyizhi到Reflect上,以後Object也不會這些方法,也添加和改進了一些原來的方法
//最後Reflect上的行為和Proxy是一一對應的,也就是說Proxy對象中存在的方法,Reflect都有,因此在改變在需要在默認行為中添加額外功能時,
//先調用Reflect中的默認行為,再添加額外的功能,它是Proxy攔截的基礎。
//屬性相關
//獲取屬性的get方法
var lixuan = {name:kermit,age:21}
console.log(Reflect.get(lixuan,name));//kermit
//設置屬性的set方法
Reflect.set(lixuan,name,lixuan);
console.log(Reflect.get(lixuan,name));//lixuan
//刪除屬性的deleteProperty方法
Reflect.deleteProperty(lixuan,age);
console.log(lixuan.age);//undefined
//判斷是否含有某個屬性
console.log(Reflect.has(lixuan,age));//false
//獲取對象的所有屬性
console.log(Reflect.ownKeys(lixuan));//[ name ]
//定義屬性
Reflect.defineProperty(lixuan,sex,{
value:M,
configurable:false
});
console.log(lixuan.sex);//M
//獲取屬性描述符
console.log(Reflect.getOwnPropertyDescriptor(lixuan,sex));
/**
* { value: M,
writable: false,
enumerable: false,
configurable: false }
*/
//原型相關
//設置對象原型
Reflect.setPrototypeOf(lixuan,person);
//獲取對象原型
console.log(Reflect.getPrototypeOf(lixuan));//{ name: lixuan, age: 18 }
//方法有關的
//方法調用
function say(){
console.log(`name:${this.name},age:${this.age}`);
};
Reflect.apply(say,lixuan,[]);//name,lixuan,age:18
//對象相關
//構造方法的調用
function Animal(name){
this.name = name;
}
console.log(Reflect.construct(Animal,[dog]));//Animal { name: dog }
//組織對象擴展(添加新屬性)
Reflect.preventExtensions(lixuan);
//判斷對象是否可擴展
console.log(Reflect.isExtensible(lixuan));//false
以上僅僅是自己對學習的總結,不代表任何觀點。
推薦閱讀: