proxy 概述
proxy用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种"元编程",即对编程语言进行编程。
proxy可以理解为在目标对象前假设一个“拦截”层,外界对该对象的访问都必须先通过这层拦截,因此提供了一种机制可以对外界的访问进行过滤和改写。Proxy这个词的原意是代理,用在这里表示由他来“代理”某些操作,可以翻译为“代理器”.
es6提供proxy构造函数,用于生成proxy实例
proxy对象的所有用法都是上面这种形式,不同的只是handler参数的写法,其中new Peoxy()表示生成一个proxy实例,target参数表示要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。
- proxy实例方法 -->defineProperty()
defineProperty()拦截Object.defineProperty操作
{
var handler = {
defineProperty(target, key , descriptor){
return false;
}
};
var target = {foo:'123'};
var proxy = new Proxy(target,handler);
console.log(Object.defineProperty(proxy,'foo',{
writable:false
}));
// 'defineProperty' on proxy: trap returned falsish for property 'foo'
}
- proxy实例方法 -->getOwnPropertyDescriptor()
getOwnPropertyDescriptor()拦截Object.getOwnPropertyDescriptor(),返回一个属性描述对象或者undefined。
{
let handler = {
getOwnPropertyDescriptor(target, key){
if(key[0] === '_'){
return;
}
return Object.getOwnPropertyDescriptor(target,key);
}
}
let target = {_foo:'bar',baz:'tar'};
let proxy = new Proxy(target,handler);
console.log(Object.getOwnPropertyDescriptor(proxy,'low'));
//false
console.log(Object.getOwnPropertyDescriptor(proxy,'baz'));
//{value: "tar", writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(proxy,'_foo'));
//false
}
该方法对内置属性或者以下划线开头的属性返回undefined
-
proxy实例方法 -->getPrototypeOf()
getPrototypeOf()方法主要用来拦截获取对象原型。主要用来拦截以下方法 + Object.prototype.__proto__ + Object.prototype.isPrototypeOf + Object.getPrototypeOf() + Reflect.getPrototypeOf() + instanceof
{
//举个例子
let proto = {};
let p = new Proxy({},{
getPrototypeOf(target){
return proto;
}
})
console.log(Object.getPrototypeOf(p) === proto);
//true
//上面的代码,getPrototypeOf方法拦截了Object.getPrototypeOf(),返回了proto对象。
}
- proxy实例方法 -->isExtensible()
isExtensible()方法拦截Object.isExtensible操作
{
let p = new Proxy({},{
isExtensible(target){
console.log("called");
return true;
}
})
console.log(Object.isExtensible(p));
// called
// true
}
-
proxy实例方法 -->ownKeys()
ownkeys方法用来拦截对象自身属性的读取操作+ Object.getOwnPropertyNames() + Object.getOwnPropertySymbols() + Object.keys()
{
//举个例子
let target = {
a:1,
b:2,
c:3
};
console.log(Object.keys(target));
//(3) ["a", "b", "c"]
let handler = {
ownKeys(target){
return ['a'];
}
}
let proxy = new Proxy(target, handler);
console.log(Object.keys(proxy));
//['a']
}
- proxy实例方法 --> Proxy.revocable()
Proxy.revocable() 方法返回一个可取消的Proxy实例
{
let target = {};
let handler = {};
let {proxy, revoke} = Proxy.revocable(target, handler);
console.log(proxy.foo = 300);
//300
revoke()
console.log(proxy.foo = 123);
// Cannot perform 'set' on a proxy that has been revoked
}
proxy.revocable 的一个使用场景是,目标对象不允许直接访问,唏嘘通过代理访问,一旦访问结束, 就要收回代理权,不允许再次访问
- proxy实例方法 -->setPrototypeOf()
setPrototypeOf方法主要用于拦截Object.setPrototypeOf
{
let handler = {
setPrototypeOf(target, proto) {
throw new Error('Changing the prototype is forbidden');
}
}
let proto = {};
let target = function () {};
let proxy = new Proxy(target, handler);
console.log(Object.setPrototypeOf(proxy, proto));
//Changing the prototype is forbidden
}
- proxy --> this问题
虽然proxy可以代理目标对象的访问,但是他不是目标对象的透明代理,即目标对象this关键字会指向proxy
{
let target = {
m(){
console.log(this === proxy);
}
}
let handler = {};
let proxy = new Proxy(target, handler);
console.log(target.m()); //false
console.log(proxy.m()); //true
}