[JavaScript Weekly #554] ES2022 feature: class static initialization block

Posted by cristiano on Tue, 11 Jan 2022 16:04:50 +0100

🥳 Welcome interested partners to do something meaningful together! Translator: Natural volume

I launched a weekly translation program, Warehouse addressAccess address

There is still a shortage of like-minded partners. They are purely personal interests. Of course, they will also help to improve English and front-end skills. Requirements: English is not too bad, github is proficient, persistent, modest and responsible for what you do.

If you want to participate, you can wx You can also send issue messages to the warehouse. My blog also has specific personal contact information: daodaolee.cn

Ron Buckton's ECMAScript proposal“ Class static initialization block ”In Phase 4 And is planned to be included in ECMAScript2022.

To create an instance of a class, we have two constructs in JavaScript:

  • Fields: create (optionally initialize) instance properties.
  • Constructor: a block of code executed before setting is completed

In order to set the static part of the class, we only have static fields. ECMAScript recommends the introduction of static initialization blocks of classes. The effect of these blocks on static classes is roughly equivalent to that of constructors on instances.

1 Why do we use static blocks in classes?

When we set static fields, the effect of using external functions is usually good:

class Translator {
    static translations = {
        yes: 'ja',
        no: 'nein',
        maybe: 'vielleicht',
    };
    static englishWords = extractEnglish(this.translations);
    static germanWords = extractGerman(this.translations);
}
function extractEnglish(translations) {
  return Object.keys(translations);
}
function extractGerman(translations) {
  return Object.values(translations);
}

There is no problem using the external functions extractEnglish() and extractGerman(), because we can see that they are called from within the class and they are completely independent of the class. But if we want to set two static fields at the same time, it will be a little strange:

class Translator {
    static translations = {
        yes: 'ja',
        no: 'nein',
        maybe: 'vielleicht',
    };
    static englishWords = [];
    static germanWords = [];
    static _ = initializeTranslator( // (A)
    this.translations, this.englishWords, this.germanWords);
}
function initializeTranslator(translations, englishWords, germanWords) {
  for (const [english, german] of Object.entries(translations)) {
    englishWords.push(english);
    germanWords.push(german);
  }
}

There are two problems with this:

  • initializeTranslator() is called additionally and must be executed outside the class after the class is created. Or at A.
  • initializeTranslator() is a private data Translator that cannot be accessed.

If static block A is used, it can be written as follows:

class Translator {
    static translations = {
        yes: 'ja',
        no: 'nein',
        maybe: 'vielleicht',
    };
    static englishWords = [];
    static germanWords = [];
    static { // (A)
        for (const [english, german] of Object.entries(this.translations)) {
        this.englishWords.push(english);
        this.germanWords.push(german);
        }
    }
}

2 more complex examples

One way to implement enumeration in JavaScript is through Enum superclass (see library for details) enumify)

class Enum {
  static collectStaticFields() {
    // Static methods are not enumerable and thus ignored
    this.enumKeys = Object.keys(this);
  }
}
class ColorEnum extends Enum {
  static red = Symbol('red');
  static green = Symbol('green');
  static blue = Symbol('blue');
  static _ = this.collectStaticFields(); // (A)

  static logColors() {
    for (const enumKey of this.enumKeys) { // (B)
      console.log(enumKey);
    }
  }
}
ColorEnum.logColors();

// Output:
// 'red'
// 'green'
// 'blue'

Here we need to collect static fields so that we can traverse the key values of the enum entry (line B). This completes the creation of all static fields. Then we call the code on line A again, which will be more elegant.

3 details

Relatively speaking, the details of static blocks are logical (compared with more complex rules, such as instance members):

  • Each class can have multiple static blocks.
  • Static block and static field initialization are interleaved.
  • Static members of a superclass are executed before static members of subclasses.
    The following code demonstrates these rules:
class SuperClass {
  static superField1 = console.log('superField1');
  static {
    assert.equal(this, SuperClass);
    console.log('static block 1 SuperClass');
  }
  static superField2 = console.log('superField2');
  static {
    console.log('static block 2 SuperClass');
  }
}

class SubClass extends SuperClass {
  static subField1 = console.log('subField1');
  static {
    assert.equal(this, SubClass);
    console.log('static block 1 SubClass');
  }
  static subField2 = console.log('subField2');
  static {
    console.log('static block 2 SubClass');
  }
}

// Output:
// 'superField1'
// 'static block 1 SuperClass'
// 'superField2'
// 'static block 2 SuperClass'
// 'subField1'
// 'static block 1 SubClass'
// 'subField2'
// 'static block 2 SubClass'

4 tools that support class static blocks

5 has JavaScript become more and more Java like or messy?

This is a very small function and will not conflict with other functions. We can use static = Field to run static code. Static blocks mean that this workspace is no longer necessary.
In addition, classes are just one of many tools for JavaScript programmers. We can use it or not, and there are many other alternatives.

6 Conclusion

Class static block is a relatively simple feature, which improves the static characteristics of class. Roughly speaking, it is a static version of the instance constructor. It is very useful when we have to set multiple static fields.

Related links

Original link

Original translation plan

Topics: Javascript Front-end