Public class fields

Both static and instance public fields are writable, enumerable, and configurable properties. As such, unlike their private counterparts, they participate in prototype inheritance.

Syntax

class ClassWithField {
  instanceField;
  instanceFieldWithInitializer = "instance field";
  static staticField;
  static staticFieldWithInitializer = "static field";
}

There are some additional syntax restrictions:

  • The name of a static property (field or method) cannot be prototype.
  • The name of a class field (static or instance) cannot be constructor.

Description

This page introduces public instance fields in detail.

Public instance fields exist on every created instance of a class. By declaring a public field, you can ensure the field is always present, and the class definition is more self-documenting.

Public instance fields are added to the instance either at construction time in the base class (before the constructor body runs), or just after super() returns in a subclass. Fields without initializers are initialized to undefined. Like properties, field names may be computed.

const PREFIX = "prefix";

class ClassWithField {
  field;
  fieldWithInitializer = "instance field";
  [`${PREFIX}Field`] = "prefixed field";
}

const instance = new ClassWithField();
console.log(Object.hasOwn(instance, "field")); // true
console.log(instance.field); // undefined
console.log(instance.fieldWithInitializer); // "instance field"
console.log(instance.prefixField); // "prefixed field"

In the field initializer, this refers to the class instance under construction, and super refers to the prototype property of the base class, which contains the base class's instance methods, but not its instance fields.

class Base {
  baseField = "base field";
  anotherBaseField = this.baseField;
  baseMethod() {
    return "base method output";
  }
}

class Derived extends Base {
  subField = super.baseMethod();
}

const base = new Base();
const sub = new Derived();

console.log(base.anotherBaseField); // "base field"

console.log(sub.subField); // "base method output"

The field initializer expression is evaluated each time a new instance is created. (Because the this value is different for each instance, the initializer expression can access instance-specific properties.)

class C {
  obj = {};
}

const instance1 = new C();
const instance2 = new C();
console.log(instance1.obj === instance2.obj); // false

Because instance fields of a class are added before the respective constructor runs, you can access the fields' values within the constructor. However, because instance fields of a derived class are defined after super() returns, the base class's constructor does not have access to the derived class's fields.

class Base {
  constructor() {
    console.log("Base constructor:", this.field);
  }
}

class Derived extends Base {
  field = 1;
  constructor() {
    super();
    console.log("Derived constructor:", this.field);
    this.field = 2;
  }
}

const instance = new Derived();
// Base constructor: undefined
// Derived constructor: 1
console.log(instance.field); // 2

Because class fields are added using the [[DefineOwnProperty]] semantic (which is essentially Object.defineProperty()), field declarations in derived classes do not invoke setters in the base class. This behavior differs from using this.field = … in the constructor.

class Base {
  set field(val) {
    console.log(val);
  }
}

class DerivedWithField extends Base {
  field = 1;
}

const instance = new DerivedWithField(); // No log

class DerivedWithConstructor extends Base {
  constructor() {
    super();
    this.field = 1;
  }
}

const instance2 = new DerivedWithConstructor(); // Logs 1

Note: Before the class fields specification was finalized with the [[DefineOwnProperty]] semantic, most transpilers, including Babel and tsc, transformed class fields to the DerivedWithConstructor form, which has caused subtle bugs after class fields were standardized.

Specifications

Specification
ECMAScript Language Specification
# prod-FieldDefinition

Browser compatibility

BCD tables only load in the browser

See also