一、Proxy概述
Proxy用于修改默寫操作的默認(rèn)行為,等同于在語言層面作出修改,所以屬于一種“元編程語言”,既對編程語言進(jìn)行編程。
對于Proxy,我相信大家都非常熟悉了,尤其是對于使用Vue開發(fā)的人來說。雖然大家知道,我這里還是要說一下(多一點字?jǐn)?shù)嗎,哈哈)。說白了,Proxy可以理解成在目標(biāo)對象前架設(shè)一“攔截”層,而外界對該對象訪問的時候都必須經(jīng)過該層攔截,類似過濾器一樣的機(jī)制。Proxy的詞意是代碼,既是代理默寫操作,亦可以理解為“代理器”。
而說到對象攔截器,就不得不說Object.definePropery這個函數(shù),也正是這個屬性,面試中難倒了一大堆同學(xué)。Object.definePropery也有攔截對象的作用,而且只能劫持對象的屬性,對于數(shù)組而言,就需要其他的方式進(jìn)行處理才能實現(xiàn)攔截的作用。而且對于對象的對象,是需要經(jīng)過層層遍歷才可以實現(xiàn)攔截。這是因為這樣,所以才有了Proxy的出現(xiàn),對于Proxy,它是可以完整的劫持整個對象,并且Proxy的有多達(dá)13種劫持操作,因為這些優(yōu)勢,自然而然的,Proxy成了劫持對象的首選。
二、使用
Proxy的第一個P大寫,而我們平時寫的構(gòu)造函數(shù)也是大寫,這就不免讓我們認(rèn)為Proxy是一個構(gòu)造函數(shù)。
var target = {};
var handler = {
get: function(target, property) {
return 23;
}
};
var proxy = new Proxy(target, handler);
console.log(proxy.name); // 23
上面的proxy.name,最終輸出23,證明我們的猜想是正確的,Proxy確實是一個構(gòu)造函數(shù),后來查資料知道了es6原生提供Proxy構(gòu)造函數(shù),用于生成Proxy實例,而且它用法參數(shù)也正如上面寫的一樣,對一個參數(shù)為目標(biāo)對象,而第二個參數(shù)handler,正是我們定義攔擊對象的方法定義。
三、Proxy實例的方法
前面說到了Pxoxy有多達(dá)13種攔截操作,也正是這里所說的實例的方法,下面是Pxoxy實例方法一覽。
get(target, propkey, reveiver)
攔截對象屬性的讀取,如上面的proxy.name,返回類型不限。最后一個參數(shù)receiver屬性很少用到,一般沒用傳遞,它的大致是當(dāng)target對象設(shè)置了propkey屬性的get函時,reveiver對象會綁定get函數(shù)的this對象。
1.set(target, propkey, value, receiver)
攔截對象屬性的設(shè)置,既如我們的proxy.name = 'june'一樣。
2.has(target, propkey)
攔截propkey in proxy的操作,返回一個布爾值。
3.deleteProperty(target, propkey)
攔截delete proxy([propkey])的操作,返回一個布爾值。
4.enumerate(target)
攔截for(var x in proxy),返回一個遍歷器
5.hasOwn(target, propkey)
攔截proxy.hasOwnProperty('name'),返回一個布爾值。
6.ownkeys(target)
攔截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy),返回一個數(shù)組。該方法返回對象所有的自身的屬性,而Object.keys()僅返回對象可遍歷的屬性。
7.getOwnPropertyDescriptor(target, propkey)
攔截Object.getOwnPropertyDescriptor(target,propkey),返回屬性的描述對象。
8.defineProperty(target,propkey,propDesc)
攔截Object.defineProperty(target,propkey,propDesc)、Object.definePropertys(target,propkey,propDesc),返回一個布爾值。
9.preventExtensions(target)
攔截Object.preventExtensions(target),返回一個對象。
10.isExtensible(target)
攔截Object.isExtensible(proxy),返回一個布爾值。
11.setPrototypeOf(target,proto)
攔截Object.setPrototypeOf(proxy,proto),返回一個布爾值。如果目標(biāo)函數(shù)是對象,那么還有兩種操作可以攔截。
12.apply(target,object,args)
攔截Proxy實例作為函數(shù)調(diào)用的操作。
13.construct(target,args,proxy)
攔截Proxy實例作為構(gòu)造函數(shù)調(diào)用的操作。
以上便是Proxy13種實例方法。
而我這里將會例舉一些我們常用的方法出來,比如get,set等。
var target = {};
var handler = {
get: function(target, propkey) {
if(propkey in target) {
return target[propkey]
} else {
throw new ReferenceError(`${propkey} does not exist`);
}
},
set: function(target, propkey, value) {
console.log(`target 對象下的propkey 值是 ${value}`);
target[propkey] = value;
},
construct: function(target, args) {
console.log(`called; ${args.join(',')}`);
},
apply: function() {
console.log('調(diào)用了apply');
return 'proxy';
}
}
var proxy = new Proxy(target, handler);
proxy.name = 'june';
proxy.age = 10;
console.log(proxy.name);
輸入結(jié)果如下
target 對象下的propkey 值是 june
target 對象下的propkey 值是 10
june
而當(dāng)我們將target改成如下的時候
var target = function(a, b) {
return a+b;
}
var proxy = new Proxy(target, handler);
console.log(proxy(10, 20));
輸入結(jié)果為
調(diào)用了apply
proxy
而當(dāng)我們把target定義為一個無返回函數(shù)時,就會打出我們construct函數(shù)里面打印的數(shù)據(jù)。
在這些函數(shù)里,只要我們對target對象做相應(yīng)的修改,就會起到攔截作用。其他攔截方法大同小異,在這里就不一一舉例了。