ES6——Proxy的this问题
虽然 Proxy 可以代理针对目标对象的访问,但它不是目标对象的透明代理,即不做任何拦截的情况下,也无法保证与目标对象
的行为一致。主要原因就是在 Proxy 代理的情况下,目标对象内部的 this 关键字会指向 Proxy 代理。
const target = { m: function() { console.log(this === proxy); } }; const handler = {}; const proxy = new Proxy(target,handler); target.m() // false proxy.m() // true
上面代码中,一旦 proxy 代理 target.m ,后者内部的 this 就是指向 proxy ,而不是 target 。
下面是一个例子,由于 this 指向的变化,导致 Proxy 无法代理目标对象。
const _name = new WeakMap(); class Person { constructor(name) { _name.set(this, name); } get name() { return _name.get(this); } } const jane = new Person('Jane'); jane.name // 'Jane' const proxy = new Proxy(jane,{}); proxy.name // undefined
上面代码中,目标对象 jane 的 name 属性,实际保存在外部 WeakMap 对象 _name 上面,通过 this 键区分。由于通过 proxy.name 访
问时, this 指向 proxy ,导致无法取到值,所以返回 undefined 。
此外,有些原生对象的内部属性,只有通过正确的 this 才能拿到,所以 Proxy 也无法代理这些原生对象的属性。
const target = new Date(); const handler = {}; const proxy = new Proxy(target,handler); proxy.getDate(); // TypeError: this is not a Date object.
上面代码中, getDate 方法只能在 Date 对象实例上面拿到,如果 this 不是 Date 对象实例就会报错。这时, this 绑定原始对
象,就可以解决这个问题。
const target = new Date('2015-01-01'); const handler = { get(target, prop) { if (prop === 'getDate') { return target.getDate.bind(target); } return Reflect.get(target, prop); } }; const proxy = new Proxy(target,handler); proxy.getDate() // 1