5

Simple question I am trying the following in my console

let a = new Proxy(new Date(), {})

I am expecting to be able to call

a.getMonth();

but it does not work it throws:

Uncaught TypeError: this is not a Date object. at Proxy.getMonth (<anonymous>)
at <anonymous>:1:3

Funny part is that in Chrome the autocomplete does suggest all the Date functions on a. What am I missing?

Edit in response for @Bergi

I realized that there is a bug in this code aside for my question but here is what I am trying to do:

class myService {
...

makeProxy(data) {
    let that = this;
    return new Proxy (data, {
        cache: {},
        original: {},
        get: function(target, name) {
            let res = Reflect.get(target, name);
            if (!this.original[name]) {
                this.original[name] = res;
            }

            if (res instanceof Object && !(res instanceof Function) && target.hasOwnProperty(name)) {
                res = this.cache[name] || (this.cache[name] = that.makeProxy(res));
            }
            return res;
        },
        set: function(target, name, value) {
            var res = Reflect.set(target, name, value);

            that.isDirty = false;
            for (var item of Object.keys(this.original))
                if (this.original[item] !== target[item]) {
                    that.isDirty = true;
                    break;
                }

            return res;
        }
    });
}

getData() {
    let request = {
     ... 
    }
    return this._$http(request).then(res => makeProxy(res.data);
}

Now getData() returns some dates

MotKohn
  • 3,485
  • 1
  • 24
  • 41
  • Proxies don't work well on builtin objects. Why do you try to use one on dates? – Bergi Dec 18 '17 at 18:47
  • @Bergi I am implementing [this](https://stackoverflow.com/q/41299642/5976576) and my date fields were not working. – MotKohn Dec 18 '17 at 18:49
  • You'd need your proxy to return a wrapper on `getMonth` that would call it with the original `target` rather than the proxy. – loganfsmyth Dec 18 '17 at 18:57
  • @Bergi specifically I'm trying to have some simple change tracking and it all works except for dates – MotKohn Dec 18 '17 at 18:57
  • What do you mean by "*implementing this*" (the script you linked only does some property access logging)? What is your [actual problem](https://meta.stackexchange.com/q/66377)? How do you want it to work with dates? ([Preventing dates from changing](https://stackoverflow.com/q/34907311/1048572) or detecting mutations of dates is extra hard) – Bergi Dec 18 '17 at 18:59
  • It would help if you could show your actual code with the complete proxy handler, not just an empty object. – Bergi Dec 18 '17 at 19:02
  • @Bergi added real code – MotKohn Dec 18 '17 at 19:23
  • Interesting, `x.y = x.y` might mark your instance as dirty :-) I also think you should avoid that `original` and just use the `target`. That said, wouldn't it be the easiest solution to just not wrap date objects, just like you already are not wrapping functions? – Bergi Dec 18 '17 at 19:30
  • @loganfsmyth I'm using bootstrap datepicker. It's hard for me to know what to wrap and what not – MotKohn Dec 18 '17 at 19:31
  • @Bergi my point is to have an `original` so if values are changed back to it's original it would not be dirty, also therefore `x.y=x.y` would not be marked dirty. – MotKohn Dec 18 '17 at 19:34
  • I updated my answer, hopefully it helps. – richbai90 Dec 18 '17 at 20:19

1 Answers1

2

My original answer was all wrong. But the following handler should work

    const handler = {
        get: function(target, name) {
            return name in target ?
                target[name].bind(target) : undefined
        }
    };


    const p = new Proxy(new Date(), handler);
    
    console.log(p.getMonth());
richbai90
  • 4,994
  • 4
  • 50
  • 85
  • Not sure why the down voting, it works on the fiddle and it follows the documentation. – richbai90 Dec 18 '17 at 18:56
  • 1
    @richbai90 One does *not* need to use a separate variable for the target. And the whole question is how to make `p.getMonth()` working - "use `target.getMonth()` instead" does not answer that – Bergi Dec 18 '17 at 19:01
  • 1
    It might have been better to delete this answer and post a new one, to avoid starting with downvotes. Btw, this still doesn't completely work, as you only must bind *functions* not any property that exists in the target. – Bergi Dec 18 '17 at 21:16
  • It works but just as @Bergi pointed out additional guards have to be in place in my case. e.g. make sure target is a date, make sure name is a function. This has nothing to do with your answer but in the end I can't use this because `angular.isDate()` does not recognize `Proxy`ies as a date. I am trying to get them to reopen a [closed issue](https://github.com/angular/angular.js/issues/7143#issuecomment-352567689). Also it would also be nice if you can explain why I would need to do this. – MotKohn Dec 18 '17 at 22:17
  • @MotKohn As I said, it would be much easier if you just didn't wrap your dates in proxies. You won't be able to observe a mutation anyway by that. – Bergi Dec 18 '17 at 23:26
  • 1
    @Bergi you're right I didn't realize that (without ridiculous work, like trapping all the set* funtions) I won't observe mutations. Thanks – MotKohn Dec 19 '17 at 14:21