The State of JavaScript in 2024

Feb 5, 2024

JavaScript has come a long way since its inception almost 30 years ago. Initially created to make web pages interactive, it has now evolved into a powerful, versatile language used in various contexts, from web development to server-side programming and even mobile app development.

Over the past decade, I’ve had the pleasure of learning and using several programming languages, but JavaScript has remained my favorite and is my go-to language for most new projects. I first started using JavaScript in its ES5.1 iteration (released in 2011), back when jQuery ruled supreme. Then, ES6 (ES2015) arrived, bringing such significant changes that I recall (albeit fondly) having to learn the language from scratch all over again.

But, ES5 is now ancient history. Most new developers will probably never have to learn how things were done before ES6 unless they are working with some legacy codebase. Let’s take a quick journey through JavaScript’s history and highlight some of the significant changes and features introduced since the ES6 overhaul.

A Brief History of JavaScript

JavaScript was created in 1995 by Brendan Eich while he was working at Netscape Communications Corporation. It was initially developed to enable interactivity on web pages and was originally called “Mocha,” later renamed to “LiveScript,” and finally “JavaScript” to capitalize on the popularity of Java at the time.

The Early Years (1995-2009)

  • 1995: JavaScript was first released as part of Netscape Navigator 2.0.

  • 1996: Microsoft introduced a similar scripting language called JScript with Internet Explorer 3.0, leading to the need for standardization.

  • 1997: The first version of the ECMAScript standard (ECMAScript 1) was published by Ecma International to ensure cross-browser compatibility.

Standardization and Growth (2009-2015)

  • 2009: ECMAScript 5 (ES5) was released, bringing significant improvements and new features such as strict mode, JSON support, and more robust object property definitions. This version became widely adopted and set the stage for more modern JavaScript development.

  • 2011: ES5.1, a minor update, was released and subsequently adopted as an ISO standard.

The Major Overhaul - ES6 (2015)

2015: ECMAScript 6 (also known as ECMAScript 2015 or ES6) marked a major milestone in JavaScript’s evolution. It introduced many new features and syntactical improvements, such as:

  • Let and Const: Block-scoped variable declarations.

  • Arrow Functions: Shorter syntax for anonymous functions.

  • Classes: A more intuitive syntax for object-oriented programming.

  • Modules: Native support for modular code.

  • Promises: A new way to handle asynchronous operations.

  • Template Literals: Enhanced string interpolation.

  • Destructuring: A convenient way to extract values from arrays and objects.

Continued Evolution

Since ES6, JavaScript has continued to evolve with annual updates, each bringing new features and improvements. The latest iteration as of writing this post is ES14 (ES2023). Here are some of the changes since ES6 that I think are significant and interesting.

ES7 (ECMAScript 2016)

  • Exponentiation Operator (**): A new operator for exponentiation.

    let squared = 2 ** 3; // 8
  • Array.prototype.includes: A method to check if an array includes a certain value.

    let arr = [1, 2, 3];
    console.log(arr.includes(2)); // true

ES8 (ECMAScript 2017)

  • async/await: A syntactic sugar for handling asynchronous operations, making code easier to read and write.

    async function fetchData() {
      let response = await fetch('https://api.example.com/data');
      let data = await response.json();
      console.log(data);
    }
    fetchData();
  • Object.entries() and Object.values(): Methods to get an object’s key-value pairs and values, respectively.

    let obj = { a: 1, b: 2, c: 3 };
    console.log(Object.entries(obj)); // [['a', 1], ['b', 2], ['c', 3]]
    console.log(Object.values(obj)); // [1, 2, 3]

ES9 (ECMAScript 2018)

  • Rest/Spread Properties: Allows for easier manipulation of objects and arrays.

    let { a, b, ...rest } = { a: 1, b: 2, c: 3, d: 4 };
    console.log(rest); // { c: 3, d: 4 }
  • Asynchronous Iteration: The for-await-of loop for iterating over async data sources.

async function process(data) {
  for await (let item of data) {
    console.log(item);
  }
}

ES10 (ECMAScript 2019)

  • Array.prototype.flat and Array.prototype.flatMap: Methods to flatten arrays.

    let arr = [1, [2, [3, 4]]];
    console.log(arr.flat(2)); // [1, 2, 3, 4]
  • Optional Catch Binding: Allows catch blocks to omit the error parameter.

    try {
      // code
    } catch {
      console.log('An error occurred');
    }

ES11 (ECMAScript 2020)

  • Optional Chaining (?.): A safe way to access deeply nested properties.

    let user = { name: 'Alice', address: { street: '123 Main St' } };
    console.log(user.address?.street); // '123 Main St'
    console.log(user.address?.zipcode); // undefined
  • Nullish Coalescing Operator (??): A way to handle null or undefined values more effectively.

    let value = null ?? 'default';
    console.log(value); // 'default'
  • Dynamic import(): A way to dynamically load modules.

    import('./module.js')
      .then(module => {
        module.doSomething();
      });

ES12 (ECMAScript 2021)

  • Logical Assignment Operators: Combines logical operators with assignment.

    let a = 1;
    a ||= 2;
    console.log(a); // 1
  • WeakRefs and FinalizationRegistry: Tools for dealing with garbage collection and memory management.

    let weakRef = new WeakRef(someObject);
    let registry = new FinalizationRegistry(heldValue => {
      console.log(`Object with held value ${heldValue} has been garbage collected`);
    });
    registry.register(someObject, 'myValue');

ES13 (ECMAScript 2022)

  • Top-Level await: Allows the use of await at the top level of modules.

    let response = await fetch('https://api.example.com/data');
    let data = await response.json();
    console.log(data);
  • New String Methods: replaceAll, at, etc.

    let str = 'aabbcc';
    console.log(str.replaceAll('b', 'd')); // 'aaddcc'

ES14 (ECMAScript 2023)

  • Array findLast and findLastIndex Methods: Methods to find the last occurrence in an array.

    let arr = [1, 2, 3, 4, 5, 6];
    console.log(arr.findLast(x => x % 2 === 0)); // 6
  • Hashbang Grammar: Allows scripts to start with #! for better compatibility with Unix-based systems.

    #!/usr/bin/env node
    console.log('Hello, world!');
  • Symbol description Property: Provides a description for symbol instances.

    let sym = Symbol('description');
    console.log(sym.description); // 'description'
  • WeakRefs and FinalizationRegistry Improvements: Enhancements to these memory management tools.

    let registry = new FinalizationRegistry(value => {
      console.log(`Finalized ${value}`);
    });

Conclusion

JavaScript’s journey from a simple scripting language to a powerful and versatile programming language is a testament to its adaptability and the active involvement of the developer community. Each new version brings enhancements that make JavaScript more robust, efficient, and easier to use, ensuring it remains a cornerstone of web development.

As a developer who has used JavaScript extensively over the years, I’ve witnessed firsthand how these updates have transformed the way we build applications. From the days of struggling with ES5 to the excitement of learning ES6 and beyond, it’s been an incredible evolution. JavaScript’s continuous improvement has not only made my work more enjoyable but also opened up new possibilities and simplified many complex tasks.

Whether you’re a seasoned developer or just starting your coding journey, JavaScript’s evolution promises to keep delivering tools and features that will help you create amazing projects. I look forward to exploring what the future holds for this ever-evolving language and continuing to share my experiences and learnings with the community.

All rights reserved.

© 2024

Sean Mishra

All rights reserved.

© 2024

Sean Mishra