javascript中的不可变类型

Sea*_*man 8 javascript oop types immutability

在我看来,Javascript中不可变的类型是不可能的,或者有没有人知道创建它们的任何技巧?这是一种好的还是坏的做法?

例如,像,

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();

}
Run Code Online (Sandbox Code Playgroud)

这当然不是真正不可改变的,但如果它是1)有充分证据表明属性'x'和'y'是getter-functions或2)在验证不变性时抛出某种警报然后它可以作为一个事实上不可变的对象.

思考?

Emi*_*l H 19

您可以使用Object.freeze(o);在新的浏览器中使对象不可变.

Point2D因此可以实现这样的:

var Point2D = function(x, y) { 
    this.x = x; 
    this.y = y;
    Object.freeze(this);
}  
Run Code Online (Sandbox Code Playgroud)

现在,没有新属性可以添加到Point2D对象,并且它的现有属性不能更改:

> 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}"
Run Code Online (Sandbox Code Playgroud)

如果您只想将对象锁定为没有添加任何新属性,则可以Object.seal(o);改为使用.这将允许您改变现有属性,但不能添加新属性.

> 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}"
Run Code Online (Sandbox Code Playgroud)

freeze并且seal是ECMAScript 5.1的一部分,在这里更正式地描述

MDN表示freeze支持:

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

或者,您可以使用更实用的编码样式:

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");
      }
   };
}
Run Code Online (Sandbox Code Playgroud)

用法如下:

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

我知道无法改变"属性" xy使用此方法,因为它们受Point2D函数范围的约束.这种方法在javascript中并不常见(据我所知),但类似于如何在例如Scheme中实现消息传递/ OO.


Kei*_*amo 5

如果您不必担心较旧的浏览器,可以查看一下Object.defineProperty

除此之外,我认为没有太多选择,因为可以在JavaScript中的任何位置重新定义对象的任何功能/属性。

  • @SeanThoman这不是真的。从ECMAScript 5.1开始,“对象”上具有“冻结”功能,该功能使对象不可变。有关在JS中实现不变性的一些不同方式,请参见下面的答案。 (2认同)