A Deep Dive into ES10: Powerful New JavaScript Features

ES10 - ECMAScript 2019

As a full-stack developer who has worked with JavaScript for over a decade, I‘ve seen the language evolve at a remarkable pace. With each new version of the ECMAScript specification, JavaScript gains powerful features that make it more expressive, efficient, and enjoyable to work with.

The latest version, ES10 (or ECMAScript 2019), is no exception. It introduces a wide range of new capabilities that address common pain points and make JavaScript more capable than ever before. In this deep dive, we‘ll explore the most significant additions in ES10 and see how they can be applied in real-world development.

Array Flattening and Mapping

One of the most impactful changes in ES10 is the addition of the flat() and flatMap() methods to the Array prototype. These methods make it simple to flatten nested arrays and map & flatten in a single operation, respectively.

Array.prototype.flat()

The flat() method creates a new array with all sub-array elements concatenated into it recursively up to a specified depth. It takes an optional depth argument (defaulting to 1) which specifies how deep the flattening should recursively apply.

const nestedArray = [1, [2, [3, [4]]]];

// Flatten one level deep
nestedArray.flat(); // [1, 2, [3, [4]]]

// Flatten two levels deep
nestedArray.flat(2); // [1, 2, 3, [4]]

// Flatten fully
nestedArray.flat(Infinity); // [1, 2, 3, 4]

This is a significant improvement over the previous approaches to flattening arrays, which typically involved recursion or reducing and concatenating. With flat(), flattening becomes a simple and intuitive operation.

Array.prototype.flatMap()

The flatMap() method is a combination of map() and flat(). It first maps each element of the array using a mapping function, then flattens the result into a new array. It is equivalent to a map followed by a flat of depth 1.

const numbers = [1, 2, 3];

// Square each number and flatten
numbers.flatMap(x => [x ** 2]); // [1, 4, 9]

// Equivalent to map() and flat()
numbers.map(x => [x ** 2]).flat(); // [1, 4, 9]

flatMap() is particularly useful when you need to map an array and the mapping function returns an array or a value that needs to be flattened. It saves you from having to perform the flattening as a separate step.

Array flattening and mapping in ES10

These array additions in ES10 make working with nested data structures much more concise and readable. They are already widely supported in modern browsers and Node.js, as shown in this compatibility table:

Browser/Runtime flat() flatMap()
Chrome 69 69
Firefox 62 62
Safari 12 12
Edge 79 79
Node.js 11 11

Source: MDN Web Docs

Object Manipulation

ES10 also introduces several new features for working with objects, including Object.fromEntries() for creating objects from key-value pairs and Object.entries() for converting objects into arrays of key-value pairs.

Object.fromEntries()

Object.fromEntries() is a new static method that allows you to easily create an object from an iterable of key-value pairs, such as an array or a Map. It is the inverse of Object.entries().

const entries = [
  [‘a‘, 1],
  [‘b‘, 2],
  [‘c‘, 3]
];

const obj = Object.fromEntries(entries);
console.log(obj); // { a: 1, b: 2, c: 3 }

This is particularly handy when you need to transform data from one format to another, such as converting a Map to an object or reshaping the results of Object.entries().

const map = new Map([
  [‘foo‘, ‘bar‘],
  [‘baz‘, 42]
]);

const obj = Object.fromEntries(map);
console.log(obj); // { foo: "bar", baz: 42 }

According to the 2020 State of JS Survey, object manipulation is one of the most common tasks JavaScript developers perform, with over 90% of respondents indicating they work with objects frequently.

Object manipulation in JavaScript

Source: 2020 State of JS

The addition of Object.fromEntries() in ES10 makes this type of object manipulation much more straightforward and efficient.

Object.entries()

While Object.entries() itself is not new in ES10 (it was introduced in ES8), it is worth mentioning as it is the counterpart to Object.fromEntries(). Object.entries() returns an array of a given object‘s own enumerable string-keyed property [key, value] pairs.

const obj = { a: 1, b: 2, c: 3 };

const entries = Object.entries(obj);
console.log(entries); // [[‘a‘, 1], [‘b‘, 2], [‘c‘, 3]]

Together, Object.entries() and Object.fromEntries() provide a convenient way to convert between objects and arrays of key-value pairs. This is useful in scenarios such as:

  • Iterating over an object‘s properties
  • Applying array methods to objects (e.g., mapping, filtering)
  • Serializing or deserializing objects

String Manipulation

ES10 introduces several new methods for working with strings, including trimStart(), trimEnd(), and String.prototype.matchAll().

String.prototype.trimStart() and trimEnd()

The trimStart() and trimEnd() methods remove whitespace from the beginning and end of a string, respectively. They provide a more explicit and intention-revealing way to trim strings compared to the existing trim() method.

const string = ‘   hello world   ‘;

string.trimStart(); // ‘hello world   ‘
string.trimEnd();   // ‘   hello world‘

These methods are also aliased as trimLeft() and trimRight() for consistency with other programming languages.

String.prototype.matchAll()

The matchAll() method returns an iterator of all results matching a string against a regular expression, including capturing groups. It provides a more convenient and efficient way to iterate over matches compared to the existing match() and exec() methods.

const string = ‘test1test2‘;
const regex = /t(e)(st(\d?))/g;

for (const match of string.matchAll(regex)) {
  console.log(match);
}

Output:

[
  ‘test1‘,
  ‘e‘,
  ‘st1‘,
  ‘1‘,
  index: 0,
  input: ‘test1test2‘,
  groups: undefined
],
[
  ‘test2‘,
  ‘e‘,
  ‘st2‘,
  ‘2‘,
  index: 5,
  input: ‘test1test2‘,
  groups: undefined
]

String manipulation is a cornerstone of JavaScript development, and these new methods in ES10 make common string operations more expressive and efficient.

Symbols and BigInts

ES10 also introduces improvements to two of JavaScript‘s newer primitive types: Symbols and BigInts.

Symbol.prototype.description

Symbols are unique and immutable primitive values that can be used as keys for object properties. In ES10, the read-only description property was added to the Symbol prototype to allow retrieving a symbol‘s optional description.

const symbol = Symbol(‘My Symbol‘);

console.log(symbol.description); // ‘My Symbol‘

This addition provides a more direct and intuitive way to access a symbol‘s description compared to the previous approach of calling toString() on the symbol.

BigInt

BigInt is a new primitive type introduced in ES10 that allows representing and manipulating integers beyond the safe integer limit of Number (2^53 – 1). BigInts are created by appending n to the end of an integer or by calling the BigInt() constructor.

const bigint = 1234567890123456789012345678901234567890n;

console.log(typeof bigint); // ‘bigint‘

BigInts bring a new level of precision to mathematical operations in JavaScript, particularly in fields like cryptography and finance where large numbers are common.

According to the 2020 State of JS Survey, 14.5% of developers have used BigInts and 23.8% are interested in learning more about them, indicating growing adoption and interest in this feature.

BigInt usage and interest

Source: 2020 State of JS

Dynamic Imports

ES10 introduces dynamic import() expressions, which allow dynamically loading modules at runtime. This is in contrast to static import declarations, which can only be used at the top level of a module.

// Static import
import { foo } from ‘./foo.js‘;

// Dynamic import
import(‘./bar.js‘)
  .then(module => {
    module.bar();
  });

Dynamic imports are particularly useful for conditionally loading modules, lazy loading, and dependency injection. They allow for more flexibility and efficiency in module loading compared to static imports.

The use of dynamic imports has been steadily growing in the JavaScript ecosystem. A 2020 analysis of over 1 million JavaScript projects on GitHub found that 12% of them used dynamic imports, with usage doubling year over year.

Dynamic import usage growth

Source: JavaScript Rising Stars 2020

Additional Features

In addition to the major features covered above, ES10 includes several other notable enhancements:

  • Array.prototype.sort() stability: The sorting algorithm used by Array.prototype.sort() is now required to be stable, meaning that elements with the same sort key maintain their relative order.
  • Function.prototype.toString() revision: The toString() method of functions now returns a string that includes the function‘s parameter list, code, and any comments or whitespace present in the original source.
  • globalThis object: The globalThis property provides a standard way to access the global object across environments (e.g., window in browsers, global in Node.js).
  • Well-formed JSON.stringify(): JSON.stringify() now outputs well-formed Unicode strings, properly escaping lone surrogates and preserving surrogate pairs.
  • Hashbang grammar: ES10 standardizes the #! (hashbang) syntax used in Unix-like systems to indicate the interpreter for a script.
  • Numeric separators: Numeric literals can now include underscores (_) as separators to improve readability, e.g., 1_000_000.

These features, while perhaps less impactful than the major additions like flat() and Object.fromEntries(), demonstrate the ongoing refinement and maturation of the JavaScript language.

Conclusion

ES10 represents a significant step forward for JavaScript, introducing powerful new features and syntax that make the language more expressive, efficient, and enjoyable to work with. From flattening arrays to manipulating objects to handling large numbers, this version addresses many of the pain points and limitations developers have historically faced.

As a seasoned full-stack developer, I‘ve found that staying up-to-date with the latest ECMAScript features is essential for writing clean, performant, and maintainable code. The enhancements in ES10 have already proven invaluable in my own projects, saving me time and effort while also making my code more readable and robust.

If you‘re not already using ES10 in your JavaScript development, I highly recommend exploring these new features and considering how they can be applied in your own work. With wide support across modern browsers and Node.js, there‘s little reason not to leverage the latest and greatest that JavaScript has to offer.

As always, the JavaScript community continues to innovate and push the language forward. I‘m excited to see what new capabilities and improvements future ECMAScript versions will bring. In the meantime, ES10 provides a solid foundation for writing powerful, efficient, and expressive JavaScript code.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *