Why can't I redefine a property in a Javascript object?

Javascript

Javascript Problem Overview


I am creating a object using Object.create and I want to add properties to it.

> var o = Object.create({});
undefined

> Object.defineProperty(o, "foo", {value: 43, enumerable: true});
{foo: 43}

> o
{foo: 43}

> o.foo
43

> for (var i in o) { console.log(i); }
foo

> Object.keys(o)
['foo']

> Object.defineProperty(o, "foo", {value: 43, enumerable: false });
TypeError: Cannot redefine property: bar

Q1) Why can't I redefine the property ?

> o.__proto__
{}

> o.prototype
undefined

Q2) Why is the prototype empty ? And why are these 2 values different i.e. {} vs undefined ?

Javascript Solutions


Solution 1 - Javascript

You are unable to redefine the property because Object.defineProperty() defaults to non-configurable properties, from the docs:

> configurable

> true if and only if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object. Defaults to false.

So this defaults to false - you'd need to pass it configurable: true to allow it.

Solution 2 - Javascript

  1. Properties defined through Object.defineProperty() are, by default, non-configurable.

    To allow them to be redefined, or reconfigured, they have to be defined with this attribute set to true.

     var o = Object.create({});
    
     Object.defineProperty(o, "foo", {
         value: 42,
         enumerable: true,
         configurable: true
     });
    
     console.log(o); // { foo: 42 }
    
     Object.defineProperty(o, "foo", {
         value: 45,
         enumerable: true,
         configurable: true
     });
    
     console.log(o); // { foo: 45 }
    

  2. o.prototype is undefined because objects don't typically have prototype properties.

    Such properties are found on constructor functions for new instances to inherit from, roughly equivalent to:

     function Foo() {}
    
     //  ... = new Foo();
     var bar = Object.create(Foo.prototype);
     Foo.call(bar);
    

    Object are, however, aware of their prototype objects. They're referenced through an internal [[Prototype]] property, which __proto__ is/was an unofficial getter/setter of:

     console.log(o.__proto__); // {}
    

    The standardized way to read the [[Prototype]] is with Object.getPrototypeOf():

     console.log(Object.getPrototypeOf(o)); // {}
    

Solution 3 - Javascript

Only when both writable and configurable are false, "Cannot redefine property" will happen.

If writable or configurable is true, the error will disappear.

"use strict"

var obj = {};

Object.defineProperty(obj, "name",
{
   value: "Fundebug",
   writable: false,
   configurable: false
})

Object.defineProperty(obj, "name",
{
   value: "云麒"
}) // “Uncaught TypeError: Cannot redefine property: name”

Therefore, jdphenix and Jonathan are not exactly correct.

Solution 4 - Javascript

Object.defineProperty(o, "foo", {value: 43, enumerable: true});

This line defines property foo on object o with value:43 and attributes enumerable:true, writable:false, configurable:false. If the property exists, defineProperty updates its flags. Otherwise, it creates the property with the given value and flags; in that case, if a flag is not supplied, it is assumed false.

So, here we are making our property non-configurable as configurable flag (or attribute) is false.

> Making a property non-configurable is a one-way road. We cannot change > it back with defineProperty. > > To be precise, non-configurability imposes several restrictions on > defineProperty: > >

  • Can’t change configurable flag.
  • Can’t change enumerable flag.
  • Can’t change writable: false to true (the other way round works).
  • Can’t change get/set for an accessor property (but can assign them if absent).

So be careful with configurable flag in defineProperty, always set it to true in defineProperty if you want to change enumerable and writable attributes(or flag). Once you set configurable false you cant set it to true.

Solution 5 - Javascript

One possible reason of this could be your version problem. Node 10 doesn't allow live binding but the newer versions now allow this. Please check you are on node 12 or plus.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGavin BongView Question on Stackoverflow
Solution 1 - JavascriptjdphenixView Answer on Stackoverflow
Solution 2 - JavascriptJonathan LonowskiView Answer on Stackoverflow
Solution 3 - JavascriptKiwenLauView Answer on Stackoverflow
Solution 4 - JavascriptPravin DivraniyaView Answer on Stackoverflow
Solution 5 - JavascriptDivya JainView Answer on Stackoverflow