我正在尝试在构造函数中创建一个属性,该属性是不可变的,除非通过原型(prototype)函数。我正在尝试关闭 MDN 文档:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties 。但似乎没有一种方法可以使属性完全不可变。考虑一个简单的例子:
function Test(){
Object.defineProperties(this,{
elems : { value : [] }
})
}
Test.prototype.addElem = function(newElem){
if (this.elems.indexOf(newElem) == -1){
this.elems.push(newElem);
}
};
在大多数情况下工作正常(不可分配):
>a = new Test()
Object { , 1 more… }
>a.elems
Array [ ]
>a.elems = 10
10
>a.elems
Array [ ]
不幸的是,它仍然是可变的。考虑:
>a.elems.push(10)
1
>a.elems
Array [ 10 ]
我确信它们是其他函数(数组或对象方法?),它们将更改不可写和不可设置属性的值。 Push 就是我遇到的一个。有办法做到这一点吗?我知道一种可能的解决方案是:
function Test(){
var elems = [];
this.addElem = function(newElem){
if (elems.indexOf(newElem) == -1){
elems.push(newElem);
}
}
}
但我读到这是内存效率低下的,尤其是当“类”有很多实例时。另外,我现在做的可能有很多这样的方法,所以我更担心内存的考虑。
有什么想法吗?我对 JS 原型(prototype)设计的所有复杂性并不是非常了解。
最佳答案
在 JavaScript 中,对象默认是可扩展的,但如果您能够利用 ES5,您应该能够使用 Object.seal()
或Object.freeze()
获取不可变属性的方法。
Object.freeze()
的 MDN 文档有一个示例,展示了如何递归地卡住(“deepFreeze”)对象的所有属性,从而有效地使其完全不可变。
这是一个概念证明,它将问题中的代码与文档中的代码相结合:
function Test() {
Object.defineProperties(this, {
elems : { value : [] }
})
}
Test.prototype.addElem = function(newElem) {
if (this.elems.indexOf(newElem) == -1) {
this.elems.push(newElem);
}
};
function deepFreeze(obj) {
// Retrieve the property names defined on obj
var propNames = Object.getOwnPropertyNames(obj);
// Freeze properties before freezing self
propNames.forEach(function(name) {
var prop = obj[name];
// Freeze prop if it is an object
if (typeof prop == 'object' && prop !== null)
deepFreeze(prop);
});
// Freeze self (no-op if already frozen)
return Object.freeze(obj);
}
a = new Test();
a.elems.push(1);
console.log(a.elems); // [1]
deepFreeze(a);
a.elems.push(2);
console.log(a.elems); // Error
在FireBug中,对象“深度卡住”后的a.elems.push()
返回TypeError
异常,表明该属性不可写;
TypeError: can't define array index property past the end of an array with non-writable length
Safari 检查器还返回一个 TypeError
异常:
TypeError: Attempted to assign to readonly property.
关于javascript - 不可设置和不可写的属性仍然是可变的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35214248/