Is there a way to Object.freeze() a JavaScript Date?

后端 未结 5 1706
醉梦人生
醉梦人生 2020-12-09 00:46

According to MDN Object.freeze() documentation:

The Object.freeze() method freezes an object: that is, prevents new prop

5条回答
  •  情歌与酒
    2020-12-09 01:21

    This is a really good question!

    T.J. Crowder's answer has an excellent solution, but it got me thinking: What else can we do? How can we go around the Date.prototype.setTime.call(yourFrozenDate)?

    1st attempt: "Wrapper"

    One direct way is to provide an AndrewDate function which wraps a date. It has everything a date has minus the setters:

    function AndrewDate(realDate) {
        var proto = Date.prototype;
        var propNames = Object.getOwnPropertyNames(proto)
            .filter(propName => !propName.startsWith('set'));
    
        return propNames.reduce((ret, propName) => {
            ret[propName] = proto[propName].bind(realDate);
            return ret;
        }, {});
    }
    
    var date = AndrewDate(new Date());
    date.setMonth(2); // TypeError: d.setMonth is not a function
    

    What this does is create an object which has all the properties that an actual date object has and uses Function.prototype.bind to set their this.

    This isn't a fool proof way of gathering around the keys, but hopefully you can see my intention.

    But wait...looking at it a little further here and there, we can see that there's a better way of doing this.

    2nd attempt: Proxies

    function SuperAndrewDate(realDate) {
        return new Proxy(realDate, {
            get(target, prop) {
                if (!prop.startsWith('set')) {
                    return Reflect.get(target, prop);
                }
            }
        });
    }
    
    var proxyDate = SuperAndrewDate(new Date());
    

    And we solved it!

    ...sort of. See, Firefox is the only one right now which implements proxies, and for some bizarre reasons date objects can't be proxied. Furthermore, you'll notice that you can still do things like 'setDate' in proxyDate and you'll see completions in console. To overcome that more traps need to be provided; specifically, has, enumerate, ownKeys, getOwnPropertyDescriptor and who knows what weird edge cases there are!

    ...So on second thought, this answer is nearly pointless. But at least we had fun, right?

提交回复
热议问题