Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Immutable types in javascript

It seems to me that immutable types are impossible in Javascript, or does anyone know of any tricks to create them? Is it a good or bad practice?

For instance something like,

var Point2D = function Point2D(x, y) {

    var _x = x;
    var _y = y;

    function constructor() {

        var self = {};

        // Pseudo-Immutable concept
        self.x = function() {
            return _x;
        }();

        self.y = function() {
            return _y;
        }();

        return self;
    }

    return constructor();

}

Which of course isn't really immutable, but if it were either 1) well-documented that the properties 'x' and 'y' are getter-functions or 2) threw some kind of alert when validating for immutability then it could act as a de-facto immutable object.

Thoughts?

like image 537
Sean Thoman Avatar asked Oct 13 '11 19:10

Sean Thoman


People also ask

What are immutable data types in JavaScript?

JavaScript strings are immutable. This means that once a string is created, it is not possible to modify it.

What are immutable and mutable types in JavaScript?

In JavaScript, only objects and arrays are mutable, not primitive values. A mutable object is an object whose state can be modified after it is created. Immutables are the objects whose state cannot be changed once the object is created.

What types are immutable?

Immutable data types differ from their mutable counterparts in that they can not be changed after creation. Some immutable types include numeric data types, strings, bytes, frozen sets, and tuples.

Are JavaScript primitive types immutable?

All primitives are immutable; that is, they cannot be altered. It is important not to confuse a primitive itself with a variable assigned a primitive value. The variable may be reassigned to a new value, but the existing value can not be changed in the ways that objects, arrays, and functions can be altered.


1 Answers

You can use Object.freeze(o); to make an object immutable in newish browsers.

The Point2D could thus be implemented like this:

var Point2D = function(x, y) { 
    this.x = x; 
    this.y = y;
    Object.freeze(this);
}  

Now no new properties can be added to a Point2D object and it's existing properties can not be altered:

> var p = new Point2D(99, 123)
undefined
> p.x
99
> p.x = 7
7
> p.x
99
> p.foo = "This won't be added"
undefined
> JSON.stringify(p);
"{"x":99,"y":123}"

If you only want to lock down the object to not have any new properties added then you can use Object.seal(o); instead. This will allow you to mutate existing properties, but not add new ones.

> var o = {x:1, y:2}
undefined
> Object.seal(o);
[object Object]
> JSON.stringify(o);
"{"x":1,"y":2}"
> o.foo = "This won't be added";
99
> o.x = 37 // Seal allows to mutate object 
37
JSON.stringify(o);
"{"x":37,"y":2}"

freeze and seal is part of ECMAScript 5.1 described more formally here

MDN states that freeze is supported in:

  • Firefox (Gecko) 4 (2.0)
  • Chrome 6
  • Internet Explorer 9
  • Opera 12
  • Safari 5.1

Alternatively, you could use a more functional coding style:

var Point2D = function(x, y) { 
   return function(prop) { 
      switch (prop) {
         case "x": return x;
         case "y": return y;
         default: throw new Error("Property '" + prop + "' not supported");
      }
   };
}

Usage would then be like:

> var p = Point2D(1,2)
undefined
> p("x")
1
> p("y")
2
> p("foo")
Error: Property 'foo' not supported

I know of no way to alter the "properties" x and y using this aproach since they are bound by the scope of the Point2D function. This approach is not commonly seen in javascript (as far as I know), but is similar to how message passing/OO can be achieved in for instance Scheme.

like image 142
Emil H Avatar answered Nov 15 '22 18:11

Emil H