Proxy
创建一个代理对象,拦截对目标对象的访问。
使用方法
const p = new Proxy(target, handler);
target: 要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler: 一个对象,其属性是当执行一个操作时定义代理的行为的函数。
1.handler.getPrototypeOf()
Object.getPrototypeOf 方法的捕捉器。
拦截目标对象的原型。当使用下面四种方法时,会调用此方法。
- Object.getPrototypeOf()
- Reflect.getPrototypeOf()
- instanceof
obj.__proto__
const monster1 = {
eyeCount: 4,
}
const monsterPrototype = {
eyeCount: 2,
}
const proxy1 = new Proxy(monster1, {
getPrototypeOf(target) {
return monsterPrototype
},
})
console.log(Object.getPrototypeOf(proxy1) === monsterPrototype) // true
console.log(Object.getPrototypeOf(proxy1).eyeCount) // 2
console.log(proxy1.eyeCount) // 4
2. handler.setPrototypeOf()
Object.setPrototypeOf 方法的捕捉器。
下面两种方法会调用此方法。
- Object.setPrototypeOf()
- Reflect.setPrototypeOf()
const newProto = {}
const target = {}
const p1 = new Proxy(target, {
setPrototypeOf(target, newProto) {
return false // 不允许设置原型 如果允许的话 可以返回 Reflect.setPrototypeOf(target, newProto)
},
})
Object.setPrototypeOf(p1, newProto) // throws a TypeError
Reflect.setPrototypeOf(p1, newProto) // returns false
3. handler.isExtensible()
Object.isExtensible 方法的捕捉器。 判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。
下面两种方法会调用此方法。
- Object.isExtensible()
- Reflect.isExtensible()
const monster1 = {
canEvolve: true,
}
const handler1 = {
isExtensible(target) {
return Reflect.isExtensible(target)
},
preventExtensions(target) {
target.canEvolve = false
return Reflect.preventExtensions(target)
},
}
const proxy1 = new Proxy(monster1, handler1)
console.log(Object.isExtensible(proxy1)) // true
console.log(monster1.canEvolve) // true
Object.preventExtensions(proxy1)
console.log(Object.isExtensible(proxy1)) // false
console.log(monster1.canEvolve) // false
4. handler.preventExtensions()
Object.preventExtensions 方法的捕捉器。(使对象变得不可扩展,也就是永远不能再添加新的属性。)
下面两种方法会调用此方法。
- Object.preventExtensions()
- Reflect.preventExtensions()
5. handler.getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptor 方法的捕捉器。(获取单个的属性描述)
下面两种方法会调用此方法。
- Object.getOwnPropertyDescriptor()
- Reflect.getOwnPropertyDescriptor()
const p = new Proxy(
{ a: 20 },
{
getOwnPropertyDescriptor: function (target, prop) {
console.log('called: ' + prop)
return { configurable: true, enumerable: true, value: 10 }
},
}
)
console.log(Object.getOwnPropertyDescriptor(p, 'a').value) // "called: a"; output 10
6. handler.defineProperty()
Object.defineProperty 方法的捕捉器。(定义对象的内部属性)
下面两种方法会调用此方法。
- Object.defineProperty()
- Reflect.defineProperty()
const obj = {}
const p = new Proxy(obj, {
defineProperty: function (target, prop, descriptor) {
console.log('called: ' + prop)
return true
},
})
Object.defineProperty(p, 'a', { configurable: true, enumerable: true, value: 10 }) // "called: a"
7. handler.has()
in 操作符的捕捉器。
下面两种方法会调用此方法。
- in 操作符
- Reflect.has()
const monster1 = {
_secret: 'easily scared',
eyeCount: 4,
}
const proxy1 = new Proxy(monster1, {
has(target, key) {
if (key[0] === '_') {
return false
}
return key in target
},
})
console.log('eyeCount' in proxy1) // true
console.log('_secret' in proxy1) // false
console.log('_secret' in monster1) // true
8. handler.get()
属性访问的捕捉器。
下面两种方法会调用此方法。
- 属性访问
- Reflect.get()
const p = new Proxy(
{},
{
get: function (target, prop, receiver) {
console.log('called: ' + prop)
return 10
},
}
)
console.log(p.a) // "called: a"; ouptut 10
9. handler.set()
属性设置的捕捉器。
下面两种方法会调用此方法。
- 属性设置
- Reflect.set()
const monster1 = { eyeCount: 4 }
const proxy1 = new Proxy(monster1, {
set(obj, prop, value) {
if (prop === 'eyeCount' && value % 2 !== 0) {
console.log('Monsters must have an even number of eyes')
return true
} else {
return Reflect.set(obj, prop, value)
}
},
})
proxy1.eyeCount = 1 // Monsters must have an even number of eyes
console.log(proxy1.eyeCount) // 4
proxy1.eyeCount = 2
console.log(proxy1.eyeCount) // 2
10. handler.deleteProperty()
delete 操作符的捕捉器。
下面两种方法会调用此方法。
- delete 操作符
- Reflect.deleteProperty()
const p = new Proxy(
{},
{
deleteProperty: function (target, prop) {
console.log('called: ' + prop)
return true
},
}
)
delete p.a // "called: a"
11. handler.ownKeys()
Object.getOwnPropertyNames 和 Object.getOwnPropertySymbols 方法的捕捉器。
Object.getOwnPropertyNames: 返回一个数组,该数组对元素是 obj自身拥有的枚举或不可枚举属性名称字符串。(不包含Symbol类型)
Object.getOwnPropertySymbols: 返回一个给定对象自身的所有 Symbol 属性的数组。
访问下面四种方法时会调用此方法。
- Object.getOwnPropertyNames()
- Object.getOwnPropertySymbols()
- Object.keys()
- Reflect.ownKeys()
const monster1 = {
_age: 111,
[Symbol('secret')]: 'I am scared!',
eyeCount: 4,
}
const proxy1 = new Proxy(monster1, {
ownKeys(target) {
console.log('ownKeys', Reflect.ownKeys(target)) // [ '_age', 'eyeCount', Symbol(secret) ]
return Reflect.ownKeys(target)
},
})
for (const key of Object.keys(proxy1)) {
console.log(key)
// Expected output: "_age"
// Expected output: "eyeCount"
}
12. handler.apply()
函数调用的捕捉器。
下面三种方法会调用此方法。
- 函数调用
- Reflect.apply()
- Function.prototype.apply() 和 Function.prototype.call()
function sum(a, b) {
return a + b
}
const proxy1 = new Proxy(sum, {
apply: function (target, thisArg, argumentsList) {
console.log(`Calculate sum: ${argumentsList}`)
// Expected output: "Calculate sum: 1,2"
return target(argumentsList[0], argumentsList[1]) * 10
},
})
console.log(sum(1, 2))
// Expected output: 3
console.log(proxy1(1, 2))
// Expected output: 30
13. handler.construct()
new 操作符的捕捉器。
下面两种方法会调用此方法。
- new 操作符
- Reflect.construct()
function monster1(disposition) {
this.disposition = disposition
}
const proxy1 = new Proxy(monster1, {
construct(target, args) {
console.log(`Creating a ${target.name}`)
// Expected output: "Creating a monster1"
return new target(...args)
},
})
console.log(new proxy1('fierce').disposition)
// Expected output: "fierce"
总结
总共有13个捕捉器
- getPrototypeOf
- setPrototypeOf
- isExtensible
- preventExtensions
- getOwnPropertyDescriptor
- defineProperty
- has
- get
- set
- deleteProperty
- ownKeys
- apply
- construct