【问题标题】:How can I create an object of fixed structure?如何创建固定结构的对象?
【发布时间】:2014-12-13 09:05:03
【问题描述】:

我的显示模块中有以下代码,但我不确定如何声明/定义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() 几乎实现了这一点,通过防止添加或删除属性,但它也防止更改属性。

例如我想要这个:

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 的值。

【问题讨论】:

  • 如果您不需要任何信息隐藏(或逻辑),为什么要将其设置为访问器属性?只需使用this.title = undefined;
  • (不确定这是否是您要寻找的全部答案)
  • @Bergi,它可能很接近。我只是不知道如何声明一个未初始化的变量。
  • 为什么这个属性根本没有初始化?实际创建它们的代码是什么?
  • @Bergi 除了this.title = undefinedObject.defineProperty 之外,没有任何东西可以创建它们。这就是我的问题的重点——如何声明它们。

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


【解决方案1】:

您要查找的内容可能是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);
};

【讨论】:

  • 您链接到的 Mozilla 页面显示“请注意,一般来说,不可扩展对象的属性仍可能删除。”我没有在我的问题中具体说明,但最好有,我现在添加它。然而,您的示例表明 delete wilI 失败。但是preventExtensions 很高兴知道,谢谢。
  • 这不是正确的答案吗?上面你刚刚说你想要preventing properties being added or removed?我会尝试回答,但您的回答太善变,无法尝试。
  • @ProfK 我编辑了我的答案,添加了你需要的东西,看看吧:)
  • 完美!谢谢,@MarcoBonelli。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-05
  • 1970-01-01
  • 1970-01-01
  • 2019-03-23
相关资源
最近更新 更多