【js】Proxy学习笔记
这篇文章可以说是MDN Proxy文档的精简版,把所有核心知识点都浓缩提炼出来了。😁😁😁凑不要脸的自夸一下,可能仍有不足,但我加上MDN的链接了。如果表述或者代码有不对的地方,欢迎指正。
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。只能通过 new
关键字来调用,如果不使用 new
关键字调用,则会抛出 TypeError
错误。
语法
const p = new Proxy(target, handler)
参数解释:
- target: 要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
- handler: 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理
p
的行为。 - 示例:
proxyExample() {const obj = {name: 'kk',age: 18}const proxyObj = new Proxy(obj, {get(target, key) {return target[key] || `属性不存在`},set(target, key, value) {target[key] = valuereturn true // 返回 true 表示设置成功}})console.log(proxyObj.name) // 输出: kkconsole.log(proxyObj.age) // 输出: 18proxyObj.age = 20 // 设置属性console.log(proxyObj.age) // 输出: 20 },
方法
- Proxy.revocable():创建一个可撤销的Proxy对象。
proxyRevocableExample() {const obj = { name: 'll', age: 18 }const revocable = Proxy.revocable(obj, {get(target, key) {return target[key] || `属性不存在`},set(target, key, value) {target[key] = valuereturn true // 返回 true 表示设置成功}})console.log(revocable) // 输出: {proxy: Proxy(Object), revoke: ƒ}// 注意使用revocable.proxy设置属性console.log(revocable.proxy.name) // 输出: llrevocable.proxy.name = 'ii' // 设置属性console.log(revocable.proxy.name) // 输出: iirevocable.revoke() // 撤销代理console.log(revocable.proxy.name) // 输出报错,因为代理已被撤销,[vue warn]: Error in mounted hook: "TypeError: Cannot perform 'get' on a proxy that has been revoked" }
console.log(revocable) // 输出: {proxy: Proxy(Object), revoke: ƒ}
- proxy:表示新生成的代理对象本身,和用一般方式 new Proxy(target, handler) 创建的代理对象没什么不同,只是它可以被撤销掉。
- **revoke:**撤销方法,调用的时候不需要加任何参数,就可以撤销掉和它一起生成的那个代理对象。一旦某个代理对象被撤销,它将变得几乎完全不可调用,在它身上执行任何的可代理操作都会抛出 TypeError 异常(注意,可代理操作一共有 14 种,执行这 14 种操作以外的操作不会抛出异常)。一旦被撤销,这个代理对象便不可能被直接恢复到原来的状态,同时和它关联的目标对象以及处理器对象都有可能被垃圾回收掉。再次调用撤销方法 revoke() 则不会有任何效果,但也不会报错。
handler 对象的方法
handler对象 是一个容纳一批特定属性的占位符对象。它包含有 Proxy 的各个捕获器(trap:处理器函数有时候也被称为劫持(trap),这是由于它们会对底层被代理对象的调用进行劫持),它们都是可选的。开发者可以按需覆盖,如果没有被重新定义,仍会按原始对象的默认方式工作,不会报错,也不会被拦截。
handler.getPrototypeOf():
Object.getPrototypeOf 方法的捕捉器。
proxyTrapGetPrototypeOf() {const monster1 = {eyeCount: 4}const monsterPrototype = {eyeCount: 2}const proxy1 = new Proxy(monster1, {getPrototypeOf(target) {// 这里直接返回自定义的原型对象return monsterPrototype //替换了目标对象的真实原型}})console.log(Object.getPrototypeOf(proxy1) === monsterPrototype)// 输出: trueconsole.log(Object.getPrototypeOf(proxy1).eyeCount)// 输出: 2
}
5 种触发 getPrototypeOf 代理方法的方式:
- Object.getPrototypeOf()
- Reflect.getPrototypeOf()
- Object.prototype.proto
- Object.prototype.isPrototypeOf()
- instanceof
proxyTrapGetPrototypeOf2() {var p = new Proxy({},{getPrototypeOf(target) {return Array.prototype}})console.log(Object.getPrototypeOf(p) === Array.prototype) // 输出: trueconsole.log(Reflect.getPrototypeOf(p) === Array.prototype) // 输出: trueconsole.log(p.__proto__ === Array.prototype) // 输出: trueconsole.log(Array.prototype.isPrototypeOf(p)) // 输出: trueconsole.log(p instanceof Array) // 输出: true }
如果违背了以下的约束,proxy 会抛出 TypeError:
- getPrototypeOf() 方法返回的不是对象也不是 null。
- 目标对象是不可扩展的,且 getPrototypeOf() 方法返回的原型不是目标对象本身的原型。
var obj = Object.preventExtensions({}) var p = new Proxy(obj, {getPrototypeOf(target) {return {}} }) Object.getPrototypeOf(p) //报错:TypeError: 'getPrototypeOf' on proxy: proxy target is non-extensible but the trap did not return its actual prototype
handler.setPrototypeOf():
Object.setPrototypeOf 方法的捕捉器。
proxyTrapSetPrototypeOf() {const proxyObj = new Proxy({},{setPrototypeOf(target, proto) {console.log(`Setting prototype to:`, proto)return Reflect.setPrototypeOf(target, proto) // 设置原型}})Object.setPrototypeOf(proxyObj, Array.prototype) // 设置原型为 Array.prototypeconsole.log(Object.getPrototypeOf(proxyObj) === Array.prototype) // 输出: true
}
该方法会拦截目标对象的以下操作:
- Object.setPrototypeOf()
- Reflect.setPrototypeOf()
如果违背了以下的约束,proxy 会抛出 TypeError:
- 如果 target不可扩展,原型参数必须与Object.getPrototypeOf(target)值相同。
handler.isExtensible():
Object.isExtensible 方法的捕捉器。
proxyTrapIsExtensible() {const proxyObj = new Proxy({}, {isExtensible(target) {return Reflect.isExtensible(target) // 返回目标对象的可扩展性},preventExtensions(target) {console.log('Preventing extensions on target')return Reflect.preventExtensions(target) // 阻止扩展}})console.log(Object.isExtensible(proxyObj)) // 输出: trueObject.preventExtensions(proxyObj) // 阻止扩展console.log(Object.isExtensible(proxyObj)) // 输出: false
}
该方法会拦截目标对象的以下操作:
- Object.isExtensible()
- Reflect.isExtensible()
如果违背了以下的约束,proxy 会抛出 TypeError:
- Object.isExtensible(proxy) 必须同 Object.isExtensible(target) 返回相同值,即当目标对象可扩展时,isExtensible 必须返回 true;当目标对象不可扩展时,isExtensible 陷阱必须返回 false。
var p = new Proxy({},{isExtensible: function (target) {return false // return 0; return NaN 等都会报错} }) Object.isExtensible(p) //输出报错:TypeError: 'isExtensible' on proxy: trap result does not reflect extensibility of proxy target (which is 'true')
handler.preventExtensions():
Object.preventExtensions 方法的捕捉器。
proxyTrapPreventExtensions() {const target = {isExtensible: true}const proxyObj = new Proxy(target, {preventExtensions(target) {target.isExtensible = falseObject.preventExtensions(target)return true}})console.log(target.isExtensible) // 输出: trueObject.preventExtensions(proxyObj) // 阻止扩展console.log(target.isExtensible) // 输出: falseconsole.log(Object.isExtensible(proxyObj)) // 输出: falseconsole.log(Object.isExtensible(target)) // 输出: false
}
该方法会拦截目标对象的以下操作:
- Object.preventExtensions()
- Reflect.preventExtensions()
如果违背了以下的约束,proxy 会抛出 TypeError:
- 如果目标对象是可扩展的,那么只能返回 false
var p = new Proxy({},{preventExtensions: function (target) {return true}} ) Object.preventExtensions(p) // 输出报错:TypeError: 'preventExtensions' on proxy: trap returned truish but the proxy target is extensible
handler.getOwnPropertyDescriptor():
Object.getOwnPropertyDescriptor 方法的捕捉器。
proxyTrapGetOwnPropertyDescriptor() {const proxyObj = new Proxy({name: 'kk',age: 18},{getOwnPropertyDescriptor: (target, key) =>Reflect.getOwnPropertyDescriptor(target, key)})console.log(Object.getOwnPropertyDescriptor(proxyObj, 'name'))// 输出: { value: 'kk', writable: true, enumerable: true, configurable: true }
}
该方法会拦截目标对象的以下操作:
- Object.getOwnPropertyDescriptor()
- Reflect.getOwnPropertyDescriptor()
如果违背了以下的约束,proxy 会抛出 TypeError:
- getOwnPropertyDescriptor 必须返回一个 object 或 undefined。
- 如果属性作为目标对象的不可配置的属性存在,则该属性无法报告为不存在。
- 含义: 目标对象身上真的有一个 configurable: false 的属性 x,你就不能在 getOwnPropertyDescriptor() 里返回 undefined(假装没有)。
- 示例:
const target = {}; Object.defineProperty(target, 'x', { value: 1, configurable: false });const proxy = new Proxy(target, {getOwnPropertyDescriptor(t, prop) {if (prop === 'x') return undefined; // ❌ 撒谎} });Object.getOwnPropertyDescriptor(proxy, 'x'); // 输出报错:TypeError: 'getOwnPropertyDescriptor' on proxy: trap returned undefined for property 'x' which is non-configurable in the proxy target
- 如果属性作为目标对象的属性存在,并且目标对象不可扩展,则该属性无法报告为不存在。
- 含义: 一旦目标被
Object.preventExtensions()
锁定,所有已经存在的自有属性都必须能被查到;返回undefined
就报错。 - 示例:
const target = { y: 2 }; Object.preventExtensions(target);const proxy = new Proxy(target, {getOwnPropertyDescriptor(t, prop) {if (prop === 'y') return undefined; // ❌ 撒谎} });Object.getOwnPropertyDescriptor(proxy, 'y'); // 输出报错:TypeError: 'getOwnPropertyDescriptor' on proxy: trap returned undefined for property 'y' which exists in the non-extensible proxy target
- 含义: 一旦目标被
- 如果属性不存在作为目标对象的属性,并且目标对象不可扩展,则不能将其报告为存在。
- 含义: 目标被冻结后,代理就不能再“伪造”一个原本不存在的属性;否则抛异常。
- 示例:
const target = {}; Object.preventExtensions(target); const proxy = new Proxy(target, {getOwnPropertyDescriptor(t, prop) {if (prop === 'z') return { value: 99, configurable: true }; // ❌ 伪造} }); Object.getOwnPropertyDescriptor(proxy, 'z'); // 输出报错:TypeError: 'getOwnPropertyDescriptor' on proxy: trap returned descriptor for property 'z' that is incompatible with the existing property in the proxy target
- 属性不能被报告为不可配置,如果它不作为目标对象的自身属性存在,或者作为目标对象的可配置的属性存在。
- 含义: 你返回的描述符里
{ configurable: false }
必须“有根有据”,只有目标对象里真的有一个对应且原本就是configurable: false
的属性时,你才能这么写。否则属于“伪造不可配置”,抛错。 - 示例(伪造不可配置):
const target = { w: 3 }; // w 默认 configurable: true const proxy = new Proxy(target, {getOwnPropertyDescriptor(t, prop) {if (prop === 'w') return { value: 3, configurable: false }; // ❌ 撒谎} });Object.getOwnPropertyDescriptor(proxy, 'w'); // 输出报错:peError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property 'w' which is either non-existent or configurable in the proxy target
- 含义: 你返回的描述符里
- Object.getOwnPropertyDescriptor(target)的结果可以使用 Object.defineProperty 应用于目标对象,也不会抛出异常。
- 含义:
你返回的描述符必须是合法且完整的:- 如果返回了存取器描述符 { get: …, set: … },这两个函数必须真正可调用;
- 如果返回了数据描述符 { value, writable, … },这些字段必须能被 defineProperty 接受。
否则同样抛 TypeError。
- 示例:
const target = {}; const proxy = new Proxy(target, {getOwnPropertyDescriptor(t, prop) {// ❌ 返回了一个不可用的 getter:不是函数if (prop === 'bad') {return { get: 123, enumerable: true, configurable: true };}} });Object.getOwnPropertyDescriptor(proxy, 'bad'); // 输出报错:TypeError: Getter must be a function: 123
- 含义:
handler.defineProperty():
Object.defineProperty 方法的捕捉器。
默认情况下,使用 Object.defineProperty() 添加的属性是不可写、不可枚举和不可配置的。
proxyTrapDefineProperty() {var p = new Proxy({},{defineProperty(target, prop, descriptor) {console.log(descriptor) //输出:{value: 'proxy'}return Reflect.defineProperty(target, prop, descriptor)}})Object.defineProperty(p, 'name', {value: 'proxy',type: 'custom'})console.log(p.name) // 输出:proxyconsole.log(Object.getOwnPropertyDescriptor(p, 'name')) //输出:{value: 'proxy', writable: false, enumerable: false, configurable: false}console.log(p) // 输出:Proxy(Object) {name: 'proxy'}
}
当调用 Object.defineProperty() 或者 Reflect.defineProperty(),传递给 defineProperty 的 descriptor 有一个限制 - 只有以下属性才有用,非标准的属性将会被无视:
- enumerable
- configurable
- writable
- value
- get
- set
该方法会拦截目标对象的以下操作:
- Object.defineProperty()
- Reflect.defineProperty()
- proxy.property=‘value’
如果违背了以下的约束,proxy 会抛出 TypeError:
- 如果目标对象不可扩展,将不能添加属性。
- 不能添加或者修改一个属性为不可配置的,如果它不作为一个目标对象的不可配置的属性存在的话。
- 如果目标对象存在一个对应的可配置属性,这个属性可能不会是不可配置的。
- 如果一个属性在目标对象中存在对应的属性,那么
Object.defineProperty(target, prop, descriptor)
将不会抛出异常。 - 在严格模式下,
false
作为handler.defineProperty
方法的返回值的话将会抛出 TypeError 异常。
handler.has():
in 操作符的捕捉器。
proxyTrapHas() {const proxyObj = new Proxy({ name: 'kk', age: undefined, height: null },{has(target, key) {return key in target // 返回 true 或 false}})console.log('name' in proxyObj) // 输出: trueconsole.log('age' in proxyObj) // 输出: trueconsole.log('height' in proxyObj) // 输出: trueconsole.log('weight' in proxyObj) // 输出: false
}
该方法会拦截目标对象的以下操作:
- 属性查询:
foo in proxy
- 继承属性查询:
foo in Object.create(proxy)
- with 检查:
with(proxy) { (foo); }
function proxyTrapHas2() {const proxyObj = new Proxy({ name: 'kk' },{has(target, key) {return key in target // 返回 true 或 false}})with (proxyObj) {console.log('name' in proxyObj) // 输出: trueconsole.log('age' in proxyObj) // 输出: false} }
Reflect.has()
如果违背了以下的约束,proxy 会抛出 TypeError:
- 如果目标对象的某一属性本身不可被配置,则该属性不能够被代理隐藏。
- 如果目标对象为不可扩展对象,则该对象的属性不能够被代理隐藏。
var obj = { a: 10 } Object.preventExtensions(obj) var p = new Proxy(obj, {has: function (target, prop) {return false} }) 'a' in p // 输出报错:TypeError: 'has' on proxy: trap returned falsish for property 'a' but the proxy target is not extensible
handler.get():
属性读取操作的捕捉器。
proxyTrapGet() {const proxyObj = new Proxy({ a: 10 },{get(target, key) {console.log(`Accessing property: ${key}`)return target[key] || `属性不存在`}})console.log(proxyObj.a) // 输出: 10console.log(proxyObj.b) // 输出: 属性不存在
}
如果违背了以下的约束,proxy 会抛出 TypeError:
- 如果要访问的目标属性是不可写且不可配置的,则返回的值必须与该目标属性的值相同。
proxyTrapGet() {const obj = {}Object.defineProperty(obj, 'a', {configurable: false,enumerable: false,writable: false,value: '1'})const proxyObj = new Proxy(obj, {get(target, key) {console.log(`Accessing property: ${key}`) // 输出: Accessing property: age, name1return 101}})console.log(proxyObj.a)// 输出报错: mounted hook: "TypeError: 'get' on proxy: property 'a' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected '1' but got '101')" }
- 如果要访问的目标属性没有配置访问方法,即 get 方法是 undefined 的,则返回值必须为 undefined。
const target = {} Object.defineProperty(target, 'secret', {set(v) {},get: undefined, // 没有 getter → [[Get]] 为 undefinedconfigurable: false //必须为 false,否则不会抛出错误,直接返回proxy get设置的值 }) const proxy = new Proxy(target, {get(t, prop, receiver) {return 'fake-value' // 返回一个假的值} }) console.log(proxy.secret) // 输出报错: TypeError: 'get' on proxy: property 'secret' is a non-configurable accessor property on the proxy target and does not have a getter function, but the trap did not return 'undefined' (got 'fake-value')
handler.set():
属性设置操作的捕捉器。
proxyTrapSet() {const proxy1 = new Proxy({ eyeCount: 4 },{set(target, prop, value, receiver) {if (prop === 'eyeCount' && value % 2 !== 0) {console.log('Monsters must have an even number of eyes')return true // 重要,必须返回布尔值,表示设置是否成功} else {return Reflect.set(target, prop, value, receiver)}}})proxy1.eyeCount = 1console.log(proxy1.eyeCount) //输出:4proxy1.eyeCount = 2console.log(proxy1.eyeCount) //输出:2
}
set() 方法应当返回一个布尔值。
- 返回 true 代表属性设置成功。
- 在严格模式下,如果 set() 方法返回 false,那么会抛出一个 TypeError 异常。
该方法会拦截目标对象的以下操作:
- 指定属性值:proxy[foo] = bar 和 proxy.foo = bar
- 指定继承者的属性值:Object.create(proxy)[foo] = bar
- Reflect.set()
如果违背了以下的约束,proxy 会抛出 TypeError:
- 若目标属性是一个不可写且不可配置的数据属性,则不能改变它的值。
const target = {} Object.defineProperty(target, 'id', {value: 42,writable: false,configurable: false // 永久只读 }) const proxy = new Proxy(target, {set(t, prop, val) {// 无论返回 false 还是强行 Reflect.set// 引擎都会检测到冲突并抛 TypeErrorreturn Reflect.set(t, prop, val) // 这里会返回 false} }) proxy.id = 99 // 输出报错: TypeError: 'set' on proxy: trap returned falsish for property 'id'
- 如果目标属性没有配置存储方法,即 [[Set]] 属性的是 undefined,则不能设置它的值。
const target = {_name: 'Tom'
}
// 仅定义 getter,没有 setter
Object.defineProperty(target, 'name', {get() {return this._name},set: undefined // 显式声明无 setter
})
const proxy = new Proxy(target, {set(t, prop, val) {return Reflect.set(t, prop, val) // 会返回 false}
})
proxy.name = 'Jerry'
// 输出报错: TypeError: 'set' on proxy: trap returned falsish for property 'name'
- 在严格模式下,如果 set() 方法返回 false,那么也会抛出一个 TypeError 异常。
handler.deleteProperty():
delete 操作符的捕捉器。
proxyTrapDeleteProperty() {const proxyObj = new Proxy({ name: 'kk', age: 18 },{deleteProperty(target, key) {console.log(`Deleting property: ${key}`) // 输出: Deleting property: age, name1return Reflect.deleteProperty(target, key)}})delete proxyObj.age // 删除 age 属性console.log(proxyObj) // 输出: { name: 'kk' }delete proxyObj.name1 // 删除 name1 属性
}
在JavaScript中,delete操作符具有以下特性:当尝试删除不存在的属性时,不会抛出错误,而是会静默返回true
。所以执行到删除name1
属性时没有报错。
该方法会拦截目标对象的以下操作:
- 删除属性:delete proxy[foo]和delete proxy.foo
- Reflect.deleteProperty()
如果违背了以下的约束,proxy 会抛出 TypeError:
- 如果目标对象的属性是不可配置的,那么该属性不能被删除。
handler.ownKeys():
Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器。
proxyTrapOwnKeys() {const monster1 = {_age: 111,[Symbol('secret')]: 'I am scared!',eyeCount: 4}const handler1 = {ownKeys(target) {return Reflect.ownKeys(target)}}const proxy1 = new Proxy(monster1, handler1)for (const key of Object.keys(proxy1)) {console.log('Object.keys:*******', key) // 输出: _age eyeCount}for (const key of Object.getOwnPropertyNames(proxy1)) {console.log('Object.getOwnPropertyNames:-----', key) // 输出: _age eyeCount}for (const key of Object.getOwnPropertySymbols(proxy1)) {console.log('Object.getOwnPropertySymbols:++++++', key.toString()) // 输出: Symbol(secret)}for (const key in proxy1) {console.log('for...in:******', key.toString()) // 输出: Symbol(secret)}for (const key of Reflect.ownKeys(proxy1)) {console.log('Reflect.ownKeys:-----', key) // 现在会输出: _age, eyeCount, Symbol(secret)}
}
该方法会拦截目标对象的以下操作:
- Object.getOwnPropertyNames()
- Object.getOwnPropertySymbols()
- Object.keys()
- Reflect.ownKeys()
如果违背了以下的约束,proxy 会抛出 TypeError:
- ownKeys 的结果必须是一个数组。
- 数组的元素类型要么是一个 String ,要么是一个 Symbol。
proxyTrapOwnKeys2() {var p = new Proxy({},{ownKeys: function (target) {// 下面的返回类型都会报错return [123, 12.5, true, false, undefined, null, {}, []]}})console.log(Object.getOwnPropertyNames(p))//输出报错:TypeError: 123 is not a valid property name }
- 结果列表必须包含目标对象的所有不可配置(non-configurable)、自有(own)属性的 key.
- 含义: 如果目标对象上有一个属性 x,且它的描述符是 { configurable: false },那么你在 ownKeys() 返回的数组里必须包含 “x”。
- 目的: 防止代理对象“隐藏”目标对象上不可删除的属性,破坏语言一致性。
- 示例:
const target = {}; Object.defineProperty(target, 'x', { value: 1, configurable: false }); const proxy = new Proxy(target, {ownKeys() {return []; // ❌ 漏了不可配置的 'x',会抛 TypeError} }); Object.keys(proxy); // 输出报错:TypeError: 'ownKeys' on proxy: trap result did not include 'x'
- 如果目标对象不可扩展,那么结果列表必须包含目标对象的所有自有(own)属性的 key,不能有其他值。
- 含义: 如果目标对象被 Object.preventExtensions(target) 锁定,不能再添加新属性,那么 ownKeys() 返回的数组必须恰好等于目标对象当前的全部自有属性 key——既不能多也不能少。
- 目的: 保证不可扩展对象的行为一致性,防止代理“伪造”或“隐藏”属性。
- 示例:
const target = { a: 1 }; Object.preventExtensions(target); const proxy = new Proxy(target, {ownKeys() {return ['a', 'b']; // ❌ 多了 'b',会抛 TypeError} }); Object.keys(proxy); // 输出报错:TypeError: 'ownKeys' on proxy: trap returned extra keys but proxy target is non-extensible
handler.apply():
函数调用操作的捕捉器。
proxyTrapApply() {function sum(a, b) {return a + b}const sumProxy = new Proxy(sum, {/** thisArg:被调用时的上下文对象。* args:被调用时的参数数组。*/apply(target, thisArg, args) {console.log(`Applying sum function with args: ${args}`,`thisArg:`,thisArg)// 输出: Applying sum function with args: 1,2 thisArg: undefinedreturn target.apply(thisArg, args) // 调用原函数}})console.log(sumProxy(1, 2)) // 输出: 3
}
该方法会拦截目标对象的以下操作:
- proxy(…args)
- Function.prototype.apply()和Function.prototype.call()
- Reflect.apply()
如果违背了以下的约束,proxy 会抛出 TypeError:
- target必须是可被调用的。 而且,它必须是一个函数对象。
handler.construct():
new 操作符的捕捉器,必须返回一个对象,否则代理将会抛出 TypeError错误。
proxyTrapNew() {function Person(name, age) {this.name = namethis.age = age}const personProxy = new Proxy(Person, {construct(target, args, newTarget) {console.log(`Creating a new person with name: ${args[0]} and age: ${args[1]}`,`newTarget:`,newTarget)// 输出: Creating a new person with name: John and age: 30 newTarget: Proxy(Function) {length: 2, name: 'Person', prototype: {…}}return new target(...args)}})const person = new personProxy('John', 30)console.log(person) // 输出: Person { name: 'John', age: 30 }
}
该方法会拦截目标对象的以下操作:
- new proxy(…args)
- Reflect.construct()
如果违背了以下的约束,proxy 会抛出 TypeError:
- 必须返回一个对象。
var p = new Proxy(function () {}, {construct: function (target, argumentsList, newTarget) {return 1} }) new p() // 输出报错: TypeError:'construct' on proxy: trap returned non-object ('1')
- 代理初始化时,传给它的target必须具有一个有效的构造函数供new操作符调用。
var p = new Proxy({},{construct: function (target, argumentsList, newTarget) {return {}}} ) new p() // 输出报错: TypeError: p is not a constructor
参考
- MDN Proxy