JavaScript (ES11 | ES12 | ES13)

This article will walk you through 'Javascript' upgrades post ES10. (Part-2)

If JavaScript is part of your dev stack or you have people around working with JavaScript, you would know how powerful and popular JavaScript has become since the release of ES6. ES6 was the biggest release of all time in JS history and a much-needed facelift JavaScript needed to come back to the game. After pushing these many upgrades in one shot, TC39 (Unit of ECMA international which takes care of standards of JavaScript) has decided to push a version out every single year, so it doesn’t become too heavy on developers to get aligned with it. So, all releases have come in subsequent years after that and not to mention they were very small releases compared to ES6.

ES6-ES10 have been covered in part-1 of this series. We will see what we have got in ES11, ES12 and ES13 in this article.

ES11(2020)

  • String.prototype.matchAll

    The matchAll() method returns an iterator of results after matching a string against a regular expression.

    
    // string definition
    const sentence = "JavaScript1JavaScript2";
    
    // a pattern having 'JavaScript' followed by a digit
    const regex = /JavaScript\d/g;
    
    // finding matches in the string for the given regular expression
    let results = sentence.matchAll(regex);
    
    // looping through the iterator
    for (result of results) {
      console.log(result);
    }
    
    // Output:
    // ["JavaScript1", index: 0, input: "JavaScript1JavaScript2", groups: undefined]
    // ["JavaScript2", index: 11, input: "JavaScript1JavaScript2", groups: undefined]
    
    
  • Dynamic Import

    The includes() method determines whether an array includes a certain value among its entries, returning true or false.

    
    [1,2,3,4].includes(2) // true
    ["q", "w", "e", "r", "t", "y"].includes("John") // false
    
    
  • BigInt

    A BigInt value, also sometimes just called a BigInt, is a bigint primitive, created by appending n to the end of an integer literal, or by calling the BigInt() function (without the new operator) and giving it an integer value or string value.

    
    const alsoHuge = BigInt(9007199254740991) // 9007199254740991n
    const hugeString = BigInt("9007199254740991") // 9007199254740991n
    
    
  • Promise.allSettled

    The Promise.allSettled() method returns a promise that resolves after all of the given promises have either fulfilled or rejected, with an array of objects that each describes the outcome of each promise.

    It is typically used when you have multiple asynchronous tasks that are not dependent on one another to complete successfully, or you'd always like to know the result of each promise.

    In comparison, the Promise returned by Promise.all() may be more appropriate if the tasks are dependent on each other / if you'd like to immediately reject upon any of them rejecting.

    
    const promise1 = Promise.resolve(3);
    const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
    const promises = [promise1, promise2];
    
    Promise.allSettled(promises).
      then((results) => results.forEach((result) => console.log(result.status)));
    
    // expected output:
    // "fulfilled"
    // "rejected"
    
    
  • Optional Chaining

    The optional chaining operator (?.) enables you to read the value of a property located deep within a chain of connected objects without having to check that each reference in the chain is valid. This is really handy when you are interested in value of a property deep down in an object.

    The ?. operator is like the . chaining operator, except that instead of causing an error if a reference is nullish (null or undefined), the expression returns value of undefined.

    
    const person = {
      name: 'Alice',
      cat: {
        name: 'Dinah'
      }
    };
    
    const dogName = person.dog?.name;
    console.log(dogName); // undefined
    
    
  • globalThis

    The global globalThis property contains the global this value, which is akin to the global object.

    
    console.log(globalThis.screenLeft); // 0
    console.log(globalThis.screenRight); // 0
    
    
  • Nullish coalescing Operator

    The nullish coalescing operator (??) is a logical operator that returns its right-hand side operand when its left-hand side operand is Nullish(null or undefined), and otherwise returns its left-hand side operand.

    
    "" ?? "Hi" // ""
    [] ?? "Hi" // "[]"
    false ?? "Hi" // "false"
    
    null ?? "Hi" // "Hi" 
    undefined ?? "Hi" // "Hi"
    
    

ES12(2021)

  • String.prototype.replaceAll

    The replaceAll() method returns a new string with all matches of a pattern replaced by a replacement. The pattern can be a string or a RegExp, and the replacement can be a string or a function to be called for each match.

    
    const str = 'John is a bogeyman.';
    console.log(p.replaceAll('John', 'Ritik')); // "Ritik is a bogeyman."
    
    
    // global flag required when calling replaceAll with regex
    const regex = /John/ig;
    console.log(p.replaceAll(regex, 'Ritik')); // "Ritik is a bogeyman."
    
    
    
  • Promise.any

    Promise.any() takes an iterable of Promise objects. It returns a single promise that resolves as soon as any of the promises fulfills, with the value of the fulfilled promise.

    If no promises fulfill (if all of the given promises are rejected), then the returned promise is rejected with an AggregateError.

    
    const promise1 = Promise.reject(0);
    const promise2 = new Promise((resolve) => setTimeout(resolve, 100, 'quick'));
    const promise3 = new Promise((resolve) => setTimeout(resolve, 500, 'slow'));
    
    const promises = [promise1, promise2, promise3];
    
    Promise.any(promises).then((value) => console.log(value)); // "quick"
    
    
  • Logical Assignment Operators

    The logical OR assignment (x ||= y) operator only assigns if x is falsy.

    
    const a = { duration: 50, title: '' };
    
    a.duration ||= 10;
    console.log(a.duration);
    // expected output: 50
    
    a.title ||= 'title is empty.';
    console.log(a.title);
    // expected output: "title is empty"
    
    
  • Numeric separators

    Large numeric literals are difficult for the human eye to parse quickly, especially when there are lots of repeating digits:

    
    1000000000000
    1019436871.42
    
    

    To improve readability, JS enables underscores as separators in numeric literals. So, the above can now be rewritten to group the digits per thousand, for example:

    
    1_000_000_000_000
    1_019_436_871.42
    
    
  • ES13(2022)

    • Class Fields

      Public static fields are useful when you want a field to exist only once per class, not on every class instance you create. Public static fields are declared using the static keyword. They are added to the class constructor at the time of class evaluation

      
      class ClassWithStaticField {
        static staticField = 'static field'
      }
      
      console.log(ClassWithStaticField.staticField)
      // expected output: "static field"
      
      

      Public instance fields

      Public instance fields exist on every created instance of a class. By declaring a public field, you can ensure the field is always present

      Public instance fields are added with Object.defineProperty() either at construction time in the base class (before the constructor body runs), or just after super() returns in a subclass.

      
      class ClassWithInstanceField {
        instanceField = 'instance field'
      }
      
      const instance = new ClassWithInstanceField()
      console.log(instance.instanceField)
      // expected output: "instance field"
      
      

      Public static methods

      The static keyword defines a static method for a class. Static methods aren't called on instances of the class. Instead, they're called on the class itself. These are often utility functions, such as functions to create or clone objects.

      
      class ClassWithStaticMethod {
        static staticMethod() {
          return 'static method has been called.';
        }
      }
      
      console.log(ClassWithStaticMethod.staticMethod());
      // expected output: "static method has been called."
      
      
    • Top-level await

      Top-level await’ which is promoted to Stage 4 in the TC39 process lets us use the asynchronous await operator at the top level of modules. Top-level await enables modules to act as big async functions.

      
      // fetch request
      const colors = fetch('../data/colors.json')
        .then(response => response.json());
      
      export default await colors;
      
      // a simple module using the Fetch API and specifying await within the export statement. Any modules that include this will wait for the fetch to resolve before running any code.
      
      
    • .at()

      The at() method takes an integer value and returns the item at that index, allowing for positive and negative integers. Negative integers count back from the last item in the array.

      
      const arr = [1,2,3,4,5]
      console.log(arr.at(1)) // 2
      console.log(arr.at(-1)) // will give you last item of the array.// 5
      
      
    • Object.prototype.hasOwn

      The Object.hasOwn() method returns true if the specified property is a direct property of the object — even if the property value is null or undefined. The method returns false if the property is inherited, or has not been declared at all.

      It is recommended over Object.hasOwnProperty() because it works for objects created using Object.create(null) and with objects that have overridden the inherited hasOwnProperty() method. While it is possible to workaround these problems by calling Object.prototype.hasOwnProperty() on an external object, Object.hasOwn() is more intuitive.

      
      Const obj = {name: "John", lastName: "Wick"}
      console.log(obj.hasOwnProperty('name')) // true
      console.log(Object.hasOwn(obj, 'name')) // true
      
      
    • Class Static Block

      Class static initialization blocks are a special feature of a class that enable more flexible initialization of static properties than can be achieved using per-field initialization.

      
      class Construct {
        static staticProperty1 = 'Property 1';
        static staticProperty2;
        static {
          this.staticProperty2 = 'Property 2';
        }
      }
      
      console.log(Construct.staticProperty1); // output: "Property 1"
      console.log(Construct.staticProperty2); // output: "Property 2"
      
      
    • Error Cause

      Error and it's subclasses now let us specify the reason behind the error. This is useful in deeply nested function where we have chained error blocks to quickly find the error.

      
      try {
          frameworkThatCanThrow();
        } catch (err) {
          throw new Error('New error message', { cause: err });
        }
      
      
Series: JS Upgrades

JavaScript (ES7 | ES8 | ES9 | ES10)

This article will walk you through 'Javascript' upgrades post ES6. (Part-1)

Read More