Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

According to MDN Object.freeze() documentation:

The Object.freeze() method freezes an object: that is, prevents new properties from being added to it; prevents existing properties from being removed; and prevents existing properties, or their enumerability, configurability, or writability, from being changed. In essence the object is made effectively immutable. The method returns the object being frozen.

I was expecting that calling freeze on a date would prevent changes to that date, but it does not appear to be working. Here's what I am doing (running Node.js v5.3.0):

let d = new Date() Object.freeze(d) d.setTime(0) console.log(d) // Wed Dec 31 1969 16:00:00 GMT-0800 (PST) 

I would have expected the call to setTime to either fail or do nothing. Any ideas how to freeze a date?

like image 808
Andrew Eisenberg Avatar asked Jan 20 '16 18:01

Andrew Eisenberg


People also ask

How do you freeze an object in JavaScript?

Object.freeze() Method freeze() which is used to freeze an object. Freezing an object does not allow new properties to be added to an object and prevents from removing or altering the existing properties. Object. freeze() preserves the enumerability, configurability, writability and the prototype of the object.

What is the difference between const and object freeze ()?

Object. freeze works on values, and more specifically, object values. It makes an object immutable, i.e. you cannot change its properties. Basically, const is the new var ; it's just block-scoped and prevents reassignment.

Can you object freeze an array?

As an object, an array can be frozen; after doing so, its elements cannot be altered and no elements can be added to or removed from the array. freeze() returns the same object that was passed into the function. It does not create a frozen copy.

How can we make an object immutable in JavaScript?

You can freeze (make immutable) an object using the function Object. freeze(obj) . The object passed to the freeze method will become immutable. The freeze() method also returns the same object.


1 Answers

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

I don't think so. You can get close, though, see under the line below. But first let's see why just Object.freeze doesn't work.

I was expecting that calling freeze on a date would prevent changes to that date...

It would if Date used an object property to hold its internal time value, but it doesn't. It uses a [[DateValue]] internal slot instead. Internal slots aren't properties:

Internal slots correspond to internal state that is associated with objects and used by various ECMAScript specification algorithms. Internal slots are not object properties...

So freezing the object doesn't have any effect on its ability to mutate its [[DateValue]] internal slot.


You can freeze a Date, or effectively so anyway: Replace all its mutator methods with no-op functions (or functions that throw an error) and then freeze it. But as observed by zzzzBov (nice one!), that doesn't prevent someone from doing Date.prototype.setTime.call(d, 0) (in a deliberate attempt to get around the frozen object, or as a byproduct of some complicated code they're using). So it's close, but no cigar.

Here's an example (I'm using ES2015 features here, since I saw that let in your code, so you'll need a recent browser to run it; but this can be done with ES5-only features as well):

"use strict";    let d = new Date();  freezeDate(d);  d.setTime(0);  snippet.log(d);    function nop() {  }    function freezeDate(d) {    allNames(d).forEach(name => {      if (name.startsWith("set") && typeof d[name] === "function") {        d[name] = nop;      }    });    Object.freeze(d);    return d;  }  function allNames(obj) {    var names = Object.create(null); // Or use Map here    var thisObj;        for (thisObj = obj; thisObj; thisObj = Object.getPrototypeOf(thisObj)) {      Object.getOwnPropertyNames(thisObj).forEach(name => {        names[name] = 1;      });    }    return Object.keys(names);  }
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->  <script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

I think all the mutator methods of Date start with set, but if not it's easy to tweak the above.

like image 56
T.J. Crowder Avatar answered Sep 20 '22 04:09

T.J. Crowder