Proxy

2021/12/11

Proxy

  • Proxy:用于创建一个对象的代理,从而实现对目标对象操作的拦截。
  • target:被代理的对象,一般理解为存储后端。
  • handler:处理器对象。
  • traps:handler提供的拦截原生操作方法。

# 声明

# 构造函数

  • 调用:new Proxy(target, handler)
  • 入参:Object, Object

  • get入参的属性名默认时String类型:get(target: object, name: string) {}
  • 数组要将String转化为Number才能计算下标

# revocable

  • 作用:创建一个可撤销的代理对象
  • 调用:Proxy.revocable(target, handler)
  • 入参:Object, Object
  • 返回:{ proxy: proxy, revoke: revokeFn }
  • tip:和new Proxy()创建的一样,只是这个可以被删除






 

 







 
 

const ans = Proxy.revocable({}, {
    get (target, name) {
        return `${name}: hdy`;
    }
})

console.log(ans); // { proxy: {}, revoke: [Function (anonymous)] }

const proxy = ans.proxy;
console.log(proxy.ownner); // ownner: hdy
console.log(proxy.name); // name: hdy

/**
 *  撤销以后再用就报错:
 *  Cannot perform 'get' on a proxy that has been revoked
 */
ans.revoke();
// console.log(proxy.name); // error
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# Reflect

  • Reflect提供JS原生操作,并且只有静态方法
  • Reflect拥有的静态方法都和handler提供的方法一一对应,可以用来proxy劫持操作后再执行target原生JS操作

# this

  • handler里面的traps函数里的this已经被绑定到handler上了。不是proxy也不是target也不是receiver


 






const handler = {
    set(target, key, value, receiver) {
        console.log(this === handler); // true
        Reflect.set(target, key, value, receiver);
    }
}
const proxy = new Proxy({}, handler);
proxy.name = 'hdy';
1
2
3
4
5
6
7
8

# handler方法

# get

  • 作用:拦截读取属性
  • 定义:get(target, prop, receiver)
  • 入参:Object, String, Object
  • 返回:any
  • 调用:proxy.XX | proxy[XX]
  • receiver:如果target里面有getter,那么getter里面的this就是receiver

约束

  1. 如果target属性的writable是false,则proxy不可改动返回值
  2. 如果target属性的get是undefined,那么proxy也要返回undefined

# set

  • 作用:劫持赋值操作
  • 定义:set(target, key, value, receiver)
  • 入参:Object, String, any, Object
  • 返回:Boolean
  • 调用:proxy.key = value

receiver

  • 直接调用proxy是proxy本身
  • proxy作为原型链,后代对象set属性也会调用此劫持,但receiver是后代对象

# has

  • 作用:针对【in】方法的劫持
  • 定义:has(target, key)
  • 入参:Object, String
  • 返回:Boolean
  • 调用:key in target

# apply

  • 作用:劫持函数调用操作
  • 定义:apply(target, thisArg, arguments)
  • 入参:Object, Object, Array
  • 返回:any
  • 调用:proxy() | proxy.apply() | proxy.call()
  • tip:被代理的一定要是函数,否则自身都没有apply方法

# ownKeys

  • 作用:劫持获取对象keys值操作
  • 定义:ownKeys(target)
  • 入参:Object
  • 返回:Iterator
  • 调用:
    1. Reflect.ownKeys(proxy)
    2. Object.keys(proxy)
    3. Object.getOwnPropertyNames(proxy)
    4. Object.getOwnPropertySymbols(proxy)

  • 必须返回一个可枚举对象

# construct

  • 作用:劫持原生的constructor函数
  • 定义:construct(target, arguments, newTarget)
  • 入参:Object, Array, Object(本Proxy对象)
  • 返回:Object
  • 调用:new proxy(args);
  • tip:target必须有constructor(是函数\类)

# getPropertypeOf

  • 作用:劫持访问原型链对象操作
  • 定义:getPropertypeOf(target)
  • 入参:Object
  • 返回:Object | null
  • 调用:
    1. Object.getPropertyOf(proxy)
    2. Reflect.getPrototypeOf(proxy)
    3. instanceof
    4. proxy._ _ proto _ _
    5. obj.isPrototypeOf(proxy)

限制

  • 必须返回Object或null
  • target不可扩展的情况下禁止撒谎

# setPrototypeOf

  • 作用:拦截Object.setProtypeOf()
  • 定义:setPrototypeOf(target, prototype)
  • 入参:Object, Object | null
  • 返回:Boolean
  • 调用:Object.setPrototypeOf(proxy, proto)

# defineProperty

  • 作用:拦截原生的defineProperty方法
  • 定义:defineProperty(target, property, descriptor)
  • 入参:Object, String, Object
  • 返回:Boolean (属性操作是否成功)
  • 调用:Object.defineProperty(proxy, name, descriptor)

# deleteProperty

  • 作用:劫持delete操作
  • 定义:deleteProperty(target, name)
  • 入参:Object, String
  • 返回:Boolean (是否删除成功)
  • 调用:delete proxy.prop

# getOwnPropertyDescriptor

  • 作用:拦截Object.getOwnPropertyDescriptor(target, name)
  • 定义:getOwnPropertyDescriptor(target, name)
  • 入参:Object, String
  • 返回:Object | undefined
  • 调用:Object.getOwnPropertyDescriptor(proxy, name)

限制:configurable相关不能撒谎

  1. 必须返回Object或undefined
  2. 不可配置属性不可以返回可配置
  3. 属性存在且target不可扩展,不可返回不存在
  4. 属性不存在的属性且target不可扩展,不可返回存在
  5. 可配置或不存在的属性,不可以返回不可配置

# isExtensible

  • 作用:劫持Object.isExtensible(target)
  • 定义:isExtensible(target)
  • 入参:Object
  • 返回:Boolean
  • 调用:Object.isExtensible(target)

  • 只能做操作,不能修改值

# preventExtensions

  • 作用:劫持限制对象扩展类操作
  • 定义:preventExtensions(target)
  • 入参:Object
  • 返回:Boolean
  • 调用:
    1. Object.preventExtensions(proxy)
    2. Object.seal(proxy)
    3. Object.freeze(proxy)
上次更新: 11/1/2024