Joji
Joji

Reputation: 5646

Confusion about JavaScript Object's method being non-enumerable

class RandomObject {
  constructor() {
    this.method1 = function() {}
  }

  method2() {
    // only this is non enumerable
  }

  method3 = function() {}
}

const object = new RandomObject()

for (const prop in object) {
  console.log(prop) // 'method1', 'method2'
}

I found that only method1 and method2 are printed out in the for...in loop, meaning they are enumerable. However method2 doesn't show up in the loop, meaning it is non-enumerable. I wonder what caused the differences here? Why is that only method2 is non-enumerable in this case?

Also, I found that if I define the method directly in the object literal, then it is enumerable again:

const object2 = {
  method2() {
    // Now this is enumerable
  }
}

Upvotes: 2

Views: 277

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 371098

Class prototype methods are non-enumerable - that's just the way the syntax was designed:

class X {
  method() {
  }
}

console.log(Object.getOwnPropertyDescriptor(X.prototype, 'method').enumerable);

See CreateMethodProperty in ClassDefinitionEvaluation, which requires that class methods be non-enumerable.

In contrast, class field syntax - that is, someProperty = someExpression directly inside the class body - is syntax sugar for running this.someProperty = someExpression inside the constructor. Ordinary assignment to a property that doesn't exist on the object yet results in the property being enumerable.

class RandomObject {
  method3 = function() {}
}

is equivalent to

class RandomObject {
  constructor() {
    this.method3 = function() {}
  }
}

With methods on ordinary objects, see PropertyDefinitionEvaluation, which describes how properties (including methods) get created in object literals. It'll carry out

Return ? MethodDefinitionEvaluation of MethodDefinition with arguments object and enumerable.

where enumerable has been set to true with ObjectLiterals.

Upvotes: 5

Related Questions