Author: Dr. Axel Rauschmayer
Translator: Frontend Xiaozhi
Source: 2ality
There are dreams and dry goods. Wechat search [Daqiang World] Pay attention to this Shuawanzhi who is still doing dishes in the early morning.
This article GitHub https://github.com/qq449245884/xiaozhi has been included, the first-line interview complete test site, information and my series of articles.

Ron Buckton’s ECMAScript proposal "Classic Static Initialization Block" has entered the fourth stage and plans to incorporate ECMAScript 2022.

In order to create an instance of a class, there are two structures in JavaScript:

  • Field: Create (optionally initialize) instance attributes.
  • Constructor: A block of code executed before the setup is complete.

For the setting of the static part of the class, we only have static fields. ECMAScript recommends the introduction of static initialization blocks for classes. In general, its effect on static classes is like the effect of constructors on instances.

1. Why do we need static blocks in classes?

When setting static fields, using external functions usually works well:

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);
}

Using external functions extractEnglish() and extractGerman() works well in this case, because we can see that they are called from within the class, and they are completely independent of the class.

If we want to set two static fields at the same time, things become less elegant.

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);
  }
}

This time, there are a few questions.

  • Calling initializeTranslator() is an extra step, or it is executed outside the class after the class is created. Or through a workaround ( A line ).
  • initializeTranslator() cannot access the private data of Translator

With the proposed static block (line A), we have a more elegant solution.

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. A more complex example

One way to implement enumeration in JavaScript is through the superclass Enum

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'

We need to collect the static fields so that we can traverse the keys of the enumeration items ( B line ). This is the last step after creating all the static fields. We again use a workaround ( A line ), the static block will be more elegant.

3. Details

The specific content of the static block is relatively logical (in contrast, the rules for instance members are more complicated):

  • Each class can have more than one static block.
  • The execution of the static block is interleaved with the execution of the static field initializer.
  • The static members of the superclass are executed before the static members of the subclass.

The following code shows 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. Support class static block in the engine

  • V8: unflagged in v9.4.146 (source)
  • SpiderMonkey: behind a flag in v92, intent to ship unflagged in v93 (source)
  • TypeScript: v4.4 (source)

5. Has JS become too Java-like and/or a mess?

This is a small feature and will not compete with other features. We can already run static code static _ = ... The static block means that this workaround is no longer needed.

In addition, classes are just one of many tools on the belt of JavaScript programmers. Some of us use it, others don't use it, and there are many alternatives. Even JS code that uses classes often uses functions, and they are often lightweight.

6. Summary

The class static block is a relatively simple function, which completes the static function of the class. Roughly speaking, it is the static version of the instance constructor. It is mainly useful when we need to set more than one static field.

~ End, I’m Shuwanzhi, Inspirational, who will go home to set up a street stall after retirement. See you in the next issue!


possible bugs of the 161a5698be9e3a code after deployment cannot be known in real time. In order to solve these bugs afterwards, a lot of time was spent on log debugging. By the way, I would like to recommend a useful BUG monitoring tool Fundebug .

Original: https://2ality.com/2021/09/class-static-block.html

comminicate

If you have dreams and dry goods, search on [Daily Move to the World] attention to the brushing wisdom who is still doing dishes in the early morning.

This article GitHub https://github.com/qq449245884/xiaozhi has been included, the first-line interview complete test site, information and my series of articles.


王大冶
68.1k 声望105k 粉丝