如何创建固定结构的对象?

时间:2014-12-13 09:05:04

标签: javascript ecmascript-5 revealing-module-pattern

我在揭示模块中有以下代码,但我不确定如何声明/定义imageListItem,它严格来说是一个DTO,并不真正需要隐藏任何信息。我正确定义了这个对象吗?

var imageListItem = function() {
    var _title;
    Object.defineProperty(this, "title", {
        get: function () { return _title; },
        set: function (value) { _title = value; }
        }
    );
};

var imageList = (function () {
    var buffer = new CBuffer();
    return {
        populate: function (listItems) {
            buffer.push(listItems);
        },
        rotate: function() {
             buffer.rotateLeft();
        }
    }
})();

使用imageListItem,我想声明一个对象结构供以后使用。该声明在逻辑上不应取决于以后如何使用该对象。也就是说,我不想发现自己动态地为imageListItem动态分配新属性或从中删除属性。对属性的任何赋值都应严格仅限于已在对象上声明的属性。

Object.freeze()几乎完成了这一点,通过阻止添加或删除属性,但它也阻止了属性的更改。

E.g。我想要这个:

var obj = {
  prop: function() {},
  foo: 'bar'
};

// New properties may be added, existing properties may be changed or removed
obj.foo = 'baz';
obj.lumpy = 'woof';

var o = Object.freeze(obj);

// Now any changes will fail
function fail(){
  'use strict';
  obj.delete(foo); // throws a TypeError
  obj.quaxxor = 'the friendly duck'; // throws a TypeError
}

我没有'想要这个:

// Now any changes will fail
function fail(){
  'use strict';
  obj.foo = 'sparky'; // throws a TypeError
}
你知道吗?我希望freeze阻止将quaxxor添加到obj,但我不希望它阻止我更改foo的值。

1 个答案:

答案 0 :(得分:4)

您要查找的内容可能是Object.preventExtensions()Object.seal()

Object.freeze()类似,两种方法都会阻止将新属性添加到对象中,但仍允许更改现有属性的值

sealpreventExtensions之间的区别在于seal严格禁止从/向数据访问者删除和转换属性,而preventExtensions实际上并未阻止要删除的现有属性:此行为取决于您使用的JS引擎(某些引擎可能会删除该属性,其他引擎可能不会)。

基本上,引用MDN文档:

  

Object.preventExtensions()方法可防止将新属性添加到对象中(即防止将来扩展该对象)。 [...] 请注意,一般情况下,不可扩展对象的属性仍可能已删除

     

Object.seal()方法密封对象,防止将新属性添加到对象中,并将所有现有属性标记为不可配置。只要它们是可写的,当前属性的值仍然可以改变。 [...] 尝试删除或向密封对象添加属性,或将数据属性转换为访问者或反之亦然,将失败

以下是演示两种方法行为的示例:

var myFirstObj = { foo: 1 },
    mySecondObj = { bar: "baz" };

Object.preventExtensions(myFirstObj);
Object.seal(mySecondObj);

myFirstObj.foo = false; // Works fine
mySecondObj.baz = "hello"; // Works fine
delete myFirstObj.foo; // May work fine depending on your JS engine

(function() {
    'use strict';
    myFirstObj.qux = 'something'; // Throws a TypeError
    mySecondObj.qux = 'something'; // Throws a TypeError
    delete mySecondObj.foo; // Throws a TypeError
})();

现在,谈论你的ImageListItem对象,你可以实现你想要的只需添加一行代码:

var ImageListItem = function() {
    var _title;
    Object.defineProperty(this, "title", {
        get: function () { return _title; },
        set: function (value) { _title = value; }
    });

    // Choose the one which fits your needs
    Object.preventExtensions(this);
    // or
    Object.seal(this);
};