### 概述
`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()