gkr
gkr

Reputation: 469

Setting enumerable property on object prototype

I'm trying to set enumerable property, with setter, on an object prototype.

function Foo(){}
Object.defineProperty(Foo.prototype, 'tag', {
    enumerable: true, configurable: true,
    set: function(x){ 
        if(typeof(x) == "string") {
            Object.defineProperty(this, 'tag', {value: x});
        }
    }
});
var bar = new Foo();

bar.tag = 7;     console.log(bar.tag); // undefined
bar.tag = "baz"; console.log(bar.tag); // "baz"

console.log(bar); // {}
console.log(bar.propertyIsEnumerable('tag')); // false

Everything work as expected, except the last two line.
I just tested the code in node v0.10.25 . I don't understand why the property tag isn't enumerable.
As a workaround, I'm using Object.defineProperty in the constructor against this instead of Foo.prototype, but I would like to understand why object in javascript can't inherit from enuerable properties.

Upvotes: 3

Views: 2282

Answers (3)

Bergi
Bergi

Reputation: 665276

The problem is that your two Object.defineProperty call define different properties:

  • One setter property on the prototype
  • One value property on each this, i.e. instance

While the one on the prototype is enumerable and configurable, the instance property will not "inherit" these descriptors; and they will default to false on the new descriptor. You will need to set them explicitly:

Object.defineProperty(Foo.prototype, 'tag', {
     enumerable: true, configurable: true,
     set: function(x){ 
         if (typeof(x) == "string")
             Object.defineProperty(this, 'tag', {
                 enumerable:true, configurable:true, // still non-writable
                 value: x
             });
     }
});

Upvotes: 4

HMR
HMR

Reputation: 39320

You re assign tag in the set function (shadowing tag by creating the member on the Foo instance named bar) but don't set it to enumarable or configurable try the following:

function Foo(){}
Object.defineProperty(Foo.prototype, 'tag', {
    enumerable: true, configurable: true,
    set: function(x){ 
        if(typeof(x) == "string") {
            Object.defineProperty(this, 'tag', {
              value: x,
              enumerable: true
            });
        }
    }
});
var bar = new Foo();

bar.tag = 7;     console.log(bar.tag); // undefined
bar.tag = "baz"; console.log(bar.tag); // "baz"

console.log(bar); // { tag="baz" }
console.log(bar.propertyIsEnumerable('tag')); // true

More info about shadowing members, constructor functions and prototype: https://stackoverflow.com/a/16063711/1641941

Upvotes: 2

Sonata
Sonata

Reputation: 2227

I think you can only define properties for an object, not on a prototype or a constructor function, see also this post.

That why putting the object.defineProperty inside the constructor will work: this inside the constructor is an object.

Upvotes: -1

Related Questions