Proxy-代理,在JS里就是对数据进行代理。

用proxy代理json数据

let data = { a: 100 };
let p = new Proxy(data, {
    has() {},
    get() {},
    set() {},
    deleteProperty() {},
});

上面建立的Proxy实例p就是给data创建了一个数据代理,我列出来了4个常用的方法:

  • has:调用in的时候就会触发该方法,例如'a' in p
  • get:获取属性的时候就会触发该方法,例如p.a
  • set:设置属性的时候就会触发该方法,例如p.a = 200
  • deleteProperty:删除属性的时候就会触发该方法,例如delete(p.a)

注意,这里和defineProperty使用上有一点不同的是,我们在新建了Proxy对象之后,需要对实例进行操作才会进行相应的拦截,而对原数据操作是不会触发这些方法的。
下面我们来把这些方法填充一下,对一个json数据做一个简单的拦截:


let data = { a: 100 }; let p = new Proxy(data, { has(data, name) { return name in data; }, get(data, name) { if (name in data) { return data[name]; } else { throw new Error(`${name} is not defined.`); } }, set(data, name, val) { data[name] = val; }, deleteProperty(data, name) { if (name in data) { return delete data[name]; } else { throw new Error(`${name} is not defined.`); } }, });

可以看到,这些方法都接收原始数据做为第一个参数,然后就是key,也就是上面写的name。

用proxy代理function


let _fn = function (a, b) { console.log(a + b); }; let sum = new Proxy(_fn, { apply(fn, thisArgs, args) { if (args.length < 2) { throw new Error(`参数太少!`); } else { fn(...args); } }, }); sum(1000, 2999);

在使用Proxy代理函数的时候,有一个apply会被调用,该方法第一个参数fn就是所代理的目标函数,第二个thisArgs是调用该代理函数时的this,第三个args就是调用代理函数时所传过来的参数。
上面代码的执行结果很明显了:

用proxy代理class

new Proxy(class {},{
  construct(cls,args){ ... }
})

当我们使用Proxy来代理一个类的时候,我们在对这个代理对象进行实例化的时候就会调用construct方法,在这里面我们可以将代理的目标类变成一个响应类:


let A = new Proxy( class { render() { console.log("rendered~"); } }, { construct(cls, args) { let obj = new cls(); return new Proxy(obj, { set(data, name, val) { data[name] = val; obj.render(); }, }); }, } );

上面,我们代理的目标类里面有一个render方法,在construct里面,我们将原类进行了实例化,但这个实例本身并不是一个可响应的对象(obj),所以我们在里面还要给它加一个代理之后再进行返回。
现在如果进行new A()并且设置属性就会看到:

我在设置a.username的时候,那么就会触发render,其实也就是被set进行了拦截,拦截的过程中想做什么就看我们自己了。