什么是Proxy?
Proxy 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)
其实就是在对目标对象操作之前提供拦截,可以对外界的操作进行过滤和改写,修改某些操作的默认行为,这样我们可以不直接操作对象本身,而是通过操作对象的代理对象来间接操作对象,达到预期目的。
看个例子:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20let obj = {
  a: 1
}
let proxyObj = new Proxy(obj, {
  get: function (target, prop) {
    return prop in target ? target[prop] : 0
  },
  set: function (target, prop, value) {
    target[prop] = 888
  }
})
// get
console.log(proxyObj.a) // 1
console.log(proxyObj.b) // 0
// set
proxyObj.a = 666
console.log(proxyObj.a) // 888
发现经过 Proxy 构造器中转一下之后,并没有按照我们预期的表现,Proxy在读取和设置之前都做了一次拦截。
语法
| 1 | let proxy = new Proxy(target, handler) | 
参数 target 是 Proxy 包装的目标对象(可以是任何类型的对象,包括数组、函数、甚至另一个代理),参数 handler 也是一个对象,其属性是执行一个操作时定义代理行为的函数。handler 可以是空对象 {},不可以设置为 null,否则会排除错误。
要想 Proxy 起作用,就不能去操作原来对象的属性,必须针对的是 Proxy 实例,否则达不到预期效果。
继续使用前面的例子:1
2console.log(proxyObj.b) // 0
console.log(obj.b) // undefined
对于 set 方法,在作用于 proxy 实例的同时也会作用于target上。1
2
3proxyObj.a === 666
console.log(proxyObj.a) // 888
console.log(obj.a) // 888
API
get(target, key, receiver)
get 方法用于拦截对象的读取属性操作。1
2
3
4
5
6/**
 * target: 目标对象
 * key: 目标属性
 * receiver: Proxy或继承Proxy的对象
 */
get(target, key, receiver)
| 1 | var obj = {name: 'Lucy'} | 
注意:如果一个属性不可配置(configurable)且不可写(writable),则 Proxy 不能修改该属性。1
2
3
4
5
6
7
8
9
10
11
12
13
14var obj = Object.defineProperties({}, {
  name: {
    value: 'Lucy',
    configurable: false,
    writable: false
  }
})
var proxy = new Proxy(obj, {
  get: function (target, key, receiver) {
    return key === 'name' ? `Hello ${target[key]}` : target[key]
  }
})
console.log(proxy.name) // 报错
set(target, key, value, receiver)
set 方法用于拦截对象的赋值操作。1
2
3
4
5
6
7/**
 * target: 目标对象
 * key: 目标属性
 * value: 目标属性值
 * receiver: Proxy或继承Proxy的对象
 */ 
set(target, key, value, receiver)
| 1 | var obj = {age: 18} | 
注意:Proxy 不能进行深度代理,如:1
2
3
4
5
6
7
8
9var obj = {borth: {year: 2000, month: 6}}
var proxy = new Proxy(obj, {
  set: function(target, key, value, receiver) {
    console.log(receiver)
    target[key] = value
  }
})
proxy.borth.month = 7