Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Class static initialization blocks #9281

Merged
merged 13 commits into from
Sep 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
---
title: Class static initialization blocks
slug: Web/JavaScript/Reference/Classes/Class_static_initialization_blocks
tags:
- Classes
- ECMAScript 2022
- JavaScript
- Language feature
- Static
- Reference
- Initialization
browser-compat: javascript.classes.class_static_initialization_blocks
---
{{jsSidebar("Classes")}}

**Class static initialization blocks** are a special feature of a {{jsxref("Statements/class", "class")}} that enable more flexible initialization of {{jsxref("Classes/static", "static")}} properties than can be achieved using per-field initialization.

Static blocks allow statements to be evaluated during initialization, which allows initializations that (for example) include `try...catch` or set multiple fields from a single value.

Initialization is performed in the context of the current class declaration, with privileged access to private state.
This means that static blocks can also be used to share information between classes with instance private fields and other classes or functions declared in the same scope (analogous to "friend" classes in C++).

{{EmbedInteractiveExample("pages/js/classes-static-initialization.html")}}

## Syntax

```js
static { ... }
```


## Description

A {{jsxref("Statements/class", "class")}} can have any number of `static {}` initialization blocks in its class body.
These are evaluated, along with any interleaved static field initializers, in the order they are declared.
Any static initialization of a super class is performed first, before that of its sub classes.

The scope of the variables declared inside the static block is local to the block.
Since `var`, `function`, `const` or `let` declared in a `static {}` initialization block are local to the block, any `var` declarations in the block are not hoisted.

```js
var y = 'Outer y';

class A {
static field = 'Inner y';
static {
var y = this.field;
}
}

// var defined in static block is not hoisted
console.log(y);
// > 'Outer y'
```

The `this` inside a static block refers to the constructor object of the class.
`super.<property>` can be used to access properties of a super class.
Note however that it is a syntax error to call {{jsxref("Operators/super", "super()")}} in a class static initialization block, or to attempt to access arguments of the class constructor function.

The scope of the static block is nested _within_ the lexical scope of the class body, and can access the private instance variables of the class.

A static initialization block may not have decorators (the class itself may).


## Examples

### Multiple blocks

The code below demonstrates a class with static initialization blocks and interleaved static field initializers.
The output shows that the blocks and fields are evaluated in execution order.

```js
class MyClass {
static field1 = console.log('field1 called');
static {
console.log('Class static block #1 called');
}
static field2 = console.log('field2 called');
static {
console.log('Class static block #2 called');
}
}

/*
> "field1 called"
> "Class static block #1 called"
> "field2 called"
> "Class static block #2 called"
*/
```

Note that any static initialization of a super class is performed first, before that of its sub classes.


### Using `this` and `super.property`

The `this` inside a static block refers to the constructor object of the class.
This code shows how to access a public static field.

```js
class A {
static field = 'A static field';
static {
var y = this.field;
}
}
```

The [`super.property`](/en-US/docs/Web/JavaScript/Reference/Operators/super) can be used inside a `static` block to reference properties of a super class.
This includes static properties, as shown below:

```js
class A {
static fieldA = 'A.fieldA';
}
class B extends A {
static {
let x = super.fieldA;
// 'A.fieldA'
}
}
```

### Access to private fields

This example below shows how access can be granted to the private object of a class from an object outside the class (example from the [v8.dev blog](https://v8.dev/features/class-static-initializer-blocks#access-to-private-fields)):


```js
let getDPrivateField;

class D {
#privateField;
constructor(v) {
this.#privateField = v;
}
static {
getDPrivateField = (d) => d.#privateField;
}
}

getDPrivateField(new D('private'));
// > private
```

### Workarounds

Prior to ES13 more complex static initialization might be achieved by using a static method that is called after the other properties to perform static initialization, or having a method that is external to the class that performs initialization tasks.

In both cases the approach is less elegant, and does not grant access to private methods in the class.


## Specifications

{{Specifications}}

## Browser compatibility

{{Compat}}

## See also

- [Class static initialization blocks](https://v8.dev/features/class-static-initializer-blocks) (v8.dev blog)
- [ES2022 feature: class static initialization blocks](https://2ality.com/2021/09/class-static-block.html) (2ality.com blog)
- [Classes](/en-US/docs/Web/JavaScript/Reference/Classes)
- {{jsxref("Operators/super", "super()")}}
- [Object.prototype.constructor](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor)
37 changes: 14 additions & 23 deletions files/en-us/web/javascript/reference/classes/constructor/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ browser-compat: javascript.classes.constructor
---
{{jsSidebar("Classes")}}

The `constructor` method is a special method of
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
a {{jsxref("Statements/class", "class")}} for creating and initializing an object of
that class.
The `constructor` method is a special method of a {{jsxref("Statements/class", "class")}} for creating and initializing an object instance of that class.

{{EmbedInteractiveExample("pages/js/classes-constructor.html")}}

Expand All @@ -27,8 +25,7 @@ constructor(argument0, argument1, ... , argumentN) { ... }

## Description

A constructor enables you to provide any custom initialization that must be done before
any other methods can be called on an instantiated object.
A constructor enables you to provide any custom initialization that must be done before any other methods can be called on an instantiated object.

```js
class Person {
Expand All @@ -48,15 +45,14 @@ const otto = new Person('Otto');
otto.introduce();
```

If you don't provide your own constructor, then a default constructor will be supplied
for you. If your class is a base class, the default constructor is empty:
If you don't provide your own constructor, then a default constructor will be supplied for you.
If your class is a base class, the default constructor is empty:

```js
constructor() {}
```

If your class is a derived class, the default constructor calls the parent constructor,
passing along any arguments that were provided:
If your class is a derived class, the default constructor calls the parent constructor, passing along any arguments that were provided:

```js
constructor(...args) {
Expand Down Expand Up @@ -88,13 +84,11 @@ try {
}
```

The `ValidationError` class doesn't need an explicit constructor, because it
doesn't need to do any custom initialization. The default constructor then takes care of
initializing the parent `Error` from the argument it is given.
The `ValidationError` class doesn't need an explicit constructor, because it doesn't need to do any custom initialization.
The default constructor then takes care of initializing the parent `Error` from the argument it is given.

However, if you provide your own constructor, and your class derives from some parent
class, then you must explicitly call the parent class constructor using
`super`. For example:
However, if you provide your own constructor, and your class derives from some parent class, then you must explicitly call the parent class constructor using `super`.
For example:

```js
class ValidationError extends Error {
Expand Down Expand Up @@ -124,16 +118,14 @@ try {
}
```

There can be only one special method with the name "`constructor`" in a
class. Having more than one occurrence of a `constructor` method in a class
will throw a {{jsxref("SyntaxError")}} error.
There can be only one special method with the name "`constructor`" in a class.
Having more than one occurrence of a `constructor` method in a class will throw a {{jsxref("SyntaxError")}} error.

## Examples

### Using the `constructor` method

This code snippet is taken from the [classes
sample](https://github.com/GoogleChrome/samples/blob/gh-pages/classes-es6/index.html) ([live demo](https://googlechrome.github.io/samples/classes-es6/index.html)).
This code snippet is taken from the [classes sample](https://github.com/GoogleChrome/samples/blob/gh-pages/classes-es6/index.html) ([live demo](https://googlechrome.github.io/samples/classes-es6/index.html)).

```js
class Square extends Polygon {
Expand All @@ -159,9 +151,7 @@ class Square extends Polygon {

### Another example

Here the prototype of `Square` class is changed—but the constructor of its
base class `Polygon` is still called when a new instance of a square is
created.
Here the prototype of `Square` class is changed—but the constructor of its base class `Polygon` is still called when a new instance of a square is created.

```js
class Polygon {
Expand Down Expand Up @@ -202,3 +192,4 @@ console.log(newInstance.name); //Polygon
- {{jsxref("Operators/class", "class expression", "", "true")}}
- {{jsxref("Classes")}}
- [Object.prototype.constructor](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor)
- [Class static initialization block](/en-US/docs/Web/JavaScript/Reference/Classes/Class_static_initialization_blocks)
8 changes: 8 additions & 0 deletions files/en-us/web/javascript/reference/classes/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ The {{jsxref("Classes/constructor", "constructor", "", "true")}} method is a spe

A constructor can use the `super` keyword to call the constructor of the super class.


### Static initialization blocks

[Class `static` initialization blocks](/en-US/docs/Web/JavaScript/Reference/Classes/Class_static_initialization_blocks) allow flexible initialization of [class `static` properties](#static_methods_and_properties) including the evaluation of statements during initialization, and granting access to private scope.

Multiple static blocks can be declared, and these can be interleaved with the declaration of static properties and methods (all static items are evaluated in declaration order).


### Prototype methods

See also {{jsxref("Functions/Method_definitions", "method definitions", "", "true")}}.
Expand Down
33 changes: 16 additions & 17 deletions files/en-us/web/javascript/reference/classes/static/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,32 @@ tags:
- JavaScript
- Language feature
- Static
browser-compat: javascript.classes.static"
browser-compat: javascript.classes.static
---
{{jsSidebar("Classes")}}

The **`static`** keyword defines a
static method or property for a class. Neither static methods nor static properties
can be called on instances of the class. Instead, they're called on the class
itself.
The **`static`** keyword defines a static method or property for a class, or a [class static initialization block](/en-US/docs/Web/JavaScript/Reference/Classes/Class_static_initialization_blocks) (see the link for more information about this usage).
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
Neither static methods nor static properties can be called on instances of the class.
Instead, they're called on the class itself.

Static methods are often utility functions, such as functions to create
or clone objects, whereas static properties are useful for caches, fixed-configuration,
or any other data you don't need to be replicated across instances.
Static methods are often utility functions, such as functions to create or clone objects, whereas static properties are useful for caches, fixed-configuration, or any other data you don't need to be replicated across instances.

Note that the examples throughout this article use [public class fields](/en-US/docs/Web/JavaScript/Reference/Classes/Public_class_fields) (including static public class fields), which are not yet part of the ECMAScript specification, but are instead specified in a [Public and private instance fields](https://tc39.es/proposal-class-fields/) proposal at [TC39](https://tc39.es/).
> **Warning:** The examples throughout this article use [public class fields](/en-US/docs/Web/JavaScript/Reference/Classes/Public_class_fields) (including static public class fields), which are not yet part of the ECMAScript specification.
> These are specified in the [class features proposal](https://tc39.es/proposal-class-fields/unified.html) at [TC39](https://tc39.es/).

{{EmbedInteractiveExample("pages/js/classes-static.html")}}


## Syntax

```js
static methodName() { ... }
static propertyName [= value];

//Class static initialization block
static {

}
```

## Examples
Expand Down Expand Up @@ -75,10 +79,7 @@ console.log(tp.calculate()); // 'tp.calculate is not a function'

### Calling static members from another static method

In order to call a static method or property within another static method of the same
class, you can use the
[`this`](/en-US/docs/Web/JavaScript/Reference/Operators/this)
keyword.
In order to call a static method or property within another static method of the same class, you can use the [`this`](/en-US/docs/Web/JavaScript/Reference/Operators/this) keyword.

```js
class StaticMethodCall {
Expand Down Expand Up @@ -132,8 +133,6 @@ class StaticMethodCall {

## See also

- [`class`
expression](/en-US/docs/Web/JavaScript/Reference/Operators/class)
- [`class`
declaration](/en-US/docs/Web/JavaScript/Reference/Statements/class)
- [`class` expression](/en-US/docs/Web/JavaScript/Reference/Operators/class)
- [`class` declaration](/en-US/docs/Web/JavaScript/Reference/Statements/class)
- [Classes](/en-US/docs/Web/JavaScript/Reference/Classes)