Complete Guide of New JavaScript Features from ECMAScript 2023
Complete Guide of New JavaScript Features from ECMAScript 2023
Photo by Joan Gamell on Unsplash
What is ECMAScript and how does it relate to JavaScript?
ECMAScript is a scripting language specification that outlines the features and syntax they must adhere to during implementation. In other words, ECMAScript provides a set of rules, syntax, and features that a scripting language must adhere to in order to be considered compliant with the ECMAScript standard.
JavaScript is one of those languages that adheres to this standard. JavaScript engines interpret and run JavaScript code according to the ECMAScript specification. V8 is a Javascript engine for Google Chrome and Node.js, while SpiderMonkey is the engine for Firefox. Some JavaScript engines have unique implementations, but their primary goal is to adhere to the ECMAScript standard as best as possible for consistent behavior across platforms and browsers.
ECMAScript 2023 (aka ES2023 or ES14) was released in June of 2023. Chrome has supported these new features since version 110, but be sure to check that these features are available in other runtime environments before using them in your project. Click on the header for each feature in this blog to be directed to the MDN documentation to check browser support and more in depth information. Most AI coding tools, like chatGPT-3.5, are not yet aware of these new features since they came out after their data models have been trained.
Ecma International posted the following statement on their site regarding this release:
Immutable Array Methods
With the ES14 version, Array.prototype added 4 new methods that change by copy: toReversed
, toSorted
, toSpliced
, and with
. These are immutable array methods, which make a copy of the array with the applied modifications without affecting the original array that they were called on.
Any array method that creates a copy, always does so shallowly. If there is an object in the array, the object reference is copied into the new array. In this case, both the original and new array refer to the same object. So when the object changes, all properties referring to the object reflect the change. Keep this in mind when using these methods if you have nested data in your array. Primitive types such as strings
, numbers
and booleans
, are copied by value into the new array, so there is no reference to the original array.
Immutable array methods are very useful when working with state and props in JavaScript libraries like React and Redux. React relies on immutable props and not changing a state value directly in order to determine when to re-render components and with what values. Mutating state directly can lead to unnecessary re-renders, as well as make it difficult to debug and test.
toReversed
// Syntax
toReversed()
The toReversed()
Array
method is the copying counterpart of reverse(). It returns a new array with the elements in reversed order and does not take in any parameters.
const originalArray = [1, 2, 3, 4, 5];
// toReversed
const newArray = originalArray.toReversed();
console.log(originalArray); // Output: [1, 2, 3, 4, 5] the array is unmodified
console.log(newArray); // Output:[5, 4, 3, 2, 1]
// old ways to create a reversed array without modification
// slice and reverse
const copy = originalArray.slice(); // make shallow copy
const newArray2 = copy.reverse(); // Reverse the copy
console.log(originalArray); // Output: [1, 2, 3, 4, 5]
console.log(newArray2); // Output: [5, 4, 3, 2, 1]
// spread
const copy2 = [...originalArray]; // copy values of original array into new array
const newArray3 = copy2.reverse();
console.log(originalArray); // Output: [1, 2, 3, 4, 5]
console.log(newArray3); // Output: [5, 4, 3, 2, 1]
toSorted
// Syntax
toSorted()
toSorted(compareFn)
toSorted
has the same signature as sort
, but it creates a new sorted array instead of sorting the array that it was called on. It returns a new array with the elements sorted in ascending order. The toSorted
method takes in one optional parameter, which is a caparison function that defines the sort order. If this parameter is left out, the array elements are converted to strings and sorted according to each character’s Unicode code point value. Therefore, make sure you include a comparison function when sorting numbers. When used on sparse arrays, the toSorted
method iterates empty spots as if the value isundefined
.
const letters = ["D", "A", "E", "C", "B"]
const numbers = [4, 2, 5, 1, 3]
// toSorted
const sortedLetters = letters.toSorted();
console.log(letters) // Output: ["D", "A", "E", "C", "B"]
console.log(sortedLetters) // Output: ["A", "B", "C", "D", "E"]
const sortedNumbers = numbers.toSorted((a, b) => a - b)
console.log(sortedNumbers) // Output: [1, 2, 3, 4, 5]
// common mistake using numbers
const nums2 = [0, 15, 5, 10, 20]
const sortedNums2 = nums2.toSorted()
console.log(sortedNums2) // Output: [0, 10, 15, 20, 5]
// sort method changes array that it called on
letters.sort()
console.log(letters); // Output: ["A", "B", "C", "D", "E"]
toSpliced
// Syntax
toSpliced(start)
toSpliced(start, deleteCount)
toSpliced(start, deleteCount, item1)
toSpliced(start, deleteCount, item1, item2)
toSpliced(start, deleteCount, item1, item2, /* …, */ itemN)
toSpliced
is the copying version of the splice
method. toSpliced
removes and/or replaces elements at a given starting index into a new array without modifying the original. The first parameter (start
) is a zero based index where changes to the array begins. A negative start
parameter counts backwards from the end. Also, if start
is greater than the length of the array, no elements will be deleted, but toSpliced
will add all of the items after the second argument to the end of the array. deleteCount
is the number of elements in the array to remove from start
. If deleteCount
is not included, or if the value is ≥ the number of elements after start
, then all the elements from start
to the end of the array will be deleted. If you want to to intentionally do this, you should pass Infinity
as deleteCount
since undefined
gets converted to 0
. After the first 2 parameters, you can include items (item1
, …, itemN
) that will be inserted into the array, beginning from start
.
const numbers = [1, 2, 6, 6, 7]
// toSpliced method
// starting at index 2, delete 1 element, then add the values - 3, 4, and 5
const result = numbers.toSpliced(2, 1, 3, 4, 5)
console.log(numbers) // Output: [1, 2, 6, 6, 7]
console.log(result) // Output: [1, 2, 3, 4, 5, 6, 7]
// delete all values after start and insert values
const result2 = numbers.toSpliced(2, Infinity, 3, 4, 5)
console.log(result2) // Output: [1, 2, 3, 4, 5]
// start >= array length, delete is ignored, but items are added
const result3 = numbers.toSpliced(999, 1, 3, 4, 5)
console.log(result3) // Output: [1, 2, 6, 6, 7, 3, 4, 5]
with
// Syntax
arrayInstance.with(index, value)
The with
method of Array instances is the copying version of using the bracket notation (array[index] = newValue
). The with
method updates a single element at a given index and returns a new array. This method takes in an index and the value to be inserted at that index.
const numbers = [1, 2, 9999, 4]
const result = numbers.with(2, 3)
console.log(numbers) // Output: [1, 2, 9999, 3]
console.log(result) // Output: [1, 2, 3, 4]
// bracket notation modifies the original array
numbers[2] = 3;
console.log(numbers) // Output: [1, 2, 3, 4]
// Old ways to create a new array with one value swapped at an index
// using map
const originalArray1 = [1, 2, 3, 4, 5];
const indexToReplace = 2;
const newValue = 10;
const newArray1 = originalArray1.map((element, index) => {
if (index === indexToReplace) {
return newValue;
}
return element;
});
console.log(newArray1); // Output: [1, 2, 10, 4, 5]
// using spread and slice
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const arr2 = [...arr.slice(0, 1), "hey", ...arr.slice(2)]
console.log(arr2) // Output: [1, "hey", 3, 4, 5, 6, 7, 8, 9]
Array Last Methods
If you know that a piece of data was towards the end of an array, findIndex
and findLastIndex
would be more efficient and simple than their counterparts find
and findIndex
. Before ES14, if you wanted to find the last element or index in an array that satisfies some condition, you would have to either reverse the array first or use a for loop
that starts from the end.
findLast
// Syntax
findLast(callbackFn)
findLast(callbackFn, thisArg)
The findLast()
Array
method begins iterating from the end of the array and returns the value of the first element that satisfies the conditions in the callback function. If no elements satisfy the testing function, undefined is returned. Each element of the array is passed into the callback function one by one.
const numsArray = [4, 51, 40, 99, 16]
const lastBigNum = numsArray.findLast((num) => num > 50)
console.log(lastBigNum) // Output: 99
findLastIndex
// Syntax
findLastIndex(callbackFn)
findLastIndex(callbackFn, thisArg)
The findLastIndex()
Array
method iterates over the array in reverse order and returns the index
of the first element that satisfies the provided testing callback function. If no elements satisfy the conditions of the function, then -1
is returned. JavaScript returns -1 since an array cannot have a negative index, which lets you know that there were no matching elements in that array.
const numsArray = [4, 51, 40, 99, 16]
const lastBigNumIndex = numsArray.findLastIndex((num) => num > 50)
console.log(lastBigNumIndex) // Output: 3
All the array methods introduced in ES14 except for toSpliced(), also apply to TypedArray.prototype. In JavaScript, a TypedArray is an array-like object that provides a way to work with binary data in a typed manner. Click here to learn more about TypedArray.
#! Hashbang (aka Shebang) Comments Support
// Syntax
#! interpreter [optional-arg]
Hashbang comments begins with #!
and is only valid at the absolute start of a script or module. No whitespace is permitted before the #!
. The standardization of hashbangs in executable scripts now allows JavaScript files to be run directly from the command line. Now, you can run JavaScript code with the command ./fileName.js
instead of something like node fileName.js
. First, make sure that you have permissions to execute the file by running the command: ls -l filename.js
. To add execute permissions, run the command: chmod +x fileName.js
.
#!/usr/bin/env node
console.log("Javascript is so cool!")
// Output: Javascript is so cool!
To run the file above, just run the commend: ./fileName.js
and it will log out: Javascript is so cool!
.
Symbols as Keys in Weak Collections
ES14 allows non-registered Symbols to be used as keys in weak collections, such as WeakMap, WeakRef, and WeakSet. Previously, only objects were allowed as keys in these collections. Weak collections are data structures that do not keep a strong reference to its elements. This means that if no other references to a value stored in the weak collection exist, then those values can be garbage collected. Unlike most primitive data types, objects and non-registered symbols can be stored as keys on weak collections because they are garbage-collectable. Weak collections are useful for storing objects that you do not want to keep alive, such as temporary metadata on objects or objects that are only used as a key in a map. A Symbol is a unique and immutable value often used as an object property key, since keys should be unique. Only non-registered Symbols can be used as keys in weak collections though. A registered Symbol is one that was created by using the Symbol.for() method, which adds the symbol to a global registry, therefore making it unable to be garbage collected. More commonly, a Symbol is created like Symbol(“description”)
, which has a scope limited to the current JavaScript file or module, unless it is exported and imported into another.
const weakMapIds = new WeakMap()
const key = Symbol("userId")
weakMapIds.set(key, "123abc")
console.log(weakMapIds.get(key))// Output: 123abc
Great job! You made it through! Check out the MDN docs to learn more about each feature by clicking on anything in this article that is underlined. Be sure to also try each of these out for yourself!
Feel free to get in touch with me on LinkedIn! Also, please book a session on codementor.io with me if you would like mentoring or would like me to work on a project with you freelancing. Please like, comment, and follow if you like what you read. Have fun coding!
LinkedIn: linkedin.com/in/rashaun-warner/