ES6 Proxy方法

什么是Proxy?

Proxy 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)

其实就是在对目标对象操作之前提供拦截,可以对外界的操作进行过滤和改写,修改某些操作的默认行为,这样我们可以不直接操作对象本身,而是通过操作对象的代理对象来间接操作对象,达到预期目的。

看个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let 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)

参数 targetProxy 包装的目标对象(可以是任何类型的对象,包括数组、函数、甚至另一个代理),参数 handler 也是一个对象,其属性是执行一个操作时定义代理行为的函数。handler 可以是空对象 {},不可以设置为 null,否则会排除错误。

要想 Proxy 起作用,就不能去操作原来对象的属性,必须针对的是 Proxy 实例,否则达不到预期效果。

继续使用前面的例子:

1
2
console.log(proxyObj.b) // 0
console.log(obj.b) // undefined

对于 set 方法,在作用于 proxy 实例的同时也会作用于target上。

1
2
3
proxyObj.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
2
3
4
5
6
7
8
var obj = {name: 'Lucy'}
var proxy = new Proxy(obj, {
get: function (target, key, receiver) {
return key === 'name' ? `Hello ${target[key]}` : target[key]
}
})

console.log(p.name) // Hello Lucy

注意:如果一个属性不可配置(configurable)且不可写(writable),则 Proxy 不能修改该属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var 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
2
3
4
5
6
7
8
9
10
11
var obj = {age: 18}
var proxy = new Proxy(obj, {
set: function(target, key, value, receiver) {
console.log(receiver)
target[key] = key === 'age' ? Math.min(value, 100) : value
}
})

proxy.age = 101
console.log(proxy.age) // 100
console.log(obj.age) // 100

注意Proxy 不能进行深度代理,如:

1
2
3
4
5
6
7
8
9
var 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

has(target, key)

deleteProperty(target, key)

ownKeys(target)

参考:segmentfault JS基础——Proxy