在我看来,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();
}
当然,这不是真正不可改变的,但如果它是1)有充分证据表明属性'x'和'y'是getter-functions或者2)在验证不变性时会抛出某种警报然后它可以充当事实上的不可变对象。
思想?
答案 0 :(得分:19)
您可以使用Object.freeze(o);
在新浏览器中使对象不可变。
Point2D
因此可以这样实现:
var Point2D = function(x, y) {
this.x = x;
this.y = y;
Object.freeze(this);
}
现在没有新属性可以添加到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}"
如果您只想锁定对象以不添加任何新属性,则可以使用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}"
freeze
和seal
是ECMAScript 5.1的一部分described more formally here
MDN表示支持freeze
:
或者,您可以使用更具功能性的编码风格:
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");
}
};
}
用法就像:
> var p = Point2D(1,2)
undefined
> p("x")
1
> p("y")
2
> p("foo")
Error: Property 'foo' not supported
我知道无法改变"属性" x
和y
使用此方法,因为它们受Point2D
函数范围的约束。这种方法在javascript中并不常见(据我所知),但类似于如何在例如Scheme中实现消息传递/ OO。
答案 1 :(得分:5)
如果您不必担心旧浏览器,可以查看Object.defineProperty
。
除此之外,我认为没有太多选项,因为对象上的任何函数/属性都可以在JavaScript中的任何位置重新定义。
答案 2 :(得分:2)
可以在javascript中定义属性getter和setter:
function Point2D(){
this.__defineGetter__("x", function(){
});
this.__defineSetter__("x", function(val){
});
}
然而,他们修改的基础变量将是可变的。
答案 3 :(得分:2)
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());
由于privateX和privateY仅存在于构造函数的范围内,因此只能通过构造函数中定义的函数访问它们(getX,getY)。
答案 4 :(得分:0)
现在有一个新的javascript保留字const
。 const
使运行时常量不可变。
通过使用Object.freeze
来防止对象突变,你可以有点不可变。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const http://caniuse.com/#search=const
答案 5 :(得分:-1)
投入一些ES2015可以提供帮助:
i