why are target and receiver not the same in this javascript proxy?

212 Views Asked by At

I am working with JavaScript Proxy and do not understand why the target and the receiver are different in both the get() and set() traps. They appear to be the same (based on console logging). The mozilla docs say that the receiver is either the proxy or the object that inherits from the proxy; in this case, it's clearly not the proxy. (FWIW, this is the proxy itself in the get() and set() traps.)

This code:

const s = 'this is a string';
const o = {a: s};

const p = new Proxy(o, {
  get(target, prop, recv) {
    console.log('get: target', target, 'recv', recv, 'same', target === recv);
    return target[prop];
  },
  set(target, prop, value, recv) {
    console.log('set: target', target, 'recv', recv);
    Reflect.set(target, prop, value, recv);
    //target[prop] = value;
    console.log('set: target', target, 'recv', recv, 'same', target === recv);
    return value;
  },
});

let z = p.a;
p.a = 'also a string';
z = p.a;

results in this output:

get: target { a: 'this is a string' } recv { a: 'this is a string' } same false
set: target { a: 'this is a string' } recv { a: 'this is a string' }
set: target { a: 'also a string' } recv { a: 'also a string' } same false
get: target { a: 'also a string' } recv { a: 'also a string' } same false
1

There are 1 best solutions below

3
bmacnaughton On

The reason is that the receiver is the proxied object and console.log() transparently renders it.

Adding this line console.log('this', this, 'p === recv', p === recv, this === recv); to the set() trap results in this output:

this { get: [Function: get], set: [Function: set] } p === recv true false

Mozilla docs say that this is bound to the handler, but it looks like this is bound to the object containing the handlers. And that would explain why this is rendered the way it is.

This could also explain why Titus saw infinite recursion in a browser implementation - console.log() is fetching the original object through the proxy to display recv. But I still can't explain why the node.js implementation does not recurse until the stack overflows.