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?
JavaScript strings are immutable. This means that once a string is created, it is not possible to modify it.
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.
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.
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.
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With