### 概述
`Proxy`用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种"元编程",即对编程语言进行编程。
`Proxy`可以理解成在目标对象前假设一个"拦截"层,外界对该对象的访问都必须通过这层拦截,因此提供了一种机制可以对外界的访问进行过滤和改写。
```js
let obj = new Proxy({}, {
get: (target, key, receiver) => {
console.log(`getting ${key}!`)
return Reflect.get(target, key, receiver)
},
set: (target, key, value, receiver) => {
console.log(`setting ${key}`)
return Reflect.set(target, key, value, receiver)
}
})
// obj.count = 1
// setting count
// 1
// ++obj.count
// getting count
// setting count
// 2
```
ES6提供了`Proxy`构造函数,用于生成`Proxy`实例。
```js
let proxy = new Proxy(target, handler)
```
`new Proxy`表示生成一个`Proxy`实例,`target`参数表示所要拦截的目标对象,`handler`参数也是一个对象,用来定制拦截行为。
```js
const proxy = new Proxy({}, {
get: (target, property) => {
return 35
}
})
```
### Proxy实例的方法
#### get()
`get`方法用于拦截某个属性的读取操作
```js
let person = {
name: '张三'
}
let proxy = new Proxy(person, {
get: function (target, property) {
if (property in target) {
return target[property]
} else {
throw new ReferenceError("Property \"" + property + "\" does not exist.")
}
}
})
proxy.name // '张三'
proxy.age // 抛出错误
```
#### set()
`set`方法拥有拦截某个属性的赋值操作
```js
let validator = {
set: function (obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('The age is not an integer')
}
if (value > 200) {
throw new RangeError('THe age seems invalid')
}
}
obj[prop] = value
}
}
let person = new Proxy({}, validator)
person.age = 100
person.age // 100
person.age = 'young' // 报错
person.age = 300 // 报错
```
#### apply()
`apply`方法拦截函数的调用、`call`和`apply`操作
#### has()
`has`方法用来拦截`HasProperty`操作,即判断对象是否具有某个属性时
#### construct()
`construct`方法用于拦截`new`命令。
#### deleteProperty()
`deleteProperty`方法用于拦截`delete`操作,如果这个方法抛出错误或返回`false`,当前属性就无法被`delete`命令删除。
#### defineProperty()
`defineProperty`方法拦截了`Object.defineProperty`操作
#### getOwnpropertyDescriptor()
`getOwnpropertyDescriptor`方法拦截`Object.getOwnPropertyDescriptor()`,返回一个属性描述对象或者`undefined`
#### getPrototypeOf()
`getPrototypeOf`方法主要用来拦截获取对象原型
#### isExtensible()
`isExtensible`方法拦截`Object.isExtensible`操作
#### ownKeys()
`ownKeys`方法用来拦截对象自身属性的读取操作
#### preventExtensions()
#### setPrototypeOf()
#### Proxy.revocable()