2017-04-19 49 views
1

JavaScript对象可以被封闭,这样可以防止添加新属性并删除或重新配置现有属性,但属性仍可写。他们也可以被冻结,这是密封加上所有属性变得不可写。不允许更改现有属性的可扩展对象?

显着缺乏的是能够使现有属性为只读,不可移动,不可配置,同时使对象可扩展。这将有助于防止意外践踏对象的属性,同时允许其他代码扩充其属性。

使用vanilla JavaScript创建这样一个对象的最佳或惯用方法是什么?

回答

1

只需通过对象的属性循环,使每一个不可写和不可配置:

var obj = { "foo": 1, "bar": 3 }; 
Object.defineProperty(obj, "baz", { set: a=>a }); 

Object.getOwnPropertyNames(obj).forEach(function(name) { 
    var desc = Object.getOwnPropertyDescriptor(obj, name); 
    desc.configurable = false; 

    // make the property non-writable if it is not an accessor property 
    if(!desc.set && !desc.get) { desc.writable = false; } 

    Object.defineProperty(obj, name, desc); 
}); 

注意,这不会使存取器属性由setget方法“不可写”,因为定义可写性的概念不适用于访问者属性 - 存储到访问者属性中运行该设置者。

+0

如果没有提及,Firefox似乎只会留下“价值”。 – Pointy

+0

@FelixKling是的,我最近了解到'defineProperty'具有定义新属性与修改现有属性的不同行为。尽管现在你已经提到了它,但是我应该添加一个'try' /'catch'来处理一些奇怪的情况 - 显然现有的'set'插槽和'configurable:false'在尝试执行'configure:虚假“。 – apsillers

+0

是啊,注意到现在......我总是被'defineProperty'这个名字弄糊涂了,因为对我来说它表示创建了一个全新的属性(吹掉了所有存在的东西)。 –

1

例如,你可以使用一个getter来设置你的属性,如:

var object = {get property(){return "value"} }; 

使他们只读的,这意味着你不能改变由分配它的价值了,因为在:

object.property = "other"; 

因为它没有固定器。因此object.property将继续返回“值”,但仍可以使用delete运算符删除“属性”键。

+0

这仍然允许该属性被'Object.defineProperty'覆盖。 –

+1

你不必一路走下去用这个尴尬的Object.definePropertty语法来做到这一点 - (因为正如已经提到的那样,你可以很容易地删除它并指定一个新的)但如果你希望你的属性安全地被意外地分配一个不同的值 - 比给定的语法将会做得更好。 –