Эта статья будет интересна тем кто использует Proxy, для реактивности или рефлексии.
Поведение JS методов, нам хорошо знакома если мы просто используем их в рамках объекта.
Если метод передается через свойство другому объект, то он работает с тем this, который определен в рамках другого объекта.
Это необходимо ясно понимать при использовании Proxy.
Результатом будет что console.log(Label2); выдаст нам Proxy объект, после которого Proxy сработает и на target и на prop (см Label1); но код же вроде как работает. Что париться.
Метод начинает общаться с объектом (this) через Proxy. Это удобно и закономерно когда пишем рефлексию (отражение свойств объекта и изменения поведения не изменяя объект). Но если это нам не нужно и нам нужно чтобы метод работал конкретно с объектом target, как тут быть? Зачем нам замедлять код?
Тем более что если внесем больше логики, например фильтры свойств и др, код может случайно загнуться. А при написании реактивного кода, идет «зашкаливание». (Например при запросе метода и последующем его исполнении, метод запрашивает свойства через прокси на которые уже повешены события ). Т.е события начинают срабатывать там где не надо и их не ждали.
Как понял this уже переопределен для метода до вызова Handler.get в Proxy. Надо просто снова его переопределить следующим образом:
Получим вот такой код:
Cоздание цепочки реактивности/рефлексии. Каждый вложенный объект будет являться Proxy:
Спасибо за внимание!
Поведение JS методов, нам хорошо знакома если мы просто используем их в рамках объекта.
Если метод передается через свойство другому объект, то он работает с тем this, который определен в рамках другого объекта.
let obj1={prop1:'HEllo',method1(){console.log(this);}} let obj2={method2:obj1.method1}; obj2.method2();
Это необходимо ясно понимать при использовании Proxy.
class MyProxy{ constructor(target){ return new Proxy(target,this); } get(target,prop){ console.log(target,prop); //Label1 return target[prop]; } } class PrimitiveType { constructor(target,prop) { this.target=target; this.prop=prop; } get(){ console.log(this);// Label2 return this.target[this.prop]; } } prim=new PrimitiveType({a:'Привет'},'a'); proxy= new MyProxy(prim); proxy.get();
Результатом будет что console.log(Label2); выдаст нам Proxy объект, после которого Proxy сработает и на target и на prop (см Label1); но код же вроде как работает. Что париться.
Метод начинает общаться с объектом (this) через Proxy. Это удобно и закономерно когда пишем рефлексию (отражение свойств объекта и изменения поведения не изменяя объект). Но если это нам не нужно и нам нужно чтобы метод работал конкретно с объектом target, как тут быть? Зачем нам замедлять код?
Тем более что если внесем больше логики, например фильтры свойств и др, код может случайно загнуться. А при написании реактивного кода, идет «зашкаливание». (Например при запросе метода и последующем его исполнении, метод запрашивает свойства через прокси на которые уже повешены события ). Т.е события начинают срабатывать там где не надо и их не ждали.
Как исправить
Как понял this уже переопределен для метода до вызова Handler.get в Proxy. Надо просто снова его переопределить следующим образом:
let answer=target[prop]; if(typeof target[prop] ==='function'){ answer=target[prop].bind(target); }
Получим вот такой код:
class MyProxy{ constructor(target){ return new Proxy(target,this); } get(target,prop){ // по уму название ему valueOf. Но для наглядного поведения ему имя get let answer=target[prop]; if(typeof target[prop] ==='function'){ answer=target[prop].bind(target); } return answer; } } class PrimitiveType { constructor(target,prop) { this.target=target; this.prop=prop; } get(){ console.log(this); return this.target[this.prop]; } } prim=new PrimitiveType({a:'Привет'},'a'); proxy= new MyProxy(prim); proxy.get();
Напоследок в качестве бонуса.
Cоздание цепочки реактивности/рефлексии. Каждый вложенный объект будет являться Proxy:
class MyProxy{ constructor(target){ return new Proxy(target,this); } get(target,prop){ let answer; let tp=target[prop];// так необходимо если target - Proxy или target[prop] -getter if(typeof tp==='object' && tp!==null){ answer =new MyProxy(tp); } else if(typeof tp ==='function'){ // Если необходима реактивность. Для рефлексии стоит убрать этот блок answer=tp.bind(target); } else { answer=tp; } return answer; } } class PrimitiveType { constructor(target,prop) { this.target=target; this.prop=prop; } valueOf(){ console.log(this); return this.target[this.prop]; } } prim=new PrimitiveType({a:'Привет'},'a'); qwer={q:prim}; proxy= new MyProxy(qwer); proxy.q
Спасибо за внимание!