1.proxy概述 用于在修改某些操作的默认行为,可理解为在目标之前架设一层拦截器,外界所有的访问都要通过该拦截器,可以对访问做出过滤和改写。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var proxy = new Proxy (target, handler);var obj = new Proxy ({}, { get : function (target, propKey, receiver ) { console .log (`getting ${propKey} !` ); return Reflect .get (target, propKey, receiver); }, set : function (target, propKey, value, receiver ) { console .log (`setting ${propKey} !` ); return Reflect .set (target, propKey, value, receiver); } }); obj.count = 1 ++obj.count
2.proxy拦截操作
get(target, propKey, receiver):拦截对象属性的读取,比如proxy.foo和proxy[‘foo’]。
set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = v或proxy[‘foo’] = v,返回一个布尔值。
has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。
deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。
ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for…in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。
getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
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(…)。
construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(…args)。
3.proxy常用实例方法
get():用于拦截某个属性的读取操作,可接受三个参数。目标对象、属性名、proxy实例本身(可选)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var person = { name : "张三" }; var proxy = new Proxy (person, { get : function (target, propKey ) { if (propKey in target) { return target[propKey]; } else { throw new ReferenceError ("Prop name \"" + propKey + "\" does not exist." ); } } }); proxy.name proxy.age
set():用来拦截某个属性的赋值操作,接收四个参数。目标对象、属性名、属性值、proxy实例本身(可选)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 let validator = { set : function (obj, prop, value ) { if (prop === 'age' ) { if (!Number .isInteger (value)) { throw new TypeError ('The age is not an integer' ); } if (value > 200 ) { throw new RangeError ('The age seems invalid' ); } } obj[prop] = value; return true ; } }; let person = new Proxy ({}, validator);person.age = 100 ; person.age person.age = 'young' person.age = 300
3.apply():拦截函数的调用、call、apply操作,接收三个参数。目标对象、目标对象的上下文对象、目标对象的参数数组。
1 2 3 4 5 6 7 8 9 10 11 12 var twice = { apply (target, ctx, args) { return Reflect .apply (...arguments ) * 2 ; } }; function sum (left, right) { return left + right; }; var proxy = new Proxy (sum, twice);proxy (1 , 2 ) proxy.call (null , 5 , 6 ) proxy.apply (null , [7 , 8 ])
has():拦截HasProperty操作,判断对象是否有某个属性,即in运算符,接收两个参数。目标对象、需查询属性名。has对for in遍历不拦截。
1 2 3 4 5 6 7 8 9 10 11 var handler = { has (target, key) { if (key[0 ] === '_' ) { return false ; } return key in target; } }; var target = { _prop : 'foo' , prop : 'foo' };var proxy = new Proxy (target, handler);'_prop' in proxy
construct():用于拦截new命令,接收三个参数。目标对象、构造函数的参数数组、创造实例参数时,new命令作用的构造函数。注意,construct必须返回一个对象,否则会报错。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const p = new Proxy (function ( ) {}, { construct : function (target, args ) { console .log ('called: ' + args.join (', ' )); return { value : args[0 ] * 10 }; } }); (new p (1 )).value const handler = { construct : function (target, args ) { console .log (this === handler); return new target (...args); } } let p = new Proxy (function ( ) {}, handler);new p ()
deleteProperty():用于拦截delete操作,接收两个参数。目标对象、删除key值。如果方法抛出错误或者返回false说明当前属性无法被delete删除。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var handler = { deleteProperty (target, key) { invariant (key, 'delete' ); delete target[key]; return true ; } }; function invariant (key, action) { if (key[0 ] === '_' ) { throw new Error (`Invalid attempt to ${action} private "${key} " property` ); } } var target = { _prop : 'foo' };var proxy = new Proxy (target, handler);delete proxy._prop