0%
Reading Settings
Font Size
18px
Line Height
1.5
Letter Spacing
0.01em
Font Family
Table of contents
    blog cover

    Modern JavaScript OOP Features

    Software Engineer
    Software Engineer
    Frontend
    Frontend
    published 2025-06-28 21:18:52 +0700 · 5 mins read
    When I first started learning JavaScript, its object-oriented features felt like an afterthought. The language had objects and prototypal inheritance, but it was missing key features like true private fields and methods. That’s why many developers turned to TypeScript or other tools to write more structured OOP-style code.

    But in recent years, JavaScript has come a long way. Thanks to the latest ECMAScript updates, it now supports a much more powerful and expressive approach to OOP, with built-in features like classes, inheritance, static fields, private fields, getters and setters, and more. Let’s take a look at how these modern features work in practice.

    1. Class syntax

    JavaScript’s class syntax provides a modern and intuitive way to define objects and behavior.
    // language: javascript
    class Animal {
      constructor(name) {
        this.name = name;
      }
    
      speak() {
        console.log(`${this.name} makes a sound.`);
      }
    }

    Browser support: Global 96.06%
    Ref: 

    2. Class fields 

    Class fields allow you to define instance properties directly in the class body, outside the constructor. There are two types of class fields:
    • Instance Fields: These are defined directly on each instance of the class. They can be initialized with a default value or left undefined.
    • Static Fields: These are defined with the static keyword and belong to the class itself, not its instances.
    // language: javascript
    class Person {
      country = "Viet Nam";      // Instance field — each object gets its own "country"
      static count = 0;          // Static field — shared across all instances
    }
    
    const john = new Person();
    
    console.log(Person.count);    // 0  -> Accessing static field on the class
    console.log(Person.country);  // undefined
    console.log(john.country);    // Viet Nam -> Accessing instance field on the object
    console.log(john.count);      // undefined

    Browser support: Global 94.12%
    Ref: 

    3. Private fields and methods with #

    One of the biggest upgrades in modern JavaScript OOP is the introduction of truly private fields and methods, using the # syntax. Before this, developers had to rely on naming conventions (like _private), closures, or Symbols to simulate privacy — none of which offered real protection from outside access.

    NOTE: Code run in the Chrome console can access private properties outside the class. This is a DevTools-only relaxation of the JavaScript syntax restriction.
    // language: javascript
    class BankAccount {
      #balance = 0;
    
      constructor(owner) {
        this.owner = owner;
      }
    
      deposit(amount) {
        if (this.#isPositive(amount)) {
          this.#balance += amount;
        }
      }
    
      getBalance() {
        return this.#balance;
      }
    
      #isPositive(value) {
        return typeof value === "number" && value > 0;
      }
    }
    
    const account = new BankAccount("Nam");
    account.deposit(100);
    console.log(account.getBalance()); // 100
    console.log(account.#balance); // ❌ Error
    console.log(account.#isPositive(5)); // ❌ Error

    Browser support: Global 93.97%
    Ref:

    4. Getters and setters

    JavaScript classes allow you to define get and set methods for properties. This is useful for encapsulation, validation, or computed properties.
    // language: javascript
    class Product {
      #price = 0;
    
      get price() {
        return `$${this.#price.toFixed(2)}`;
      }
    
      set price(value) {
        if (value < 0) throw new Error("Price can't be negative");
        this.#price = value;
      }
    }
    
    const item = new Product();
    item.price = 25.5;
    console.log(item.price); // $25.50

    You interact with getters and setters like regular properties, but behind the scenes, you have full control over access and logic.
    Ref: 

    5. Inheritance with extends

    Inheritance is a core concept in OOP, and modern JavaScript supports it natively using the extends and super keywords. It allows one class (a subclass) to inherit properties and methods from another class (the superclass), enabling code reuse and polymorphism.
    // language: javascript
    class Vehicle {
      constructor(type) {
        this.type = type;
      }
    }
    
    class Car extends Vehicle {
      constructor(brand) {
        super("car");  // Call parent constructor
        this.brand = brand;
      }
    
      describe() {
        console.log(`${this.brand} is a type of ${this.type}`);
      }
    }
    
    const car = new Car("Toyota");
    car.describe(); // Toyota is a type of car

    Browser support: Global 95.04%
    Ref: 

    6. Static class blocks

    Static initialization blocks are declared within a class. It contains statements to be evaluated during class initialization, before any instance is created. This feature is useful when you need to initialize static fields with computed values, validate class-level configuration, or group related static logic together.

    // language: javascript
    class AppConfig {
      static version;
      static environment;
    
      static {
        this.version = "1.0.0";
        this.environment = process.env.NODE_ENV || "development";
    
        if (this.environment === "production") {
          console.log("Production mode enabled");
        }
      }
      
      constructor() {
        console.log("App initialized!");
      }
    }
    
    // Suppose process.env.NODE_ENV is null
    
    console.log(AppConfig.version)      // 1.0.0
    console.log(AppConfig.environment)  // development
    new AppConfig()                     // App initialized!

    You can declare multiple static blocks, and they will run in order of appearance. Inside a static block, this refers to the class itself, just like in static methods.
    Browser support: Global 92.31%
    Ref: 

    7. Babel plugins

    To ensure your code runs smoothly everywhere, you can use Babel, a JavaScript transpiler that converts modern syntax into backward-compatible code. To support the latest class syntax, make sure to include the following Babel plugins:
    // language: bash
    @babel/plugin-transform-class-properties
    @babel/plugin-transform-private-methods
    @babel/plugin-transform-private-property-in-object
    @babel/plugin-transform-class-static-block

    7. Conclusion

    If you haven’t used JavaScript’s OOP features in a while, now is a great time to revisit them. While it still lacks a few things like abstract classes or interfaces, the current feature set is good enough for writing well-structured, maintainable code. And with the language evolving quickly, I believe that we’ll see more improvements soon.

    Please note that the “Browser support” number in this blog is recorded as of June 2025. For the most up-to-date information, please refer to the link provided.

    Related blogs