【问题标题】:ES5 Defining Unchangeable Arrays / Property ValuesES5 定义不可更改的数组/属性值
【发布时间】:2013-12-25 10:39:41
【问题描述】:

当将数组定义为 ES5 样式对象的属性时,我想使其属性的值无法更改。

'use strict';

var global = Object.create(Object.prototype, {
    names: {
        value: ['Barney', 'Trogdor'],
        writable: false
    }
});

global.names.push('Jackson'); // I expected a read-only error here

console.log(global.names[2]); // >> Jackson

global.names = ['Ooga', 'Booga']; // >> TypeError: "names" is read-only

看来我只保护了财产转让。

有没有办法防止像Array.push() 这样修改我的“不可写”数组的东西?

【问题讨论】:

    标签: javascript arrays object ecmascript-5 writable


    【解决方案1】:

    Object.seal() 似乎有效。

    'use strict';
    
    var global = Object.create(Object.prototype, {
        names: { value: Object.seal(['Barney', 'Trogdor']) }
    });
    global.names.push('Jackson'); // >> TypeError: global.names.push(...) is not extensible
    

    编辑:其实,没关系。

    在前面的示例中,我是否要附加以下代码行:

    global.names[0] = 'Jackson'; // Still works
    

    我相信Object.freeze() 是我真正想要的。

    var global = Object.create(Object.prototype, {
        names: { value: Object.freeze(['Barney', 'Trogdor']) }
    });
    global.names.push('Jackson');  // >> TypeError: global.names.push(...) is not extensible
    global.names[0] = 'Jackson';   // >> TypeError: 0 is read-only
    global.names = ['Jackson'];    // >> TypeError: "names" is read-only
    

    【讨论】:

    • 我认为 Object.create 在这里是不必要的,var global = { names: Object.freeze(['Barney', 'Trogdor']) } 应该足够了。
    • 不。当我用Object.create() 定义names 属性时,该属性隐式为writable: false(为了清楚起见,我只在我的问题代码中明确说明了它)。如果我使用对象文字语法,则该属性变为 writable。尽管如此,我还是打算向global 添加更多属性。
    • 哦,有道理,那样global.names = [] 会失败。我对你的回答做了+1,尽管我通常倾向于让事情变得宽容,例如使用完整的大写名称来表示常量,开发人员会隐含地知道修改这些属性可能会产生意想不到的结果。
    • 是的,数组是现在基本上是一个常数。 global.NAMES 会是一个更好的名字。
    【解决方案2】:

    加载完所有数据后,为什么不覆盖现有的 push 方法:

    global.names.push = function () {return false}
    

    【讨论】:

    • 我还需要覆盖.splice()等。这是一个不利的解决方案。
    • 是的,但是 Object.seal(),虽然是一个很好的解决方案,[关于 IE] 仅适用于版本 9+ 我想知道一个合适的解决方案。如果不支持此方法,也许后备方法是覆盖它们或仅提供对数组的只读访问。
    • 我是在 ES5 的上下文中问这个问题的,这意味着 IE9+。我不需要 Object.seal() 的后备;实际上,考虑到writable: false 的存在,.seal() 对我来说并不是很“语义化”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-08
    • 1970-01-01
    • 2014-06-08
    • 1970-01-01
    • 1970-01-01
    • 2015-03-06
    • 1970-01-01
    相关资源
    最近更新 更多