Перейти к основному содержимому

Статические блоки инициализации классов

· 2 мин. чтения
Shu-yu Guo ([@_shu](https://twitter.com/_shu))

Новый синтаксис статического блока инициализации классов позволяет разработчикам собирать код, который должен выполняться один раз для определения класса, и размещать его в одном месте. Рассмотрим следующий пример, где генератор псевдослучайных чисел использует статический блок для инициализации пула энтропии один раз, когда выполняется определение class MyPRNG.

class MyPRNG {
constructor(seed) {
if (seed === undefined) {
if (MyPRNG.entropyPool.length === 0) {
throw new Error('Пул энтропии исчерпан');
}
seed = MyPRNG.entropyPool.pop();
}
this.seed = seed;
}

getRandom() {}

static entropyPool = [];
static {
for (let i = 0; i < 512; i++) {
this.entropyPool.push(probeEntropySource());
}
}
}

Область видимости

Каждый статический блок инициализации имеет свою собственную область видимости для var и let/const. Как и в инициализаторах статических полей, значение this в статических блоках относится к самому классу-конструктору. Аналогично, super.property внутри статического блока ссылается на статическое свойство родительского класса.

var y = 'внешний y';
class A {
static fieldA = 'A.fieldA';
}
class B extends A {
static fieldB = 'B.fieldB';
static {
let x = super.fieldA;
// → 'A.fieldA'
var y = this.fieldB;
// → 'B.fieldB'
}
}
// Поскольку статические блоки имеют свою область видимости `var`, `var` не всплывает!
y;
// → 'внешний y'

Несколько блоков

Класс может иметь более одного статического блока инициализации. Эти блоки выполняются в порядке их текстового расположения. Кроме того, если есть статические поля, все статические элементы выполняются в текстовом порядке.

class C {
static field1 = console.log('поле 1');
static {
console.log('статический блок 1');
}
static field2 = console.log('поле 2');
static {
console.log('статический блок 2');
}
}
// → поле 1
// статический блок 1
// поле 2
// статический блок 2

Доступ к приватным полям

Поскольку статический блок инициализации класс всегда вложен внутри класса, он имеет доступ к приватным полям этого класса.

let getDPrivateField;
class D {
#privateField;
constructor(v) {
this.#privateField = v;
}
static {
getDPrivateField = (d) => d.#privateField;
}
}
getDPrivateField(new D('приватное'));
// → приватное

Это все. Удачной объектно-ориентированности!

Поддержка статических блоков инициализации классов