使现有的不可写和不可配置属性可写和可配置

时间:2016-01-06 21:18:48

标签: javascript

说我有一个对象:

Object.defineProperty(Agent.prototype, 'id', {
    configurable: false,
    writable: false
})

当我构建Agent类时,我决定使id属性不可变:

this

但在某些时候我会想要删除对象。而且因为我们实际上无法删除id,所以我将通过删除Object.defineProperty(agent, 'id', { configurable: true, writable: true }) delete agent.id 属性来削弱对象。所以我再去写一下这个属性:

TypeError: Cannot redefine property: id 

但我当然得到:

id

因为{{1}}已经存在。

如何使现有不可写属性可写?

2 个答案:

答案 0 :(得分:7)

Mozilla documentation

  

当属性已存在时,Object.defineProperty()会尝试   根据描述符中的值修改属性   对象的当前配置。如果旧的描述符有它的   可配置属性设置为false(该属性据说是   “不可配置”),那么除了可写之外没有任何属性可以   改变。如果属性是不可配置的,则其可写属性可以   只能改为假。

换句话说,如果要稍后修改属性定义(可写),则必须在第一个属性定义中将configurable设置为true

请注意,当configurablefalse时,您可以采用另一种方式(使可写属性不可写),但这与您在此处所做的相反。

答案 1 :(得分:5)

有一种方法可以用你的具体例子来做到这一点!然而,它非常顽皮。可以自行决定在生产代码中使用它。

这里的问题不仅是non-configurable属性不是,也是可配置的 - 当你调用Object.defineProperty时,它会检查对象上的现有属性。对象的原型链

解决这个问题很简单:暂时摆脱原型链!

警告: 修改现有对象的原型链是一项危险的操作,只能在成人监督下进行。副作用可能包括:严重的重新编译,减少应用程序范围的性能,以及在清醒的审查员的大多数代码审查程序中自动F.

let parent = {};
Object.defineProperty(parent, "property", {
    get: () => 1,
    configurable: false
});

// here child.property === 1 of course
let child = Object.create(parent);

// however, if we like abusing our JavaScript engine, we can do this:
Object.setPrototypeOf(child, null);

Object.defineProperty(child, "property", {
    get: () => 2,
    configurable: true
});

Object.setPrototypeOf(child, parent);
//now child.property === 2! 

在您的情况下,属性是在Agent原型上定义的,而不是Agent对象本身。因此你可以使用这个技巧。新属性将掩盖旧属性,将替代使用。旧的财产仍然存在,只会被阻止。