开发者

Immutable types in javascript

开发者 https://www.devze.com 2023-04-12 16:56 出处:网络
It seems to me that immu开发者_如何学Pythontable types are impossible in Javascript, or does anyone know of any tricks to create them? Is it a good or bad practice?

It seems to me that immu开发者_如何学Pythontable 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?


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.


If you don't have to worry about older browsers you can look into Object.defineProperty.

Other than that, I don't think there is much of an option since any function/property on an object can be redefined at any point in JavaScript.


It is possible in javascript to define property getters and setters:

function Point2D(){
    this.__defineGetter__("x", function(){

    });

    this.__defineSetter__("x", function(val){

    });
}

The underlying variables they modify will, however, be mutable.


Point2D = function(x, y)
{
    var privateX = x;
    var privateY = y;

    return {
        getX: function()
        {
            return privateX;
        },
        getY: function()
        {
            return privateY;
        }
    };
};

var foo = new Point2D(20, 30);
console.log(foo.getX(), foo.getY());

Since privateX and privateY only exist in the scope of the constructor, they can only be accessed by the functions defined in the constructor (getX, getY).


There is now a new javascript reserved word const. const makes runtime constants that are immutable.

Note: const does NOT render objects or arrays to be immutable.

You can be kinda sorta immutable-ish by using Object.freeze to prevent mutation of objects.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const http://caniuse.com/#search=const

DEMO


Throwing some ES2015 in the mix can help:

function Point2D(x, y) {
  const instanceX = x,
    instanceY = y;

  return {
    get x() { return instanceX; },
    get y() { return instanceY; }
  }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消