Proxy 是什么?
Proxy
是由 ES6
原生提供的一个构造函数
Proxy
指在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
作用
Proxy
的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
Proxy
用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming
),即对编程语言进行编程。
使用方法
参数
Proxy
作为一个构造函数,它接受两个参数。
const p = new Proxy(target, handler)
第一个参数是所要代理的目标对象即target
:
target
要使用 Proxy
包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
第二个参数是一个配置对象,对于每一个被代理的操作,需要提供一个对应的处理函数即handler
,该函数将拦截对应的操作。
handler
一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p
的行为。
Proxy.revocable()
创建一个可撤销的Proxy
对象。
配置对象的方法
有一个 get 方法,用来拦截对目标对象属性的访问请求,而 get 方法两个参数分别是目标对象(target)和所要访问的属性(prop)。
注意:要使得 Proxy 起作用,必须针对 Proxy 实例进行操作,而不是针对目标对象进行操作。
//new Proxy()表示生成一个Proxy实例
var proxy = new Proxy({}, {
get: function(target, propKey) {
return 35;
}
});
console.log(proxy.name) // 35
console.log(proxy.sex) // 35
console.log(proxy.age) // 35
//可以看到,由于拦截函数总是返回35,所以访问任何属性都得到35。
//如果handler没有设置任何拦截,那就等同于直接通向原对象。
var target = {};
var handler = {};
var proxy2 = new Proxy(target, handler);
proxy2.a = 'b';
target.a // "b"
//Proxy 实例也可以作为其他对象的原型对象。
var proxy3 = new Proxy({},{
return 35
})
let obj = Obeject.create(proxy3)
console.log(obj.name) // 35
//上述代码proxy3对象是obj对象的原型,obj对象本身并没有name属性,所以根据原型链,会在proxy3对象上读取该属性,导致被拦截。
//同一个拦截器函数,可以设置拦截多个操作。
var handler = {
get: function(target, name) {
if (name === 'prototype') {
return Object.prototype;
}
return 'Hello, ' + name;
},
apply: function(target, thisBinding, args) {
return args[0];
},
construct: function(target, args) {
return {value: args[1]};
}
};
var fproxy = new Proxy(function(x, y) {
return x + y;
}, handler);
fproxy(1, 2) // 1
new fproxy(1, 2) // {value: 2}
fproxy.prototype === Object.prototype // true
fproxy.foo === "Hello, foo" // true
Proxy 实例的方法
get()
get
方法用于拦截某个属性的读取操作。
可接受三个参数:
- 目标对象(
target
) - 属性名(
prop
) proxy
实例本身(receiver
)(严格地说,是操作行为所针对的对象),其中最后一个参数可选。
set()
set
用来拦截某个属性的赋值操作。
可接受四个参数:
- 目标对象(
target
) - 属性名(
prop
) - 属性值(
value
) Proxy
实例本身(receiver
),其中最后一个参数可选。
apply()
apply
方法拦截函数的调用、call
和 apply
操作。
apply
方法可接受三个参数
- 目标对象 (
target
) - 目标对象的上下文对象(
ctx
) - 目标对象的参数数组(
…arguments
)
has()
has()
方法用来拦截 HasProperty
操作,即判断对象是否具有某个属性时,这个方法会生效。
典型的操作就是 in
运算符。
has()
方法可接受两个参数:
- 目标对象
- 需查询的属性名。
construct()
用于拦截 new
命令,拦截对象的写法:
const handler = {
construct (target, args, newTarget) {
return new target(...args);
}
};
construct()
可接受三个参数:
target
:目标对象。args
:构造函数的参数数组。newTarget
:创造实例对象时,new
命令作用的构造函数。
const p = new Proxy(function () {}, {
construct: function(target, args) {
console.log('called: ' + args.join(', '));
return { value: args[0] * 10 };
}
});
(new p(1)).value
// "called: 1"
// 10
注意:
由于 construct()
拦截的是构造函数,所以它的目标对象必须是函数,否则就会报错。
construct()
方法中的 this
指向的是 handler
,而不是实例对象。
headler对象的方法
handler
对象是一个容纳一批特定属性的占位符对象。它包含有 Proxy
的各个捕获器(trap
)。
所有的捕捉器是可选的。如果没有定义某个捕捉器,那么就会保留源对象的默认行为。
handler.getPrototypeOf()
Object.getPrototypeOf
方法的捕捉器。
handler.setPrototypeOf()
Object.setPrototypeOf
方法的捕捉器。
handler.isExtensible()
Object.isExtensible
方法的捕捉器。
handler.preventExtensions()
Object.preventExtensions
方法的捕捉器。
handler.getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptor
方法的捕捉器。
handler.defineProperty()
Object.defineProperty
方法的捕捉器。
handler.has()
in
操作符的捕捉器。
handler.get()
属性读取操作的捕捉器。
handler.set()
属性设置操作的捕捉器。
handler.deleteProperty()
delete
操作符的捕捉器。
handler.ownKeys()
Object.getOwnPropertyNames
方法和 Object.getOwnPropertySymbols
方法的捕捉器。
handler.apply()
函数调用操作的捕捉器。
handler.construct()
new
操作符的捕捉器。