ECMAScript 2023 (ES14) introduced several enhancements to JavaScript, optimizing both functionality and expressiveness. This article shows you the latest additions: the much-anticipated findLast
and findLastIndex
array methods, new immutable array methods like toSorted
and toSpliced
, symbols as WeakMap keys, and the inclusion of Hashbang Grammar.
Since the introduction of ES2015, commonly known as ES6, JavaScript has been evolving at a dynamic pace. With new functionality being added every year, the latest release—ECMAScript 2023 (ES14)—brings a number of useful features to JavaScript.
In this article, we will delve into the latest additions—new array methods, symbols as WeakMap keys and Hashbang Grammar support.
ES2023 introduced the findLast
array method, a very useful addition that simplifies the process of locating the last element in an array that satisfies a given predicate function. Let’s illustrate this with an example:
const numbers = [1, 2, 3, 4, 5, 6, 7]
const lastEvenNum = numbers.findLast(number => number % 2 === 0)
// lastEvenNum is 6
With findLast
, you can quickly pinpoint the last matching element in an array. Before this, there were a few different solutions to achieving this result. For example, we could first reverse an array and then find the first element that matches the predicate.
const numbers = [1, 2, 3, 4, 5, 6, 7]
const lastEvenNum = [...numbers].reverse().find(number => number % 2 === 0)
// lastEvenNum is 6
This solution is OK when not dealing with very large arrays. The code above creates a new copy of the numbers
array, reverses it and then finds the first element that matches the predicate. The cost of additional operations is negligible if you are dealing with small datasets.
A more performant approach requires looping through the numbers array just once and assigning values that match the predicate to a variable.
const numbers = [1, 2, 3, 4, 5, 6, 7]
let lastEvenNum
for (const num of numbers) {
if (num % 2 === 0) {
lastEvenNum = num
}
}
// lastEvenNum is 6
This solution is more imperative, but is much faster, as it requires only one loop and doesn’t involve copying the numbers array and reversing it.
Building on the concept of finding the last element, ES2023 also introduced findLastIndex
. This method returns the index of the last element that meets a specific condition. Here’s a practical application:
const numbers = [1, 2, 3, 4, 5, 6, 7]
const lastEvenNumIndex = numbers.findLastIndex(number => number % 2 === 0)
// lastEvenNumIndex is 5
Below, you can see how we can find an index of the last element that matches the predicate using a for loop.
let lastEvenNumIndex;
for (let i = 0; i <= numbers.length; i++) {
const num = numbers[i];
if (num % 2 === 0) {
lastEvenNumIndex = i;
}
}
// lastEvenNumIndex is 5
The findLastIndex
method is much cleaner and more declarative than the imperative for loop solution.
findLast
and findLastIndex
are not the only array methods introduced in ES2023. Other new array methods are toSorted
, toSpliced
and with
.
But wait, don’t we already have sort
and splice
methods? Why do we need toSorted
and toSpliced
?
The problem with sort
and splice
methods is that they mutate the original array they are called on. Here’s an example:
const fruits = ['banana', 'kiwi', 'apple', 'orange']
const sortedFruits = fruits.sort((a, b) => a.localeCompare(b))
// sortedFruits is ['apple', 'banana', 'kiwi', 'orange']
// fruits also is now ['apple', 'banana', 'kiwi', 'orange']
The sortedFruits
const receives a sorted array of fruits. However, the fruits
array was also modified. This behavior can lead to accidental data mutations that were not expected.
The same applies to the splice
method. The splice
method can be used to add, replace and remove items from an array, but it also mutates the original array. That’s where the new methods come in. Let’s have a look at each of the newly added methods.
The toSorted
method, as you probably already guessed, is a new alternative to the sort
method. It allows you to create a sorted version of an array without altering the original. Here’s an example of sorting fruits alphabetically, but this time with the toSorted
method.
const fruits = ['banana', 'kiwi', 'apple', 'orange']
const sortedFruits = fruits.toSorted((a, b) => a.localeCompare(b))
// sortedFruits is ['apple', 'banana', 'kiwi', 'orange']
// fruits is ['banana', 'kiwi', 'apple', 'orange']
The toSorted
method creates a copy instead of mutating the original array. This results in more predictable code and prevents accidental data mutations.
With toSpliced
, you can create a new array by splicing elements without modifying the source array.
const items = ['carrot', 'banana', 'potato']
const vegetables = items.toSpliced(1, 1)
// vegetables is ['carrot', 'potato']
This method is particularly handy when you need to manipulate arrays without side effects.
Completing the set of new array methods is the with
method. It enables you to replace an element at a specified index, creating a new array while preserving the original:
const vegetables = ['carrot', 'potato']
const updatedVegetables = vegetables.with(1, 'parsnip')
// updatedVegetables is ['carrot', 'parsnip']
The with
method is an immutable equivalent of updating an array using the bracket notation.
const vegetables = ['carrot', 'potato']
const newVegetables = [...vegetables]
newVegetables[1] = 'parsnip'
// updatedVegetables is ['carrot', 'parsnip']
Another interesting change in ES2023 is the inclusion of symbols as WeakMap keys. Previously, symbols were not allowed in this context. This enhancement offers new possibilities, as illustrated in the following example:
const weakMap = new WeakMap()
const uniqueSymbolKey = Symbol('myUniqueSymbolKey')
weakMap.set(uniqueSymbolKey, 'value')
console.log(weakMap.get(uniqueSymbolKey)) // 'value'
This update extends the versatility of symbols and WeakMaps, which are a great tool for associating additional information to certain values without affecting garbage collection.
JavaScript in ES2023 now embraces Hashbang Grammar, allowing developers to specify the program or engine used to execute a script. This feature is useful in various environments and can be implemented as follows:
#!/usr/bin/env node
console.log('I am a JS script that should be run in Node.js!')
ES2023 ushered in a new era of JavaScript development, marked by improved functionality and expressiveness. The new array methods, immutable array methods, symbols as WeakMap keys, and Hashbang Grammar collectively contribute to a more versatile and efficient language.
Thomas Findlay is a 5-star rated mentor, full-stack developer, consultant, technical writer and the author of “React - The Road To Enterprise” and “Vue - The Road To Enterprise.” He works with many different technologies such as JavaScript, Vue, React, React Native, Node.js, Python, PHP and more. Thomas has worked with developers and teams from beginner to advanced and helped them build and scale their applications and products. Check out his Codementor page, and you can also find him on Twitter.