Proxy 对象
Proxy 用来修正某些默许操纵,同等于在言语层面做出修正。所以属于一种元编程(meta programming), 即对编程言语举行编程。字面理解为Proxy代办了某些默许的操纵。
其运用花样以下:
var proxy = new Proxy(target, handler);
target是被代办的目的对象,handler也是个对象,用来定制阻拦行动,内部定义每一个被代办的行动。
注重:
- 假如愿望这个代办有用,需要在 proxy 对象上挪用属性要领,而不是在 target 上挪用
- 假如指定 handler 为空对象,那末获得对象和原对象一样
- 获得的 proxy 是 target 的援用,假如没有代办,在 proxy 上的修正和在 target 上的修正同等
看一个简朴的实例
var proxy = new Proxy({},{
get: function(target, key){
return 35;
}
});
console.log(proxy.time); //35
console.log(proxy.name); //35
console.log(proxy.title); //35
//被代办的对象不管输入什么属性都返回35
实际上,proxy 对象也能够被继续:
var proxy = new Proxy({},{
get: function(target, key){
return 35;
}
});
var obj = Object.create(proxy);
obj.time = 20;
console.log(obj.time); //20
console.log(obj.name); //35
感受一下它的威力:
var obj = new Proxy({}, {
get: function(target, key, receiver){
console.log(`getting ${key} ...`);
return Reflect.get(target, key, receiver);
},
set: function(target, key, value, receiver){
console.log(`setting ${key} ...`);
return Reflect.set(target, key, value, receiver);
}
});
obj.count = 1; //setting count ...
++obj.count; //getting count ...
//setting count ...
console.log(obj.count); //getting count ...
//2
能够看出来,handler对象中 get 要领示意属性的接见要求,set 要领示意属性的写入要求。
固然不单单议 get 和 set, 我们能够定义以下阻拦函数:
- get(target, propKey, receiver = target)
阻拦对象的读取属性。当 target 对象设置了 propKey 属性的 get 函数时,receiver 绑定 get 函数的 this。返回值恣意
- set(target, propKey, value, receiver = target)
阻拦对象的写入属性。返回一个布尔值
- has(target, propKey)
阻拦 propKey in proxy 操纵符,返回一个布尔值
- deleteProperty(target, propKey)
阻拦 delete proxy[propKey] 操纵符,返回一个布尔值
- enumerate(target)
阻拦 for(let i in proxy) 遍历器,返回一个遍历器
- hasOwn(target, propKey)
阻拦 proxy.hasOwnProperty(‘foo’),返回一个布尔值
- ownKeys(target)
阻拦 Object.getOwnPropertyNames(proxy), Object.getOwnPropertySymbols(proxy), Object.keys(proxy),返回一个数组。该要领返回对象一切本身属性,包含不可遍历属性,不包含 Symble属性,然则Object.keys(proxy)
不应该包含不可遍历属性
- getOwnPropertyDescriptor(target, propKey)
阻拦 Object.getOwnPropertyDescriptor(proxy, propKey),返回其属性描述符
- defineProperty(target, propKey, propDesc)
阻拦 Object.defineProperty(proxy, propKey, propDesc), Object.defineProperties(proxy, propDesc),返回一个布尔值
- preventExtensions(target)
阻拦 Object.preventExtensions(proxy),返回一个布尔值
- getPrototypeOf(target)
阻拦 Object.getPrototypeOf(proxy),返回一个对象
- isExtensible(target)
阻拦 Object.isExtensible(proxy),返回一个布尔值
- setPrototypeOf(target, proto)
阻拦 Object.setPrototypeOf(proxy, proto),返回一个布尔值
- apply(target, object, args)
阻拦对 proxy 实例的函数操纵,包含 proxy(…args),proxy.call(object, …args),proxy.apply(object, args)
- construct(target, args, proxy)
阻拦用 new 挪用 proxy 函数的操纵,construct()返回的不是对象会报错
以下枚举一些 Proxy 的实例
接见对象不存在的属性报错
var obj = new Proxy({}, {
get: function(target, key){
if(key in target){
return Reflect.get(target, key);
} else {
throw new ReferenceError(`"${key}" is not in object`);
}
}
});
obj.look = "picture";
console.log(obj.look); //"picture"
console.log(obj.sleep); //ReferenceError: "sleep" is not in object
数组索引为负时返回倒数位置的值
var origin = [10,20];
var arr = new Proxy(origin, {
get(target, key){
let index = parseInt(key);
if(index < 0){
index = target.length + index;
if(index < 0) return undefined;
}
return Reflect.get(target, index);
}
});
console.log(arr[0]); //10
console.log(arr[1]); //20
console.log(arr[2]); //undefined
console.log(arr[-1]); //20
console.log(arr[-4]); //undefined
庇护对象内以 “_” 开首的属性为私有属性:
var o = {
"_name": "Bob",
"age": 13,
"_fun": function(){
console.log("_fun is called");
}
};
var obj = new Proxy(o, {
get(target, key){
if(key.charAt(0) === '_'){
return undefined;
}
return Reflect.get(target, key);
},
set(target, key, value){
if(key.charAt(0) === '_'){
throw new Error('Cannot define a property begin with "_"');
}
return Reflect.set(target, key, value);
},
has(target,key){
if(key.charAt(0) === '_'){
return false;
}
return Reflect.has(target, key);
},
deleteProperty(target,key){
if(key.charAt(0) === '_'){
return false;
} else {
Reflect.deleteProperty(..arguments);
}
},
apply(target,ctx,args){
if(target.name.charAt(0) === '_'){
throw new TypeError(`${target.name} is not defined`);
} else {
Reflect apply(...arguments);
}
},
defineProperty(target,key,desc){
if(key.charAt(0) === '_'){
return new Error(`cannot define property begin with "_"`);
} else {
Reflect.defineProperty(..arguments);
}
},
setPrototypeOf(target,proto){
throw new TypeError(`Cannot change the proto of ${target}`);
},
construct(target,ctx,args){
if(target.name.charAt(0) === '_'){
throw new TypeError(`${target.name} is not defined`);
} else {
Reflect construct(...arguments);
}
}
});
console.log(obj.age); //13
obj.age = 20;
console.log(obj.age); //20
console.log(obj._name); //undefined
obj._hobby = "Coding"; //Error: Cannot define a property begin with "_"
_name in key //false
delete obj._name;
Object.defineProperty(obj,"_hobby",{
value: "Coding"
});
Object.defineProperties(obj,{
'_hobby': {
value: "Coding"
}
});
obj._fun();
var a = new obj._fun();
obj.__proto__ = {}; //Cannot define a property begin with "_"
Object.setPrototypeOf(obj,{}) //Cannot change the proto of obj
固然不是一切 proxy 代办都不可作废,下面要领设置的代办是能够经由过程定义代办时返回的revoke函数作废:
var a = {
name:"Bob"
};
var {proxy, revoke} = Proxy.revocable(a, {
get(target,key){
return undefined;
}
});
proxy.name; //undefined;
revoke();
proxy.name; //TypeError: Cannot perform 'get' on a proxy that has been revoked
Reflect 对象
Reflect 对象有一下作用:
- 将 Object对象的一些显著属于言语层面的要领布置在 Reflect 上
- 修正某些 Object 对象的要领使其更合理。比方
Object.defineProperty
碰到没法定义属性时会抛出毛病,而Reflect.defineProperty
会返回 false - 把所以 object 的操纵都替代成函数行动,比方用
Reflect.has(obj,name)
替代name in obj
- 保证只如果 Proxy 有的要领就肯定能够在 Reflect 上找到雷同的要领,如许能够在完成 proxy 时轻易的完成默许行动。换言之,不管 proxy 怎样修正默许行动,你总能够在 Reflect 上找到真正默许的行动
代办在增加分外的功用时,应用 Reflect 保证了原始功用的完成。举个例子:
var loggedObj = new Proxy({}, {
get(target,propKey){
console.log(`getting ${target}.${propKey}`); //固然你最好把操纵记录到一个 log 中
return Reflect.get(target,propKey);
}
});
Reflect有以下要领:
- Reflect.getOwnPropertyDescriptor(target, propKey)
同等于 ObjectgetOwnPropertyDescriptor(target, propKey)
- Reflect.defineProperty(target,propKey,desc)
同等于 Object.defineProperty(target,propKey,desc)
- Reflect.getOwnPropertyNames(target)
同等于 Object.getOwnPropertyNames(target)
- Reflect.getPrototypeOf(target)
同等于 Object.getPrototypeOf(target)
- Reflect.setPrototypeOf(target, proto)
同等于 Object.setPrototypeOf(target, proto)
- Reflect.deleteProperty(target, propKey)
同等于 delete target.propKey
- Reflect.enumerate(target)
同等于 for ... in target
- Reflect.freeze(target)
同等于 Object.freeze(target)
- Reflect.seal(target)
同等于 Object.seal(target)
- Reflect.preventExtensions(target)
同等于 Object.preventExtensions(target)
- Reflect.isFrozen(target)
同等于 Object.isFrozen(target)
- Reflect.isSealed(target)
同等于 Object.isSealed(target)
- Reflect.isExtensible(target)
同等于 Object.isExtensible(target)
- Reflect.has(target, propKey)
同等于 propkey in object
- Reflect.hasOwn(target, propKey)
同等于 target.hasOwnProperty(propKey)
- Reflect.ownKeys(target)
遍历获得target本身一切属性,包含不可枚举属性,不包含 Symbol 属性
- Reflect.get(target,propKey, receiver = target)
假如 propKey 是个读取器,则读取器中的 this 绑定到 receiver
var per = {
bar: function(){console.log("per-bar")}
}
var obj = {
get foo(){ this.bar(); },
bar: function (){console.log("obj-bar")}
};
Reflect.get(obj, "foo", per); //"per-bar"
- Reflect.set(target,propKey, value, receiver = target)
假如 propKey 是个读取器,则读取器中的 this 绑定到 receiver
- Reflect.apply(target, thisArg, args)
同等于 Function.prototype.apply.call(target, thisArg, args)
即 thisArg.target(args)
- Reflect.construct(target,args)
同等于 new target(...args)
注重以上要领中,Reflect.set()
, Reflect.defineProperty()
, Reflect.freeze()
, Reflect.seal()
, Reflect.preventExtensions()
在胜利时返回 true, 失利时返回 false。对应的 Object 要领失利时会抛出毛病。