diff --git a/files/en-us/web/javascript/reference/classes/class_static_initialization_blocks/index.md b/files/en-us/web/javascript/reference/classes/class_static_initialization_blocks/index.md new file mode 100644 index 000000000000000..f216ee399a76da2 --- /dev/null +++ b/files/en-us/web/javascript/reference/classes/class_static_initialization_blocks/index.md @@ -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.` 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) diff --git a/files/en-us/web/javascript/reference/classes/constructor/index.md b/files/en-us/web/javascript/reference/classes/constructor/index.md index 4573bf1a680975d..b79d00f5bbd0ccd 100644 --- a/files/en-us/web/javascript/reference/classes/constructor/index.md +++ b/files/en-us/web/javascript/reference/classes/constructor/index.md @@ -10,9 +10,7 @@ browser-compat: javascript.classes.constructor --- {{jsSidebar("Classes")}} -The `constructor` method is a special method of -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")}} @@ -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 { @@ -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) { @@ -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 { @@ -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 { @@ -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 { @@ -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) diff --git a/files/en-us/web/javascript/reference/classes/index.md b/files/en-us/web/javascript/reference/classes/index.md index 56fe1b06245b37e..826e3c20e7bdef2 100644 --- a/files/en-us/web/javascript/reference/classes/index.md +++ b/files/en-us/web/javascript/reference/classes/index.md @@ -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")}}. diff --git a/files/en-us/web/javascript/reference/classes/static/index.md b/files/en-us/web/javascript/reference/classes/static/index.md index a014d7d72ece93a..7cb6f9e75b487bb 100644 --- a/files/en-us/web/javascript/reference/classes/static/index.md +++ b/files/en-us/web/javascript/reference/classes/static/index.md @@ -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). +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 @@ -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 { @@ -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)