代理捕获器与反射方法

424 阅读7分钟

有几种不同的JS操作会调用同一个捕获器处理程序。不过,对于在代理对象上执行的任何一种操作,只会有一个捕获处理程序被调用。不会存在重复捕获的情况。

get()

obj.get(property)获取对象属性

get()捕获器会在获取属性值的操作中被调用

对应的反射API方法为Reflect.get()

const myTarget = {};
const proxy = new Proxy(myTarget, {
    get(target, property, receiver) {
        return Relect.get(...arguments);
    }
})
  • 捕获器处理程序参数

    • target:目标对象
    • property:引用的目标对象上的字符串键属性
    • receiver:代理对象或继承代理对象的对象
  • 返回值

    不限

  • 拦截的操作

    • proxy.property
    • proxy[property]
    • Object.create(proxy)[property]
    • Reflect.get(proxy, property, receiver)
  • 捕获器不变式

    如果target.property不可写且不可配置,则处理程序返回的值必须与target.property匹配

    如果target.property不可配置且[[Get]]特性为undefined,处理程序的返回值也必须是undefined

set()

obj.key = val;对象属性赋值

set()捕获器会再设置属性值的操作中被调用

对应的反射API方法为Reflect.set()

const myTarget = {};
const proxy = new Proxy(myTarget, {
    set(target, property, value, receiver) {
        return Reflect.set(...arguments);
    }
})
  • 捕获器处理程序参数

    • target:目标对象
    • property:引用的目标对象的字符串键属性
    • value:要赋给属性的值
    • receiver:接收最初赋值的对象
  • 返回值

    true表示成功; false表示失败,严格模式下会抛出TypeError

  • 拦截的操作

    • proxy.property = value
    • proxy[property] = value
    • Object.create(proxy)[property] = value
    • Reflect.set(proxy, property, value, receiver)
  • 捕获器不变式

    如果target.property不可写且不可配置,则不能修改目标属性的值

    如果target.property不可配置且[[Set]]特性为undefined,则不能修改目标属性的值

    在严格模式下,处理程序中返回false会抛出TypeError

has()

obj.has(property)判断对象中是否有某属性

has()捕获器会在in操作符中被调用

对应的反射API方法为Reflect.has()

const myTarget = {};
const proxy = new Proxy(myTarget, {
    has(target, property) {
        return Reflect.has(...arguments);
    }
})
  • 捕获器处理程序参数

    • target:目标对象
    • property:引用的目标对象上的字符串键属性
  • 返回值

    has()必须返回布尔值,表示属性是否存在。

  • 拦截的操作

    • property in proxy
    • property in Object.create(proxy)
    • with(proxy) {(property)}
    • Reflect.has(proxy, property)
  • 捕获器不变式

    如果target.property存在且不可配置,则处理程序必须返回true

    如果target.property存在且目标对象不可扩展,则处理程序必须返回true

defineProperty()

obj.defineProperty(target, key, {..})为某对象设置属性

此捕获器会在Object.defineProperty()中被调用

对应的反射API方法为Reflect.defineProperty()

const myTarget = {};
const proxy = new Proxy(myTarget, {
    defineProperty(target, property, descriptor) {
        return Reflect.defineProperty(...arguments);
    }
})
Object.defineProperty(proxy, 'foo', { value: 'bar' })
  • 捕获器处理程序参数

    • target:目标对象
    • property:引用的目标对象上的字符串键属性
    • descriptor:包含可选地enumerableconfigurablewritablevaluegetset定义的对象
  • 返回值

    必须返回布尔值,表示属性是否成功定义

  • 拦截的操作

    • Object.defineProperty(proxy, property, descriptor)
    • Reflect.defineProperty(proxy, property, descriptor)
  • 捕获器不变式

    如果目标对象不可扩展,则无法定义属性

    如果目标对象有一个可配置的属性,则不能添加同名的不可配置属性

    如果目标对象有一个不可配置的属性,则不能添加同名的可配置属性

getOwnPropertyDescriptor()

Object.getOwnPropertyDescriptor(obj, property)读取对象中某个属性的特性

getOwnPropertyDescriptor()捕获器会在Object.getOwnPropertyDescriptor()中被调用。

对应的反射API方法为Reflect.getOwnPropertyDescriptor()

const myTarget = {};
const proxy = new Proxy(myTarget, {
    getOwnPropertyDescriptor(target, property) {
        return Reflect.getOwnPropertyDescriptor(...arguments);
    }
});
Object.getOwnPropertyDescriptor(proxy, 'foo');
  • 捕获器处理程序参数

    • target:目标对象
    • property:引用的目标对象上的字符串键属性
  • 返回值

    必须返回对象,或者在属性不存在时返回undefined

  • 拦截的操作

    • Object.getOwnPropertyDescriptor(proxy, property)
    • Reflect.getOwnPropertyDescriptor(proxy, property)
  • 捕获器不变式

    如果自有的target.property存在且不可配置,则处理程序必须返回一个表示该属性存在的对象

    如果自有的target.property存在且可配置,则处理程序必须返回表示该属性可配置的对象

    如果自有的target.property存在且target不可扩展,则处理程序必须返回一个表示该属性存在的对象

    如果target.property不存在且target不可扩展,则处理程序必须返回undefined表示该属性不存在

    如果target.property不存在,则处理程序不能返回表示该属性可配置的对象

deleteProperty()

delete obj.key删除对象中某个属性

deleteProperty()捕获器在delete操作中被调用

对应的反射API方法为Reflect.deleteProperty()

const myTarget = {};
const proxy = new Proxy(myTarget, {
    deleteProperty(target, property) {
        return Reflect.deleteProperty(...arguments);
    }
})
  • 捕获器处理程序参数

    • target:目标对象
    • property: 引用的目标对象上的字符串键属性
  • 返回值

    必须返回布尔值,表示删除属性是否成功。

  • 拦截的操作

    • delete proxy.property
    • delete proxy[property]
    • Reflect.deleteProperty(proxy, property)
  • 捕获器不变式

    如果自有的target.property存在且不可配置,则处理程序不能删除这个属性

ownKeys()

Object.keys(obj)获取对象中自有属性

ownKeys()捕获器在Object.keys()及类似方法中被调用

对应的反射API方法为Reflect.ownKeys()

const myTarget = {};
const proxy = new Proxy(myTarget, {
    ownKeys(target) {
        return Reflect.ownKeys(...arguments);
    }
})
  • 捕获器处理程序参数

    • target:目标对象
  • 返回值

    必须返回包含字符串或符号的可枚举对象

  • 拦截的操作

    • Object.getOwnPropertyNames(proxy)
    • Object.getOwnPropertySymbols(proxy)
    • Object.keys(proxy)
    • Reflect.ownKeys(proxy)
  • 捕获器不变式

    返回的可枚举对象必须包含target的所有不可配置的自有属性

    如果target不可扩展,则返回可枚举对象必须准确的包含自有属性键。

getPrototypeOf()

obj.__proto__获取对象的原型(内部[[Prototype]]属性的值)

getPrototypeOf()捕获器在Object.getPrototypeOf()中被调用。

对应的反射API方法为Reflect.getPrototypeOf()

const myTarget = {};
const proxy = new Proxy(myTarget, {
    getPrototypeOf(target) {
        return Reflect.getPrototypeOf(...arguments);
    }
})
  • 捕获器处理程序参数

    • target:目标对象
  • 返回值

    必须返回对象或null

  • 拦截的操作

    • Object.getPrototypeOf(proxy)
    • Reflect.getPrototypeOf(proxy)
    • proxy.__proto__
    • Object.prototype.isPrototypeOf(proxy)
    • proxy instanceof Object
  • 捕获器不变式

    如果target不可扩展,则Object.getPrototypeOf(proxy) 唯一有效的返回值就是Object.getPrototypeOf(target)的返回值

setPrototypeOf()

Object.setPrototypeOf(obj, prototype)设置对象的原型

setPrototypeOf()捕获器在Object.setPrototypeOf()中被调用。

对应的反射API方法为Reflect.setPrototypeOf()

const myTarget = {};

const proxy = new Proxy(myTarget, {
    setPrototypeOf(target, prototype) {
        return Reflect.setPrototypeOf(...arguments);
    }
})
  • 捕获器处理程序参数

    • target:目标对象
    • prototypetarget的替代原型,如果是顶级原型则为null
  • 返回值

    必须返回布尔值,表示原型赋值是否成功。

  • 拦截的操作

    • Object.setPrototypeOf(proxy)
    • Reflect.setPrototypeOf(proxy)
  • 捕获器不变式

    如果target不可扩展,则唯一有效的prototype参数就是Object.getPrototypeOf(target)的返回值

isExtensible()

Object.isExtensible(obj)判断一个对象是否是可扩展的

isExtensible()捕获器会在Object.isExtensible()中被调用。

对应的反射API方法为Reflect.isExtensible()

const myTarget = {};
const proxy = new proxy(myTarget, {
    isExtensible(target) {
        return Reflect.isExtensible(...arguments);
    }
})
  • 捕获器处理程序参数

    • target:目标对象
  • 返回值

    必须返回布尔值,表示target是否可扩展

  • 拦截的操作

    • Object.isExtensible(proxy)
    • Reflect.isExtensible(proxy)
  • 捕获器不变式

    如果target可扩展,则处理程序必须返回true

    如果target不可扩展,则处理程序必须返回false

preventExtensions()

Object.preventExtensions(obj)让对象变的不可扩展

preventExtensions()捕获器会在Object.preventExtensions()中被调用

对应的反射API方法为Reflect.preventExtensions()

const myTarget = {};
const proxy = new Proxy(myTarget, {
    preventExtensions(target) {
        return Reflect.preventExtensions(...arguments)
    }
})
  • 捕获器处理程序参数

    • target:目标对象
  • 返回值

    必须返回布尔值,表示target是否已经不可扩展

  • 拦截的操作

    • Object.preventExtensions(proxy)
    • Reflect.preventExtensions(proxy)
  • 捕获器不变式

    如果Object.isExtensible(proxy)false,则处理程序必须返回true

apply()

fun.apply(this)修改this指向

apply()捕获器在调用函数时被调用

对应的反射API方法为Reflect.apply()

const myTarget = () => {};
const proxy = new Proxy(myTarget, {
    apply(target, thisArg, ...argumentsList) {
        return Reflect.apply(...arguments);
    }
});
  • 捕获器处理程序参数

    • target:目标对象
    • thisArg:调用函数时的this参数
    • argumentsList: 调用函数时的参数列表
  • 返回值

    无限制

  • 拦截的操作

    • proxy(...argumentsList)
    • Function.prototype.apply(thisArg, argumentsList)
    • Function.prototype.call(thisArg, ...argumentsList)
    • Reflect.apply(target, thisArgument, argumentsList)
  • 捕获器不变式

    target必须是一个函数对象

construct()

const obj = new ConstructorFun()实例化构造函数

construct()捕获器会在new操作符中被调用。

对应的反射API方法为Reflect.construct()

const proxy = new Proxy(myTarget, {
    construct(target, argumentsList, newTarget) {
        return Reflect.construct(...arguments)
    }
});
  • 捕获器处理程序参数

    • target: 目标构造函数
    • argumentsList:传给目标构造函数的参数列表
    • newTarget:最初被调用的构造函数
  • 返回值

    必须是一个对象

  • 拦截的操作

    • new proxy(...argumentsList)
    • Reflect.construct(target, argumentsList, newTarget)
  • 捕获器不变式

    target必须可以用作构造函数