ES6:プロキシについてどのくらい知っていますか?
概要概要
- プロキシは、特定の操作のデフォルトの動作を変更するために使用されます。これは、言語レベルで変更を加えることと同じであるため、一種の「メタプログラミング」、つまりプログラミング言語のプログラミングに属します。
- プロキシは、ターゲットオブジェクトの前にインターセプトのレイヤーを設定することとして理解できます。オブジェクトへの外部アクセスはすべてこのレイヤーによってインターセプトされる必要があるため、外部アクセスをインターセプトまたはフィルタリングするメカニズムを提供します。
インスタンスメソッド
1.get()
- getメソッドは、属性の読み取り操作をインターセプトするために使用されます。
let person = {
name : '张三'
}
let proxy = new Proxy(person,{
get : function(target,property){
if(property in target){
return target[property];
}else{
throw new Error('property ' + property + ' no found!')
}
}
})
proxy.name; //'张三'
proxy.age; //property age no found!
上記の例では、オブジェクトにない属性ageを取得するとエラーがスローされます。プロキシを通過しない場合は、undefinedが返されます。
- getメソッドは継承できます
let proto = new Proxy({
},{
get(target,propertykey,receiver){
console.log('get '+ propertykey);
return target[propertykey];
}
});
let obj = Object.create(proto);
obj.lalala; //get lalala
- Proxyオブジェクトを使用すると、属性の読み取り操作を変更して特定の関数を実行し、関数のチェーン操作を実現できます。
let pipe = (function(){
return function(value){
//创建函数执行栈
let funcStack = [];
//创建拦截器
let oproxy = new Proxy({
},{
get: function(pipeObj,fnName){
//当属性为get,返回函数栈一次执行函数后的结果
if(fnName === 'get'){
return funcStack.reduce(function(val,fn){
return fn(val);
},value)
}
//否则将函数置入函数执行栈中,并返回又一个拦截器
else{
funcStack.push(window[fnName]);
return oproxy;
}
}
});
// 将拦截器返回给pipe
return oproxy;
}
}())
let double = n=>n*2;
let pow = n=>n*n;
pipe(2).double.pow.get; //16
2.set()
- setメソッドのユーザーが特定の属性の代入操作をインターセプトする
let ageLimit = {
set : function(obj,prop,val){
if(prop === 'age'){
if(!Number.isInteger(val)){
throw new TypeError('the age must be a integer')
}
if(val > 150 || val < 0){
throw new RangeError('the age must be from 0 to 150')
}
}
obj[prop] = val;
}
}
let person = new Proxy({
},ageLimit);
person.age = 200; //the age must be from 0 to 150;
person.age = 'abc' //the age must be a integer;
person.age = 20; //正常
person.age; // 20;
- ageLimitインターセプターを介して、ユーザーのデータ入力を時間内に検証し、値の指定を確認できます。
- オブジェクトに内部プロパティを設定する場合があります。プロパティ名の最初の文字はアンダースコア「_」です。これは、プロパティに外部からアクセスしたり、外部で使用したりできないことを意味します。getメソッドとsetメソッドを組み合わせると、内部属性が外部によって読み書きされるのを防ぐことができます。
let handler = {
get (target , key){
invariant(key,'get');
return target[key];
},
set (target , key , value){
invatiant(key,'set');
taget[key] = value;
return true;
}
}
function invariant(key,action){
if(key[0] === '_'){
throw new Error('no allowed to ' + action + ' the property');
}
}
let target = {
_name : '张三',
_age : 20
};
let proxy = new Proxy(target,handler);
proxy._name; // no allowed to get the property
proxy._age = 12 // no allowed to set the property
3.apply()
- applyメソッドは、関数呼び出し、呼び出し、および適用操作をインターセプトします
- applyメソッドは、ターゲットオブジェクト、ターゲットオブジェクトのコンテキストのこれ、およびターゲットオブジェクトのパラメータ配列の3つのパラメータを受け取ります。
let target = function(){
console.log('I am the target');
}
let handler = {
apply : function(){
console.log('I am the apply');
}
}
let p = new Proxy(target,handler);
p(); //I am the apply;
4.その他の方法
has(target、propkey)
- ブール値をインターセプト
hasProperty()
、propkey in proxy
操作、および返します。deleteProperty(target、propkey)
delete proxy[propkey]
操作をインターセプトし、ブール値を返します。ownKeys(target)
- 傍受は
Object.getOwnPropertyNarnes(proxy)
、Object.getOwnPropertySyrnbols (proxy)
、Object.keys(proxy)
、配列を返します。このメソッドは、ターゲットオブジェクトのすべての独自のプロパティのプロパティ名を返し、Object.keys()の戻り結果には、ターゲットオブジェクト自体のトラバース可能なプロパティのみが含まれます。getOwnPropertyDescriptor(target、propkey)
- インターセプト
Object.getOwnPropertyDescriptor(proxy, propKey)
、属性の説明オブジェクトを返します。defineProperty(target、propkey)
- インターセプト
Object.defineProperty(proxy, propKey, propDesc)
、およびObject.define Properties(proxy, propDescs)
ブール値を返します。PreventExtensions(ターゲット)
- インターセプト
Object . preventExtensions (proxy)
、ブール値を返します。getPrototypeOf(target)
- インターセプト
Object.getPrototypeOf(proxy)
、オブジェクトを返します。isExtensible(ターゲット)
- インターセプト
Object.isExtensible(proxy)
、ブール値を返します。setPrototypeOf(target)
- インターセプト
Object.setPrototypeOf(proxy,proto)
、ブール値を返します。オブジェクトが関数の場合、インターセプトできる他の2つの操作があります(適用、構築)構築(ターゲット、引数)
- new proxy(... args);などのコンストラクター呼び出しとしてProxyインスタンスの操作をインターセプトします。