DEV Community

Cover image for What, Why and How Javascript Static Initialization Blocks?
Rahul Sharma
Rahul Sharma

Posted on • Edited on

What, Why and How Javascript Static Initialization Blocks?

ES2022 introduces a new feature called static initialization blocks. With static initialization blocks, we can initialize static variables and execute some code only once when the class is loaded.

This article Will discuss what static initialization blocks are, why to use them, and how to use them.

What, Why and How Javascript Static Initialization Blocks?

Let's get started.

Before diving into the details of static initialization blocks, Let's understand the static variable first.

Static variables

Static variables are variables that are shared by all instances of a class. They are declared with the static keyword. Static variables are initialized when the class is loaded.

class MyClass {
    static staticProp = 'Some value';
}

console.log(MyClass.staticProp)
Enter fullscreen mode Exit fullscreen mode

Let's try to understand the difference between static and instance variables with the help of an example.

class MyClass {
    static staticProp = {};
    constructor() {
        this.instanceProp = {};
    }
}

const a = new MyClass();
const b = new MyClass();

console.log(a.staticProp === b.staticProp); // true
console.log(a.instanceProp === b.instanceProp); // false
Enter fullscreen mode Exit fullscreen mode

If we compare the values of the staticProp, we get true as the output. This is because the staticProp is shared by all instances of the class. But if we compare the values of the instanceProp, we get false as the output. This is because the instanceProp is not shared by all instances of the class.

Now we know the difference between static and instance variables. Let's understand the static initialization block.

Static initialization blocks

Static initialization blocks are a special feature of a class that enables more flexible initialization of static properties than can be achieved using per-field initialization. Static blocks allow statements to be evaluated during the initialization of a class.

To define a static initialization block, We can use the static keyword followed by a block({ }). Inside the block, we can initialize static variables and execute some code only once when the class is loaded.

Let's see an example.

class MyClass {
    static staticProp;
    static {
        console.log('Static initialization block');
        MyClass.staticProp = {};
    }
    constructor() {
        this.instanceProp = {};
    }
}
Enter fullscreen mode Exit fullscreen mode

If we run the above code, we will get the log message 'Static initialization block' in the console and the staticProp will be initialized with an empty object. Our example works like before, but this time we achieved using a static initialization block.

Why use static initialization blocks?

Sometimes we want to initialize static variables conditionally or execute some code only once like database connection, etc. In such cases, we can use static initialization blocks.

Let's assume that we have a function createDBConnection which is responsible for creating a database connection.

const createDBConnection = () => {
    console.log('Database connection created');
}

class Connection {
    constructor() {
        createDBConnection();
    }
}

const a = new Connection();
const b = new Connection();
Enter fullscreen mode Exit fullscreen mode

If we create a database connection in the constructor, for every instance of the class, we will create a new connection. which is not a good practice, because 1 class can have multiple instances and we might end up creating thousands of connections.

To solve this problem, we can use static initialization blocks to create a connection, since it will execute only once when the class is loaded.


const createDBConnection = () => {
    console.log('Database connection created');
}

class Connection {
    static {
        createDBConnection();
    }
}
const a = new Connection();
const b = new Connection();
Enter fullscreen mode Exit fullscreen mode

If we run the code again, we will get only 1 log message in the console. This way we can get rid of creating multiple connections.

Now we know what static initialization blocks are, Why to use them, and how to use them.

Few more things you should know about static initialization blocks.

A class can have any number of static initialization blocks in its class body, These are evaluated in the order they are declared. Static initialization blocks will be executed from top to bottom.
class Connection {
    static {
        console.log('Block 1');
    }
    static {
        console.log('Block 2');
    }
}
Enter fullscreen mode Exit fullscreen mode

If we run the above code we will get 'Block 1' and 'Block 2' in the console.


They are called before the constructor.
class Connection {
    static {
        console.log('Block');
    }
    constructor() {
        console.log('Constructor');
    }
}

const a = new Connection();
Enter fullscreen mode Exit fullscreen mode

If we run the above code, we will get 'Block' and 'Constructor' in the console.


They are called before the constructor of the derived class. Let's say we have a class BaseConnection and another class Connection that extends BaseConnection and we have a static initialization block in both classes.
class BaseConnection {
    static {
        console.log('BaseConnection');
    }
    constructor() {
        console.log('BaseConnection constructor');
    }
}

class Connection extends BaseConnection {
    static {
        console.log('Connection');
    }
    constructor() {
        super();
        console.log('Connection constructor');
    }
}

const a = new Connection();
Enter fullscreen mode Exit fullscreen mode

If we run the above code, the execution order will be

  1. BaseConnection static initialization block
  2. Connection static initialization block
  3. BaseConnection constructor
  4. Connection constructor

Sometimes it is difficult to understand the execution order of static initialization blocks.

In the same example, If We create an instance of the BaseConnection class instead of the Connection class.

class BaseConnection {
    static {
        console.log('BaseConnection');
    }
    constructor() {
        console.log('BaseConnection constructor');
    }
}

class Connection extends BaseConnection {
    static {
        console.log('Connection');
    }
    constructor() {
        super();
        console.log('Connection constructor');
    }
}

const a = new BaseConnection();
Enter fullscreen mode Exit fullscreen mode

If we run the above code, the execution order will be

  1. BaseConnection static initialization block
  2. Connection static initialization block
  3. BaseConnection constructor

As you can see, the static initialization block of the derived class is executed even if we create an instance of the base class. This is because the static initialization block of the derived class is executed before the constructor of the derived class.

Note: Static initialization blocks are executed only once when the class is loaded. No matter whether you are using the class or not, the static initialization block will be executed.

Must Read If you haven't

More content at Dev.to.
Catch me on

Youtube Github LinkedIn Medium Stackblitz Hashnode HackerNoon

Top comments (1)

Collapse
 
porobertdev profile image
Robert P. • Edited

Hi there,

I can't comment on the full article as I haven't read it fully yet, but what you are saying about Static Variables is wrong. I'm just learning about them.

MDN states that static properties are not inherited by instances (the objects created by the class). They're available only in the class itself.

The value of a.staticProp and b.staticProp in your given example is undefined, because the property isn't found in the object nor its prototype. That's why a.staticProp == b.staticProp.

SOURCE

Image description