I have an ES6 class (transcompiled with babeljs) with a getter property. I understand that these properties are not enumerable by default. However, I do not understand why I
Non-static methods and accessors of a class lie on the prototype of the class so that every instance of it inherits them. You can access them through the instances, but they are not the own properties of the instances. Static methods and accessors lie on the class (which is a function) itself.
class Test {
#private_field = "A private field.";
public_field = "A public field.";
static get static_getter() {
return "A static getter.";
}
static static_method() {
return "A static method.";
}
get getter() {
return "A non-static getter.";
}
method() {
return "A non-static method.";
}
}
console.log(`Class ("${typeof Test}" type)`, Object.getOwnPropertyDescriptors(Test));
console.log("Its prototype", Object.getOwnPropertyDescriptors(Test.prototype));
console.log("Its instance", Object.getOwnPropertyDescriptors(new Test));
Class ("function" type) {
"length": {
"value": 0,
"writable": false,
"enumerable": false,
"configurable": true
},
"prototype": {
"value": {……},
"writable": false,
"enumerable": false,
"configurable": false
},
"static_getter": {
"get": ƒ static_getter() {……},
"set": undefined,
"enumerable": false,
"configurable": true
},
"static_method": {
"value": ƒ static_method() {……},
"writable": true,
"enumerable": false,
"configurable": true
},
"name": {
"value": "Test",
"writable": false,
"enumerable": false,
"configurable": true
}
}
Its prototype {
"constructor": {
"value": class Test {……},
"writable": true,
"enumerable": false,
"configurable": true
},
"getter": {
"get": ƒ getter() {……},
"set": undefined,
"enumerable": false,
"configurable": true
},
"method": {
"get": ƒ method() {……},
"writable": true,
"enumerable": false,
"configurable": true
}
}
Its instance {
"public_field": {
"value": "A public field",
"writable": true,
"enumerable": true,
"configurable": true
}
}
You can make non-static accessors, which are properties on a prototype, enumerable using Object.defineProperty.
class Person {
constructor(name) {
this.name = name;
}
get greeting() {
return `Hello from ${this.name}.`;
}
}
for(const property of ["greeting"]) {
Object.defineProperty(Person.prototype, property, {enumerable: true});
}
But this way it’ll be mostly of no use, as most of the useful functions, such as Object.keys, Object.values, Object.entries, JSON.stringify, et cetera, do only look for own properties of objects.
You can also bring (copy) properties on a prototype down to instances. This way they no longer inherit the properties from the prototype, but have them as their own properties.
class Person {
constructor(name) {
this.name = name;
for(const property of ["greeting"]) {
const descriptor = Object.getOwnPropertyDescriptor(Person.prototype, property);
const modified_descriptor = Object.assign(descriptor, {enumerable: true});
Object.defineProperty(this, property, modified_descriptor);
}
}
get greeting() {
return `Hello from ${this.name}.`;
}
}
const alice = new Person("Alice");
console.log(alice.greeting);
console.log(JSON.stringify(alice));
console.log(Object.entries(alice));
const prototype = Object.getPrototypeOf(this);
const prototype_property_descriptors = Object.getOwnPropertyDescriptors(prototype);
for(const [property, descriptor] of Object.entries(prototype_property_descriptors)) {
const is_nonstatic_getter = (typeof descriptor.get === "function");
if(is_nonstatic_getter) {
descriptor.enumerable = true;
Object.defineProperty(this, property, descriptor);
}
}