Make an existing non-applicable and non-configurable property writable and custom

Let's say I have an object:

var agent = new Agent({name: 'James', type: 'secret', id: 007}) 

When I built the Agent class, I decided to make the id property immutable:

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

But at some point I want to mark the object to be deleted. And since we cannot actually remove this , I am going to destroy the object by deleting the id property. Therefore, I proceed to write the property again:

 Object.defineProperty(agent, 'id', { configurable: true, writable: true }) delete agent.id 

But of course I get:

 TypeError: Cannot redefine property: id 

Because id already exists.

How can I create an existing property that is not writable?

+2
javascript
source share
2 answers

Mozilla documentation says

When a property already exists, Object.defineProperty () tries to change the property according to the values ​​in the handle and the current configuration of the object. If the old custom attribute descriptor is set to false (the property is called "non-configurable"), then no attribute other than the one being written can be changed. If the property is not configurable, its writable attribute can only change to false.

In other words, you must set configurable to true in the first property definition if you want to change the property definition later (to be writable).

Note that you can go the other way (making the property writable the property is not writable) if configurable is false , but this is the opposite of what you are doing here.

+4
source share

There is a way to do this, with your specific example! It is, however, very naughty. Use it in the production code of your choice.

The problem here is not only that non-configurable properties cannot be configurable - this means that when calling Object.defineProperty it checks the existing property of the object, as well as the prototype chain of the object.

And the solution to this problem is quite simple: temporarily get rid of the prototype chain!

Warning: Changing the sequence of prototypes of an existing facility is a dangerous operation and should only be performed under adult supervision. Side effects may include: serious bouts of recompilation, decreased performance of the entire application, and automatic F in most code verification procedures with a sober examiner.

 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! 

In your case, the property is defined on the Agent prototype, and not on the Agent object. Therefore, you can use this trick. The new property will mask the old and will be used instead. The old property will still exist, it will simply be locked.

+2
source share

All Articles