-1

I'm working with JS Proxies for fun and have made decent progress. But currently it's all at a single level. What I would like is to have nested Proxies be returned if I'm making a nested call/access, otherwise just return the object.

// example calls/accesses
data.settings = {fire: true};

data.settings.fire // nested call
// returns true

data.settings // top level call
// returns {fire: true}

// the proxy code
const data = new Proxy({}, {
  get: function(target, property, receiver) {
    // how to figure out nestedCall?
    if (nestedCall) {
      return new Proxy(target[property], {
        get: function(subTarget, subProperty, subReceiver) {
          return 'nonsense, there is nothing nested here';
        }.
      });
    }
    else {
      return target[property];
    }
  },
});

Is this even possible?

user3840170
  • 26,597
  • 4
  • 30
  • 62
Merlin -they-them-
  • 2,731
  • 3
  • 22
  • 39
  • I don't see any calls in your examples at all? – Bergi Apr 20 '18 at 15:20
  • 1
    I suppose it would be more accurate to say nested access since I'm not calling a function – Merlin -they-them- Apr 20 '18 at 17:10
  • So @Bergi is right, the object referenced by the 'settings' property is not proxied in your example, so the accessing of the 'fire' property doesn't get intercepted. Does that answer your question? If not maybe you can expand on your question to explain better what you are trying to accomplish. – ansibly Apr 20 '18 at 18:15
  • And to clarify, as @Bergi stated, there is no way to distinguish within the 'get' trap on the root object that 'settings' is being accessed as part of a chain. – ansibly Apr 20 '18 at 18:33
  • Well the settings property would get proxied on the call if nestedCall is true, but since there is no way to determine if nestedCall is possible, it can't be done. – Merlin -they-them- Apr 20 '18 at 20:24
  • @merlinpatt You should simply always return a proxy, and then it either gets another (nested) access (for `.fire`) or it does not. – Bergi Apr 20 '18 at 21:39

2 Answers2

2

Is this even possible?

No, it is not possible to distinguish

const val = data.settings.fire; // two accesses

from

const obj = data.settings; // one access
const val = obj.fire; // another access

and return a plain object, instead of a proxy for it, for .settings only in the second case.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
1

Just use a 'set' trap. This 'set' trap example proxies objects as they are being assigned. You can alter the criteria to be more sophisticated as needed.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy#A_complete_traps_list_example

const whatICareAbout = ['settings', 'mediaSettings', 'fire', 'video'];

const proxy = {
  get: function(obj, prop) {
    if(whatICareAbout.includes(prop)) console.log('Get...', prop);
    return obj[prop];
  },
  set: function(obj, prop, value) {
    if(typeof value === 'object') {
      console.log('Proxy...', prop);
      obj[prop] = new Proxy(value, proxy);
    } else {
      obj[prop] = value;
    }
  }
};

const p = new Proxy({}, proxy);
p.settings = {fire: true};
p.settings.mediaSettings = {video: false};
console.log(p.settings);
console.log(p.settings.mediaSettings);
ansibly
  • 398
  • 3
  • 7