at() (ES2022) reads from the end with a negative index, where arr[-1] is just a missing property. findLast() and findLastIndex() (ES2023) search right to left. The ES2023 change array by copy methods give each mutator a copying twin with the same arguments, as immutable React 7,897 or Redux 3,824 state requires. Object.groupBy() and Map.groupBy() (ES2024) split a list into buckets.
| Mutates in place | Returns a copy instead |
|---|---|
| arr.sort(compareFn) | arr.toSorted(compareFn) |
| arr.reverse() | arr.toReversed() |
| arr.splice(start, count, ...items) | arr.toSpliced(start, count, ...items) |
| arr[index] = value | arr.with(index, value) |
const scores = Object.freeze([72, 95, 58, 88]); // frozen: sort() would throw
console.log(scores.toSorted((m, n) => n - m), scores.toReversed());
console.log(scores.toSpliced(1, 2, 60), scores.with(-1, 90), scores);
console.log(scores.at(-1), scores.findLast((s) => s < 80));
const people = [{ name: 'Ana', age: 17 }, { name: 'Ben', age: 34 }, { name: 'Cy', age: 71 }];
const band = ({ age }) => (age < 18 ? 'minor' : age < 65 ? 'adult' : 'senior');
const groups = Object.groupBy(people, band);
console.log(groups.adult, Object.keys(groups), Object.getPrototypeOf(groups));
console.log(Map.groupBy(people, (p) => p.age >= 18).get(false));[ 95, 88, 72, 58 ] [ 88, 58, 95, 72 ]
[ 72, 60, 88 ] [ 72, 95, 58, 90 ] [ 72, 95, 58, 88 ]
88 58
[ { name: 'Ben', age: 34 } ] [ 'minor', 'adult', 'senior' ] null
[ { name: 'Ana', age: 17 } ]Object.groupBy() returns a null-prototype object, so groups.toString is not inherited and a group named constructor is safe; keys become strings. Map.groupBy() keeps booleans or objects as keys. The copying methods return a plain Array, and with() throws RangeError for an index outside the array. Typed arrays (Typed Arrays and Binary Data) gain toSorted(), toReversed() and with() but not toSpliced().