Proxy引见

Proxy 让我们能够对任何对象的绝大部分行动举行监听和过问,完成更多的自定义顺序行动。
用法:new Proxy(target, handler)。
   Proxy 经由历程设置行动监听要领来捕捉顺序对对应对象的行动。

    const obj = {};
    const proxy = new Proxy(obj, {
        // ...
    })

Proxy 的组织器接收两个参数,第一个参数为须要举行包装的目的对象,第二个参数则为用于监听目的对象行动的监听器,个中监听器能够接收一些参数以监听相对应的顺序行动。
监听属性、参数及监听内容

属性值监听器参数监听内容
has(target, prop)监听 in 语句的运用
get(target, prop, reciver)监听目的对象的属性读取
set(target, prop, value, reciver)监听目的对象的属性赋值
deleteProperty(target, prop)监听 delete 语句对目的对象的删除属性行动
ownKeys(target)监听 Object.getOwnPropertyName() 的读取
apply(target, thisArg, arguments)监听目的函数(作为目的对象)的挪用行动
construct(target, arguments, newTarget)监听目的组织函数(作为目的对象)应用 new 而天生实例的行动
getPrototypeOf(target)监听 Objext.getPrototypeOf() 的读取
setPrototypeOf(target, prototype)监听 Objext.setPrototypeOf() 的挪用
isExtensible(target)监听 Objext.isExtensible() 的读取
preventExtensions(target)监听 Objext.preventExtensions() 的读取
getOwnPropertyDescriptor(target, prop)监听 Objext.getOwnPropertyDescriptor() 的挪用
defineProperty(target, property, descriptor)监听 Object.defineProperty() 的挪用

has

能够经由历程为 Proxy 的 handler 定义 has 监听要领,来监听顺序经由历程 in 语句来搜检一个字符串或数字是不是为该 Proxy 的目的对象中某个属性的属性键的历程。

const p = new Proxy({}, {
    has(target, prop){
        console.log(`Checking "${prop}" is in the target or not`);
        return true;
    }
})

console.log('foo' in p);
// Checking "foo" is in the target or not
// true

该监听要领有两个须要注重的处所,假如碰到这两种状况,便会抛出 TypeError 毛病。

1.当目的对象被其他顺序经由历程 Object.preventExtensions() 禁用了属性拓展 (该对象没法再增添新的属性,只能对当前已有的属性举行操纵,包含读取、操纵和删除,然则一旦删除就没法再定义) 功用,且被搜检的属性键确切存在与目的对象中,该监听要领便不能返回 false。

const obj = {foo: 1};

Object.preventExtensions(obj);

const p = new Proxy(obj, {
    has(target, prop){
        console.log(`Checking "${prop}" is in the target or not`);
        return false; 
    }
})

console.log('foo' in p);   
//抛出Uncaught TypeError: 

2.当被搜检的属性键存在与目的对象中,且该属性的 configurable 设置是 false 时,该监听要领不能返回 false。

const obj = {};

Object.defineProperty(obj, 'foo', {
    configurable: false,
    value: 10
})

const p = new Proxy(obj, {
    has(target, prop){
        console.log(`Checking "${prop}" is in the target or not`);
        return false;
    }
})

console.log('foo' in p);
//抛出Uncaught TypeError: 

get

Getter只能对已知的属性键举行监听,而没法对一切属性读取行动举行阻拦,而 Proxy 能够经由历程设定 get 监听要领,阻拦和过问目的对象的一切属性读取行动。

const obj = {foo: 1};
const p = new Proxy(obj, {
    get(target, prop){
        console.log(`Program is trying to fetch the property "${prop}".`);
        return target[prop];
    }
})

alert(p.foo);  // Program is trying to fetch the property "foo".
alert(p.something);    // Program is trying to fetch the property "something".

  这个监听要领也存在须要注重的处所——当目的对象被读取属性的 configurable 和 writable 属性都为 false 时,监听要领末了返回的值必需与目的对象的原属性值一致。

const obj = {};

Object.defineProperty(obj, 'foo', {
    configurable: false,
    value: 10,
    writable: false
})

const p = new Proxy(obj, {
    get(target, prop){
        return 20;
    }
})

console.log(p.foo);

set

  handler.set 用于监听目的对象的一切属性赋值行动。注重,假如目的对象本身的某个属性是不可写也不可设置的,那末 set 不得转变这个属性的值,只能返回一样的值,不然报错。

const obj = {};
const p = new Proxy(obj, {
    set(target, prop, value){
        console.log(`Setting value "${value}" on the key "${prop}" in the target object`);
        target[prop] = value;
        return true;
    }
})

p.foo = 1;  
// Setting value "1" on the key "foo" in the target object

apply

handler.apply , Proxy 也为作为目的对象的函数供应了监听其挪用行动的属性。

const sum = function(...args) {
  return args
    .map(Number)
    .filter(Boolean)
    .reduce((a, b) => a + b);

}

const p = new Proxy(sum, {
  apply(target, thisArg, args) {
    console.log(`Function is being called with arguments [${args.join()}] and context ${thisArg}`);
    return target.call(thisArg, ...args);
  }
})

console.log(p(1, 2, 3));
// Function is being called with arguments [1,2,3] and context undefined
// 6

construct

  handler.construct, Proxy 也能够将类作为目的监听对象,并监听其经由历程 new 语句来临盆新实例的行动,这一样能够运用再作为组织器的组织函数上。

class Foo{};

const p = new Proxy(Foo, {
    construct(target, args, newTarget){
        return {arguments: args}    // 这里返回的效果会是 new 所获得的实例
    }
});

const obj = new p(1, 2, 3);
console.log(obj.arguments);  // [1, 2, 3]

建立可消除 Proxy 对象

用法:Proxy.revocable(target, handler) : (proxy, revoke)。

const obj = {foo: 10};
const revocable = Proxy.revocable(obj, {
    get(target, prop){
        return 20;
    }
})
const proxy = revocable.proxy;
console.log(proxy.foo); // 20
revocable.revoke();
console.log(proxy.foo); 
// TypeError: Cannot perform 'get' on a proxy that has been revoked

  Proxy.revocable(target, handler) 会返回一个带有两个属性的对象,个中一个 proxy 就是该函数所天生的可消除 Proxy 对象,而另一个 revoke 则是将适才的 Proxy 对象消除的消除要领。

    原文作者:紫云梦
    原文地址: https://segmentfault.com/a/1190000017323334
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞