proxy学习笔记整理

    技术2026-08-03  3

    proxy(代理)亦可理解为发言代表

    syntax: const proxy = new Proxy(target, handle) 释义:proxy是生成的发言代表,target是需要被代表发言的对象,handle是发言代表需要遵守的规则,也是一个对象。

    先抛一个小例子,热热身:

    const obj = {a:1} const handle = { get: function(target, propKey){ return '我就不告诉你!' } } const proxy = new Proxy(obj, handle) proxy.a // "我就不告诉你!" obj.a // 1

    看,proxy(代理)可坏了,它得知并拦截了你访问obj的操作(get),还不好好回答你问题!当你见不到obj本人时,你从proxy那获取到的obj信息,其实是proxy的handle胡诌的答案,并不一定真实、有效!

    参考阮一峰的《ES6入门》,代理能够拦截的操作有以下13种:

    1. get(target, propKey, receiver)

    拦截的操作:对象属性的读取,比如proxy.foo和proxy[‘foo’]; 参数释义: target——目标对象 propKey——属性名 receiver——【可选】操作行为所针对的对象。①如果是你通过代理访问target的属性,那么receiver就指向代理;②如果你是以代理为原型新生成了一个对象,则receiver指向该对象。 返回值:想return啥return啥~

    示例,这里阮一峰举了三个很好的例子(其实例子有好几个,但是复杂点的就3个),我就不献丑了~

    注*: 如果一个属性不可配置(configurable)且不可写(writable),则 Proxy 不能修改该属性的get操作,否则通过 Proxy 对象访问该属性会报错。

    2. set(target, propKey, value, receiver)

    拦截的操作:对象属性的设置,比如proxy.foo = v或proxy[‘foo’] = v; 参数释义: target——目标对象 propKey——属性名 value——属性值 receiver——【可选】操作行为所针对的对象。 返回值:布尔值。

    注*:①如果目标对象自身的某个属性,不可写且不可配置,那么set方法将不起作用;②严格模式下,set代理如果没有返回true,就会报错

    3. has(target, propKey)

    拦截的操作:propKey in proxy的操作; 参数释义: target——目标对象 propKey——需查询的属性名 返回值:布尔值。

    注*: ①如果原对象不可配置或者禁止扩展,这时has拦截会报错; ②has方法拦截的是HasProperty操作,而不是HasOwnProperty操作,即has方法不判断一个属性是对象自身的属性,还是继承的属性; ③has拦截对for…in循环不生效;

    4. deleteProperty(target, propKey)

    拦截的操作:delete proxy[propKey]的操作; 参数释义: target——目标对象 propKey——目标对象的属性名 返回值:布尔值。

    注*: ①如果这个方法抛出错误或者返回false,当前属性就无法被delete命令删除; ②目标对象自身的不可配置(configurable)的属性,不能被deleteProperty方法删除,否则报错。

    5. ownKeys(target)

    拦截的操作:对象自身属性的读取操作。如: ①Object.getOwnPropertyNames(proxy) ②Object.getOwnPropertySymbols(proxy) ③Object.keys(proxy) ④for...in循环 返回值:一个数组(数组成员,只能是字符串或 Symbol 值)。该方法返回目标对象所有自身的属性的属性名,而Object.keys(proxy)的返回结果仅包括目标对象自身的可遍历属性。

    看这个例子: p和target都不包含a,b,c三个属性,但三种拦截方式的返回值都不同(Object.getOwnPropertyNames(proxy)是return啥,它就返回啥;for…in和Object.keys(proxy)则是在return里面找本身确实有的属性返回)

    注*: ①使用Object.keys()方法时,有三类属性会被ownKeys()方法自动过滤,不会返回。

    目标对象上不存在的属性属性名为 Symbol 值不可遍历(enumerable)的属性

    ②如果目标对象自身包含不可配置的属性,则该属性必须被ownKeys()方法返回,否则报错; ③如果目标对象是不可扩展的(non-extensible),这时ownKeys()方法返回的数组之中,必须包含原对象的所有属性,且不能包含多余的属性,否则报错。

    6. getOwnPropertyDescriptor(target, propKey)

    拦截的操作:Object.getOwnPropertyDescriptor(proxy, propKey); 返回值:proxy的propKey属性的描述对象。

    7. defineProperty(target, propKey, propDesc)

    拦截的操作: ①Object.defineProperty(proxy, propKey, propDesc) ②Object.defineProperties(proxy, propDescs) 参数释义: target——目标对象 propKey——目标对象的属性名 propDesc——目标对象属性的描述器 返回值:布尔值。

    注*: ①如果目标对象不可扩展(non-extensible),则defineProperty()不能增加目标对象上不存在的属性,否则会报错; ②如果目标对象的某个属性不可写(writable)或不可配置(configurable),则defineProperty()方法不得改变这两个设置。

    8. preventExtensions(target)

    拦截的操作:Object.preventExtensions(proxy); 返回值:必须返回一个布尔值,否则会被自动转为布尔值。

    注*:该方法有一个限制,只有目标对象不可扩展时(即Object.isExtensible(proxy)为false),proxy.preventExtensions才能返回true,否则会报错。

    9. getPrototypeOf(target)

    拦截的操作: ①Object.prototype.__proto__ ②Object.prototype.isPrototypeOf() ③Object.getPrototypeOf() ④Reflect.getPrototypeOf() ⑤instanceof 返回值:一个对象或者null。

    注*:如果目标对象不可扩展(non-extensible), getPrototypeOf()方法必须返回目标对象的原型对象。

    10. isExtensible(target)

    拦截的操作:Object.isExtensible(proxy); 返回值:只能返回布尔值,否则返回值会被自动转为布尔值。

    注*:该方法有一个强限制:返回值必须与目标对象的isExtensible属性保持一致,否则就会抛出错误(即不能谎报军情)。

    11. setPrototypeOf(target, proto)

    拦截的操作:Object.setPrototypeOf(proxy, proto); 返回值:布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截(见12、13)。

    注*:如果目标对象不可扩展(non-extensible),setPrototypeOf()方法不得改变目标对象的原型。

    12. apply(target, object, args)

    拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。

    参数释义: target——目标对象 object——目标对象的上下文对象(this) args——目标对象的参数数组

    13. construct(target, args, newTarget)

    拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(…args)。 参数释义: target:目标对象 args:构造函数的参数对象 newTarget:new命令作用的构造函数 返回值:必须是一个对象,否则会报错。


    从这开始,不是proxy拦截的操作了!

    Proxy.revocable()

    Proxy.revocable()方法返回一个可取消的 Proxy 实例。

    let target = {}; let handler = {}; let {proxy, revoke} = Proxy.revocable(target, handler); proxy.foo = 123; proxy.foo // 123 revoke(); proxy.foo // TypeError: Revoked

    使用场景:目标对象不允许直接访问,必须通过代理访问,一旦访问结束,就收回代理权,不允许再次访问。

    还有以下this指向问题,导致的proxy和target表现不一致的问题,以及proxy在对象拦截方面的潜力,请自行看阮一峰的书或是查资料(Vue3.0数据响应)~

    此致

    Processed: 0.014, SQL: 9