1

I don't understand why the property "salary" is not shown, despite being enumerable :

class People {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
}
Object.defineProperty(People.prototype, 'salary', {
    value: 3000,
    enumerable: true,
    writable: true
});

Execution :

> var p = new People('Jack', 46);
> console.log(p)
People { name: 'Jack', age: 46 }
> console.log(p.propertyIsEnumerable('salary'));
false
> console.log(p.salary)
3000

Why does it say false for p.propertyIsEnumerable('salary') ?

However, if I modify the property, suddenly it starts to be enumerated :

> p.salary = 4500
4500
> console.log(p)
People { name: 'Jack', age: 46, salary: 4500 }
> console.log(p.propertyIsEnumerable('salary'));
true

What's going on ? Why does it become enumerable only after modification ? Why isn't it enumerable from the beginning ?

ChennyStar
  • 350
  • 1
  • 2
  • 11

1 Answers1

1

The console you use only logs the own property values of the object, not ones that come from the prototype. That is not necessarily true for all consoles:

class People {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
}

Object.defineProperty(People.prototype, 'salary', {
    value: 3000,
    enumerable: true,
    writable: true
});

var p = new People('Jack', 46);
//compare with the browser console
console.log(p);

As for why is the property "not enumerable" - it's because Object#propertyIsEnumerable does not traverse the prototype chain:

var a = { foo: 1 };
var b = Object.create(a);
b.bar = 2;

console.log(`a:
  a.foo: ${a.foo}
  a.hasOwnProperty("foo"): ${a.hasOwnProperty("foo")}
  a.propertyIsEnumerable("foo"): ${a.propertyIsEnumerable("foo")}`);

console.log(`b:
  b.foo: ${b.foo}
  b.hasOwnProperty("foo"): ${b.hasOwnProperty("foo")}
  b.propertyIsEnumerable("foo"): ${b.propertyIsEnumerable("foo")}
  b.bar: ${b.bar}
  b.hasOwnProperty("bar"): ${b.hasOwnProperty("bar")}
  b.propertyIsEnumerable("bar"): ${b.propertyIsEnumerable("bar")}`);

As for why does it "become enumerable" when you change it - the truth is that it doesn't - when you add a new property to the object, you are now getting that, not the one from the prototype. The prototype property is not changed:

var a = { foo: 1 };
var b = Object.create(a);

console.log(`b before adding a property:
  b.foo: ${b.foo}
  b.hasOwnProperty("foo"): ${b.hasOwnProperty("foo")}
  b.propertyIsEnumerable("foo"): ${b.propertyIsEnumerable("foo")}`);
  
b.foo = 2;

console.log(`b after adding a property:
  b.foo: ${b.foo}
  b.hasOwnProperty("foo"): ${b.hasOwnProperty("foo")}
  b.propertyIsEnumerable("foo"): ${b.propertyIsEnumerable("foo")}`);
  
console.log(`a after adding a property to b:
  b.foo: ${a.foo}`);
VLAZ
  • 26,331
  • 9
  • 49
  • 67
  • "compare with the browser console" I just did (Firefox), same result – ChennyStar Oct 31 '19 at 17:52
  • @ChennyStar Does it print `{ "name": "Jack", "age": 46, "salary": 3000 }` like the StackSnippet console does? – VLAZ Oct 31 '19 at 17:56
  • I did some more tests, and you're right it's due to console behaviour. JSBin and Chrome show the prototype properties (i.e., they display { "name": "Jack", "age": 46, "salary": 3000 }), but Node REPL and Firefox don't (i.e., they display { "name": "Jack", "age": 46}). – ChennyStar Oct 31 '19 at 18:04
  • Consoles don't have a well defined behaviour outside "they log stuff". When it comes to objects, you might get just the own properties or everything and it might be at the point of logging the object [or be lazily evaluated at a later point](https://stackoverflow.com/questions/4057440/is-chromes-javascript-console-lazy-about-evaluating-arrays). – VLAZ Oct 31 '19 at 18:05
  • +1, I just upvoted your answer, but it doesn't show (I have less than 15 reputations). Thanks for your help – ChennyStar Oct 31 '19 at 18:14
  • Erratum : it works fine in Firefox too. So it seems this console behaviour occurs only in Node REPL (tested in JSBin, Firefox and Chrome, all working) – ChennyStar Oct 31 '19 at 21:23