owned this note
owned this note
Published
Linked with GitHub
# Introduction
JavaScript is a programming language employed in websites, web applications, and other contexts.
The latest iteration of JavaScript, [ECMAScript 2023](https://tc39.es/ecma262/2023/), released in 2023 under the name ECMAScript 2023, introduces new features and enhancements, which include four additional methods for the Array class.
The methods comprise:
- `toSorted()`
- `toReversed()`
- `toSpliced()`
- `with()`
These methods hold significance as they enable the manipulation of arrays without altering their original state. They prove valuable for functional programming and enhancing code predictability.
This article explains these innovative methods, encompassing their interactions with sparse arrays and objects resembling arrays.
Following this article, you will gain a profound understanding of:
- `toReversed()` method
- `toSorted()` method
- `toSpliced(start, deleteCount, item1)` method
- The `with(index, value)` method and
- Keeping the original arrays without changes
# Why keep the original array intact?
The four new array methods in ECMAScript 2023 return a new array instead of mutating the original collection, which is essential because it has several benefits, including:
* **Immutability**: Data passed to the array methods remains unchanged, meaning they do not modify it. It makes them ideal for functional programming, where immutability is a fundamental principle.
* **Traceability**: The new array methods make state management more traceable by creating new copies of the state object. It eliminates unexpected changes to the state and makes it easier to track how the state has changed over time.
* **Reactivity**: The new array methods make reactivity easier by creating new copies of the state object. It allows you to react to changes in the state by updating the user interface accordingly.
In general, there are many benefits to using immutable data. The four new array methods in ECMAScript 2023 take advantage of this by returning new arrays instead of mutating the original collections.
Doing this makes them valuable to the JavaScript language for functional programming and state management.
# The `toReversed()` method
The `toReversed()` method is a new addition to the JavaScript language in ECMAScript 2023.
It is similar to the `reverse()` method but does not mutate the original array. Instead, it returns a new array with the elements in reversed order.
For example, consider the following array of countries:
```javascript
const countries = ['Nigeria', 'Australia', 'England']
```
The initial array is mutated using the former `reverse()` method to reverse the order of an array. For example, in the following code snippet
```javascript
// Reverse the array
const result = countries.reverse();
console.log(result);
// [ 'England', 'Australia', 'Nigeria' ]
console.log(countries);
// [ 'England', 'Australia', 'Nigeria' ]
// Initial array is mutated
```
Using `reverse()`, the initial array is mutated.
To reverse the same array without modifying, you can use the `toReversed()` method as follows:
```javascript
const countries = ["Nigeria", "Australia", "England"];
console.log(countries); // ['Nigeria', 'Australia', 'England']
const reversedCountries = countries.toReversed();
console.log(reversedCountries); // ['England', 'Australia', 'Nigeria']
console.log(countries); // ['Nigeria', 'Australia', 'England']
```
The example above defines and prints an array named countries with three country names. Then, a new array appears that is the reverse of the items array. The original items array remains unchanged.
## Using `toReversed()` on sparse arrays
As a quick recap, let's revisit the concept of sparse arrays, which are arrays containing non-sequential elements. For instance, observe the following scenario:
```javascript
const characters = ['a', 'b', 'c'];
// Assign an item to index 10
characters[10] = 'd';
console.log(characters);
// ['a', 'b', 'c', empty × 6, 'd']
```
In the given example, the `characters` array contains six unpopulated item slots, classifying it as a sparse array. Now, let's delve back into `toReversed()` and explore its behavior with a different example of sparse arrays.
It's essential to highlight that `toReversed()` ensures the absence of a sparse array in its return. Should the original array include vacant slots, these slots will manifest as `undefined` values upon retrieval.
Consider applying `toReversed()` to the `characters` array below:
```javascript
const characters = ['a', 'b', 'c'];
// Assign an item to index 10
characters[10] = 'd';
characters.toReversed();
// ['d', undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, 'c', 'b', 'a']
```
As anticipated, unoccupied slots come as `undefined` values within the array.
## `toReversed()` behavior with array-like objects
Although `toReversed()` is specifically available on the `Array` prototype, it's also usable on objects resembling arrays.
An array-like object generally possesses a `length` property and possibly properties with integer index names. An instance of a string object serves as an illustration of an array-like object.
`toReversed()` begins by extracting the `length` property from the object it operates on. Subsequently, it iterates through the integer keys of the object, starting from the end `length - 1` and moving toward the beginning `0`.
During this iteration, it collects the values of these properties and appends them to a new array, which returns.
Let's put this concept into practice. Imagine you incorrectly attempt to use `toReversed()` on a string:
```javascript
const text = "Hello, Nigeria!"
// Attempting to call `toReversed` on the string
text.toReversed()
// Uncaught TypeError: text.toReversed is not a function
```
Despite a string being an array-like object, the above approach will not work.
It's not valid to invoke `string.toReversed()` because `toReversed()` isn't a defined function within the `string` prototype.
However, you can achieve the intended outcome using the `call()` method:
```javascript
const text = "Hello, Nigeria!"
// Using Array.prototype.toReversed.call(arrayLike)
Array.prototype.toReversed.call(text)
//
(15) ['!', 'a', 'i', 'r', 'e', 'g', 'i', 'N', ' ', ',', 'o', 'l', 'l', 'e', 'H']
```
Now, let's explore a different scenario involving a custom array-like object:
```javascript
// Exhibits a length property and an integer index property.
const customArray = {
length: 4,
2: "Item 2"
}
```
If this were a regular array, it would be sparse, signifying that it holds a length of four with a value at the second index.
When you employ `toReversed()` with this object:
```javascript
console.log(Array.prototype.toReversed.call(customArray))
// [undefined, 'Item 2', undefined, undefined]
```
The `toReversed()` method generates a reversed array without introducing sparsity. As expected, vacant slots are indicated by `undefined` values.
# The `toSorted()` method
The equivalent of the classic `.sort()` method is `.toSorted()`.
In contrast to `.sort()`, which changes the original array, `.toSorted()` maintains the original array intact. Let's illustrate this contrast using an essential sorting operation with `.sort()`:
```javascript
const scores = [85, 70, 92, 60, 78];
// Sort in ascending order
const sortedScores = scores.sort();
console.log(sortedScores);
// [60, 70, 78, 85, 92]
console.log(scores);
// [60, 70, 78, 85, 92]
```
As demonstrated above, `.sort()` modifies the array directly, resulting in a changed array. Now, let's compare this with the behavior of `.toSorted()`:
```javascript
const scores = [85, 70, 92, 60, 78];
// Sort in ascending order using .toSorted()
const sortedScores = scores.toSorted();
console.log(sortedScores);
// [60, 70, 78, 85, 92]
console.log(scores);
// [85, 70, 92, 60, 78]
```
The above example highlights that `.toSorted()` produces a fresh array with elements arranged in a sorted order while the original array remains unaltered.
It's worth mentioning that `.toSorted()` shares the same syntax as `.sort()`. For instance, you can define a custom sorting order using a function, as shown here, with `scores.toSorted(comparefunction)`:
```javascript
const scores = [85, 70, 92, 60, 78];
// Sort the array in descending order using .toSorted()
const descendingScores = scores.toSorted((a, b) => b - a);
console.log(descendingScores);
// [92, 85, 78, 70, 60]
```
In the example, `.toSorted()` sorts the array in descending order using a custom comparison function.
## Using `toSorted()` on sparse arrays
When empty slots arise, it converts them into `undefined` values in the resulting array. Essentially, it treats them as having an `undefined` value.
Notably, the `comparefunction` won't be invoked for these empty slots, ensuring they always appear at the end of the returned array.
Let's illustrate this with a different example involving an array that starts with an empty slot:
```javascript
// Observe the empty initial slot
const days = [, "Monday", "Tuesday", "Wednesday"];
console.log(days.toSorted());
// ['Monday', 'Tuesday', 'Wednesday', undefined]
```
This behavior remains consistent even when the initial value of the slot is explicitly `undefined`, as demonstrated below:
```javascript
const days = [undefined, "Monday", "Tuesday", "Wednesday"];
console.log(days.toSorted());
// ['Monday', 'Tuesday', 'Wednesday', undefined]
```
Furthermore, it's important to emphasize that empty slots (or slots with `undefined` values) will consistently be positioned at the end of the returned array, regardless of their original position.
Consider the following scenario:
```javascript
// An empty slot at index 2
const items = ["pen", "book", , "desk"];
console.log(items.toSorted());
// Appears last in the resulting array
// ['book', 'desk', 'pen', undefined]
// An 'undefined' value at index 2
const otherItems = ["pen", "book", undefined, "desk"];
console.log(otherItems.toSorted());
// Appears last in the resulting array
// ['book', 'desk', 'pen', undefined]
```
In both cases, whether it's an empty slot or a slot with an `undefined` value, the position of such entries remains consistent – they are always placed at the end of the returned array.
## `toSorted()` behavior with array-like objects
When the `toSorted()` method applies to objects, it initially examines the `length` property of the current object. Subsequently, it compiles the integer keys of the object, starting from the beginning and progressing to the end – that is, from `0` to `length - 1`. After arranging these keys in a sorted manner, it creates a new array containing the corresponding values.
For Example:
```javascript
// Contains a length property and integer index property.
const temperatureData = {
length: 6,
0: 25,
2: 30,
4: 22,
};
console.log(Array.prototype.toSorted.call(temperatureData));
// Result: [22, 25, 30, undefined, undefined, undefined]
```
In this scenario, the `toSorted()` method applies to an object representing temperature data.
The length property indicates the object's size, and integer keys (0, 2, and 4) represent different temperature values.
Upon applying `toSorted()`, the function processes these values and arranges them in sorted order, with `undefined` values appended for indices with no corresponding value.
The example above showcases how `toSorted()` operates on objects, extracting and sorting integer keys to create a new array of values.
# The `toSpliced(start, deleteCount, ...items)` method
The `.toSpliced()` method is the counterpart to the conventional `.splice()` method.
Like the other newly introduced methods we've discussed, invoking `.toSpliced()` won't result in changes to the array on which it's used – a contrast to the effects of `.splice()`.
The syntax for using `.toSpliced()` mirrors that of `.splice()`, as demonstrated below:
```javascript
.toSpliced(start)
.toSpliced(start, deleteCount)
.toSpliced(start, deleteCount, item1)
.toSpliced(start, deleteCount, item1, item2, itemN)
```
Let's contrast this with the traditional `.splice()` approach, which adds a new array item:
```javascript
const weekdays = ["Tuesday", "Wednesday", "Thursday", "Friday"];
// Inserting "Monday" at index 0, deleting 0 items
weekdays.splice(0, 0, "Monday");
console.log(weekdays);
// ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
```
The `.splice()` method introduces the new array item and alters the original array.
If you aim to produce a new array without modifying the original, `.toSpliced()` is the choice.
Let's take the previous example and reimagine it using `.toSpliced()`:
```javascript
const weekdays = ["Tuesday", "Wednesday", "Thursday", "Friday"];
// Adding "Monday" at index 0, with 0 items deleted
const updatedWeekdays = weekdays.toSpliced(0, 0, "Monday");
console.log(updatedWeekdays);
// ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
console.log(weekdays);
// ['Tuesday', 'Wednesday', 'Thursday', 'Friday']
```
Observe that `.toSpliced()` yields a fresh array while preserving the original unaltered. It's interesting to note the identical syntax shared by both `.toSpliced()` and `.splice().`
## Using `toSpliced(start, deleteCount, ...items)` on sparse arrays
`toSpliced()` ensures it always generates arrays without sparse elements.
Consequently, empty slots within the array will represent as `undefined.`
For example:
```javascript
const numbers = [1, , 3, , 5];
// Begin at index 1, deleting 1 item
console.log(numbers.toSpliced(1, 1));
// Result: [1, 3, undefined, 5]
```
In the example above, the array `numbers` has gaps due to the missing values at index `1` and `3`. Applying toSpliced() creates a new array that adheres to the principle of not having sparse elements. Thus, the gaps are filled with `undefined` values, leading to the outcome
`[1, 3, undefined, 5]`.
## `toSpliced(start, deleteCount, ...items)`behavior with array-like objects
When dealing with array-like objects, `toSpliced()` retrieves the length property of the current object, then retrieves the required integer keys, and finally assembles the result into a fresh array:
For example:
```javascript
const text = "Hello, World!"
// Starting at index 1, deleting 2 items, inserting the provided items
console.log(Array.prototype.toSpliced.call(text, 1, 2, 'e', 'a', 'r'));
// Result: ['e', 'a', 'r', 'l', 'd', '!', ' ', 'W', 'o', 'r', 'l', 'd']
```
# The `with(index, value)` method
The `.with()` method for arrays presents an intriguing feature. To begin, let's consider using bracket notation to alter the value of a particular array index:
Imagine having an array called `preferredFruits`:
```javascript
const preferredFruits = ["Apples", "Bananas", "Oranges"];
preferredFruits[1] = "Mangoes";
console.log(preferredFruits);
// Result: ['Apples', 'Mangoes', 'Oranges']
```
In this instance, the value at index 1 of the `preferredfruits` array has been changed from `Bananas` to `Mangoes` through bracket notation. This direct approach allows for the modification of specific elements within the array.
Now, contrast this with the `.with()` method. It accomplishes the same task of inserting an element at a specific index but doesn't modify the original array. Instead, it produces a new array with the specified index updated.
Let's reimagine the previous example using the `.with()` method:
```javascript
const preferredFruits = ["Apples", "Bananas", "Oranges"];
const updatedFruits = preferredFruits.with(1, "Mangoes");
console.log(updatedFruits);
// Result: ['Apples', 'Mangoes', 'Oranges']
console.log(preferredFruits);
// ['Apples', 'Bananas', 'Oranges']
```
In this revised example, `.with()` replaces an element at index 1. The method generates a new array named `updatedFruits`, reflecting the modification, while the original `preferredFruits` array remains unchanged.
## Using `with(index, value)` on sparse arrays
The `with()` method consistently generates arrays without sparse elements. As a result, any vacant slots within the array display as `undefined`:
Consider an example with an array named `numbers`:
```javascript
const numbers = [, 10, , 30, 40, , 60];
numbers.with(1, 3);
// Result: [10, 30, 40, undefined, undefined, undefined, 60]
```
In this case, the `with()` method is utilized with the `numbers` array. The method replaces elements starting from index `1` and extending to the following three positions.
The output is a new array where the gaps are filled with `undefined` values, as the method guarantees a complete array without any empty slots.
## `with(index, value)` behavior with array-like objects
Like other methods, the `with()` method examines the current object's length property. It then scans through each positive integer index (less than the length) within the object.
As it traverses these indices, it captures the corresponding property values and assigns them to the new array.
Let's delve into a distinct example to illustrate further:
Consider the sentence `I love programming`:
```javascript
const sentence = "I love programming";
// Change the value of the first character
console.log(Array.prototype.with.call(sentence, 0, "M"));
// Result: ['M', ' ', 'l', 'o', 'v', 'e', ' ', 'p', 'r', 'o', 'g', 'r', 'a', 'm', 'm', 'i', 'n', 'g']
```
# Conclusion
Embracing the continuous enhancements within the ECMAScript standard proves to be advantageous.
Utilizing the newly introduced functionalities, such as `toReversed`, `toSorted`, and `toSpliced`, enables creation of more expressive and concise JavaScript applications.
By incorporating these features, developers can enhance the readability and maintainability of their code, thus making the most of the evolving language capabilities.
# References
[ECMAScript 2023 (ES14): Four New Features](http://web.archive.org/web/20230426045402/https://www.showwcase.com/show/34770/ecmascript-2023-es14-four-new-features)
[A guide to the 4 new Array.prototype methods in JavaScript](https://blog.logrocket.com/guide-four-new-array-prototype-methods-javascript/)