rest getters and setters (sorry, __noSuchMethod__ again)

# Tobias Buschor (7 years ago)

I realy like the possibility to react to dynamic properties, like what you can do with Proxies. But Proxies are not the (my) perfect solution.

class items {
    constructor() {
        return new Proxy(this, {
            get(target, name) {
                if (name[0] === '$') return
target.getItem(name.substr(1)).value;
                return target[name];
            }
        });
    }
    getItem(id) {
        return this._item[id];
    }
}

myItems = new items(); // [1]
myItems.$1

[1] this direct returns a Proxy for the newly created Object, ok.. i can do "myItems.$3" instead of "myItems.getItem(4)";

but i can not act like this inside the Object, because i am not working with the Proxy

class items {
    getItem3(){
        return this.$3;
    }
}

I have to do this instead...

class items {
    getItem3(){
        return this.getItem(3);
    }
}

What about something like getters and setters for the rest (undefined properties)?

class items {
    get...(name){
        if (name[0] === '$') return this.getItem(name.substr(1)).value;
    }
    set...(name, value){
        // implement setter for unknown
    }
}

Maybe a stupid idea and certainly not thought through. But what do you think?

# Logan Smyth (7 years ago)

but i can not act like this inside the Object, because i am not working

with the Proxy

You're not quite taking into account the behavior of this in JS. this is set at call-time, so when you do

class items {
    // ...

    getItem3(){
        return this.$3;
    }
}

this depends on how getItem3 was called. In your case if you do

myItems = new items();
myItems.getItem3();

this will be myItems because that is how you have called it, meaning that getItems3() will behave just like if you had done myItems.$3.

Your code works as expected in this Fiddle: jsfiddle.net/2dgefd9d

# Tobias Buschor (7 years ago)

wow, you are right!

But this does not work. It returns "undefined"

class items {
    // ...
    get item3(){
        return this.$3;
    }
}
myItems = new items();
console.log( myItems.item3 );

see jsfiddle.net/2dgefd9d/1

I see, the getter is called on the object itself and not on the proxy....

2017-07-29 2:05 GMT+02:00 Logan Smyth <loganfsmyth at gmail.com>:

# Logan Smyth (7 years ago)

I almost mentioned that last time, alas. You have a bug in your proxy get handler. It should be:

get(target, name, receiver) {
    if (name[0] === '$') return target.getItem(name.substr(1));

    return Reflect.get(target, name, receiver);
}

The third argument receiver being the important part here. Reflect.get(target, name, receiver) is the correct reproduction of the default non-proxy get behavior. target[name] is close, but loses information, causing the bad behavior you are seeing. target is the actual target initially passed to new Proxy, while receiver is the object that was actually used to access the property, which is the actual proxy object in this case.

Updated fiddle: jsfiddle.net/2dgefd9d/2

# Tobias Buschor (7 years ago)

Ok, thank you Logan.

Still have to digest :)

I'm now fine with proxies, you can ignore this post.

2017-07-29 2:50 GMT+02:00 Logan Smyth <loganfsmyth at gmail.com>:

# Allen Wirfs-Brock (7 years ago)

On Jul 28, 2017, at 5:50 PM, Logan Smyth <loganfsmyth at gmail.com> wrote:

return Reflect.get(target, name, receiver);

}

The third argument `receiver` being the important part here. `Reflect.get(target, name, receiver)` is the correct reproduction of the default non-proxy `get` behavior. `target[name]` is close, but loses information, causing the bad behavior you are seeing. `target` is the actual target initially passed to `new Proxy`, while `receiver` is the object that was actually used to access the property, which is the actual proxy object in this case.

yes, the is exactly the reason for the 3rd parameter of Reflect.get