> 技术文档 > 【js】Proxy学习笔记

【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] = value return true // 返回 true 表示设置成功 } }) console.log(proxyObj.name) // 输出: kk console.log(proxyObj.age) // 输出: 18 proxyObj.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] = value return true // 返回 true 表示设置成功 } }) console.log(revocable) // 输出: {proxy: Proxy(Object), revoke: ƒ} // 注意使用revocable.proxy设置属性 console.log(revocable.proxy.name) // 输出: ll revocable.proxy.name = \'ii\' // 设置属性 console.log(revocable.proxy.name) // 输出: ii revocable.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) // 输出: true console.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) // 输出: true console.log(Reflect.getPrototypeOf(p) === Array.prototype) // 输出: true console.log(p.__proto__ === Array.prototype) // 输出: true console.log(Array.prototype.isPrototypeOf(p)) // 输出: true console.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)) // 输出: true Object.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 = false Object.preventExtensions(target) return true } }) console.log(target.isExtensible) // 输出: true Object.preventExtensions(proxyObj) // 阻止扩展 console.log(target.isExtensible) // 输出: false console.log(Object.isExtensible(proxyObj)) // 输出: false console.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: trueconst 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) // 输出:proxy console.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) // 输出: true console.log(\'age\' in proxyObj) // 输出: true console.log(\'height\' in proxyObj) // 输出: true console.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) // 输出: true console.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, name1 return 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]] 为 undefined configurable: 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 = 1 console.log(proxy1.eyeCount) //输出:4 proxy1.eyeCount = 2 console.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 // 引擎都会检测到冲突并抛 TypeError return 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,没有 setterObject.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, name1 return Reflect.deleteProperty(target, key) } } ) delete proxyObj.age // 删除 age 属性 console.log(proxyObj) // 输出: { name: \'kk\' } delete proxyObj.name1 // 删除 name1 属性}

在JavaScript中,delete操作符具有以下特性:当尝试删除不存在的属性时,不会抛出错误,而是会静默返回true。所以执行到删除name1属性时没有报错。
【js】Proxy学习笔记
该方法会拦截目标对象的以下操作:

  • 删除属性: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) }}

【js】Proxy学习笔记
该方法会拦截目标对象的以下操作:

  • 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: undefined return 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 = name this.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