javascript - 不可设置和不可写的属性仍然是可变的

标签 javascript oop immutability

我正在尝试在构造函数中创建一个属性,该属性是不可变的,除非通过原型(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/

相关文章:

javascript - 带有 getElementsByTagName 的嵌套标签名称不起作用

javascript - 仅在鼠标单击并移出元素后才初始化悬停状态

javascript:使用 onclick 切换事件监听器

java - 为什么不允许子类覆盖方法会导致创建不可变对象(immutable对象)?

java - 有什么方法可以将 String 作为可变方法传递给方法吗?

javascript - 更改 DOM 元素的 html 内容并将其作为对象传递

c# - 不可变与可变 C#

javascript - "OOP"-JS - 设置属性等于函数

design-patterns - 如何超越回调编程?

c# - C#/C++ 中缓存或预计算的不可变函数