skip to Main Content

I need to exercise some code in data mapping functions. For this, I need a proxy that returns an iterable array with one element (itself; an iterable array) when any property is requested. This will activate all loops and property checks in the data mapper layer (not shown here).

Something like this:

p = new Proxy([], {
  get(obj, prop) {
    if(prop === 'length') return obj.length
    if(prop === 'push') return obj.push
    if(p.length === 0) p.push(p)
    return p
  }}
)

This starts off well:

> p.any.length
1

but fails here:

> for(let v of p.any){console.log(v)}
Uncaught TypeError: p.any is not iterable

I need the loop to iterate and console.log one element:

> p.any
Proxy [
  <ref *1> [ Proxy [ [Circular *1], [Object] ] ],
  { get: [Function: get] }
]

Some proxy docs and guides cover the in and object but do not cover the of and array.

2

Answers


  1. Note: I am by no means a pro with the Proxy API, but hopefully, I can help you out at least a bit.

    Could you do something like this?

    p = new Proxy([], {
      get(obj, prop) {
        if (prop === "length") return obj.length;
        if (prop === "push") return obj.push;
        if (p.length === 0) p.push(p);
        return [p]; // Wrapped the proxy in an array
      },
    });
    

    Then when you run your loop:

    for (let v of p.any) {
      console.log(v);
    }
    

    You should see this:

    Proxy [
      <ref *1> [ Proxy [ [Circular *1] ] ],
      { get: [Function: get] }
    ]
    
    const p = new Proxy([], {
      get(obj, prop) {
        if (prop === "length") return obj.length;
        if (prop === "push") return obj.push;
        if (p.length === 0) p.push(p);
        return [p]; // Wrapped the proxy in an array
      },
    });
    
    for (let v of p.any) {
      console.log(v);
    }
    Login or Signup to reply.
  2. The error occurs because the for..of loop will query the proxy object with the @@iterator symbol property, and your code will react by returning p, and not an iterator as is what Array.prototype[Symbol.iterator] returns.

    The solution is simple: just like you let the access to length and push let through, also do the same with symbol properties.

    Another thing you may consider is to not do p.push(p), but obj.push(p). That way you can ignore a push that is issued by the user, and can perform this action as the first action.

    Resulting code:

    const p = new Proxy([], {
      get(obj, prop) {
        if (obj.length === 0) obj.push(p);
        if (prop === 'length' || typeof prop === "symbol") return obj[prop];
        return p;
      }}
    );
    
    for (let v of p) {
      console.log(v);
    }
    
    console.log(p);
    console.log(p.any);
    console.log(p.any.any);

    Maybe you should also let other property accesses pass through, like array methods (forEach, reduce, map, filter,… etc).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search