Эта статья будет интересна тем кто использует 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
Спасибо за внимание!