Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ES6 Proxy #24

Open
ChuChencheng opened this issue Jan 13, 2020 · 0 comments
Open

ES6 Proxy #24

ChuChencheng opened this issue Jan 13, 2020 · 0 comments

Comments

@ChuChencheng
Copy link
Owner

概念

用于修改某些操作的默认行为,等同于在语言层面做出修改。相当于在目标对象之前架设一层“拦截”,外部对对象的操作,必须通过这层拦截,可对操作进行过滤和改写。

const proxyObject = new Proxy({}, {
  get (target, key, receiver) {
    // target: 目标对象
    // key: 当前获取的键
    // receiver: 当前 Proxy 对象
    console.log('getting ', key)
    return Reflect.get(target, key, receiver)
  },
  set (target, key, value, receiver) {
    // value 当前设置的值
    console.log('setting ', key)
    return Reflect.set(target, key, value, receiver)
  },
})

proxyObject.a = 1 // setting a

proxyObject.a++
// getting a
// setting a
// 1

Proxy 的 13 种拦截操作

  • get? (target: T, p: PropertyKey, receiver: any): any 拦截属性的读取
  • set? (target: T, p: PropertyKey, value: any, receiver: any): boolean 拦截属性的设置
  • has? (target: T, p: PropertyKey): boolean 拦截 propertyKey in proxy 操作
  • deleteProperty? (target: T, p: PropertyKey): boolean 拦截删除属性操作
  • ownKeys? (target: T): PropertyKey[] 拦截 Object.getOwnPropertyNames(proxy), Object.getOwnPropertySymbols(proxy), Object.keys(proxy), for...in
  • getOwnPropertyDescriptor? (target: T, p: PropertyKey): PropertyDescriptor | undefined 拦截 Object.getOwnPropertyDescriptor(proxy, propertyKey)
  • defineProperty? (target: T, p: PropertyKey, attributes: PropertyDescriptor): boolean 拦截 Object.defineProperty(proxy, propertyKey, propertyDescriptor), Object.defineProperties(proxy, propertyDescriptors)
  • preventExtensions? (target: T): boolean 拦截 Object.preventExtensions(proxy)
  • getPrototypeOf? (target: T): object | null 拦截 Object.getPrototypeOf(proxy)
  • setPrototypeOf? (target: T, v: any): boolean 拦截 Object.setPrototypeOf(proxy, proto)
  • isExtensible? (target: T): boolean 拦截 Object.isExtensible(proxy)
  • apply? (target: T, thisArg: any, argArray?: any): any 拦截 Proxy 实例作为函数调用的操作
  • construct? (target: T, argArray: any, newTarget?: any): object 拦截 Proxy 实例作为构造函数调用的操作

具体参数说明与用法,可参考各类文档,例如 MDN , typescript 定义,http://es6.ruanyifeng.com/#docs/proxy 等。

Proxy.revocable()

定义:

revocable<T extends object>(target: T, handler: ProxyHandler<T>): { proxy: T; revoke: () => void; }

返回一个可取消的 Proxy 实例

const { proxy, revoke } = Proxy.revocable({}, {})

proxy.a = 1
proxy.a // 1

revoke()

proxy.a // TypeError: Cannot perform 'get' on a proxy that has been revoked

可应用于不允许直接访问对象,必须通过代理访问,访问结束后就收回代理,不能再次访问的场景。

this

Proxy 中的 this 指向的是 proxy ,而不是原对象,因此,即使 handler 是空的,什么也不拦截,其 proxy 的表现与原对象也不是完全一致的。

const target = {
  f () {
    return this
  }
}

const proxy = new Proxy(target, {})

target.f() === target // true
proxy.f() === target // false
proxy.f() === proxy // true

此外,一些原生对象的内部属性,只有通过正确的 this 才能拿到,例如 Date

const target = new Date()
const proxy = new Proxy(target, {})

proxy.getDate() // TypeError: this is not a Date object

如果把 this 绑定回原来的对象,就可以正常使用:

const target = new Date()
const proxy = new Proxy(target, {
  get (target, key) {
    if (key === 'getDate') {
      // 判断是否调用的 getDate 方法
      return target.getDate.bind(target)
    }
    return Reflect.get(target, key)
  }
})

proxy.getDate() // 正常显示日期

参考

http://es6.ruanyifeng.com/#docs/proxy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant