JavaScript has come a long way in the past 10 years with brand new feature upgrades in each one.
Still remember when we created classes like this?
function Car(make, model) {
this.make = make;
this.model = model;
}
// And had to join strings like this
Car.prototype.drive = function() {
console.log("Vroom! This " + this.make +
" " + this.model + " is driving!");
};
Yeah, a lot has changed!
Let’s take a look at the 5 most significant features that arrived in ES14 (2023); and see the ones you missed.
1. toSorted()
Sweet syntactic sugar.
ES14’s toSorted()
method made it easier to sort an array and return a copy without mutation.
Instead of this:
const nums = [5, 2, 6, 3, 1, 7, 4];
const sorted = clone.sort();
console.log(sorted); // [1, 2, 3, 4, 5, 6, 7]
// ❌❌ Mutated
console.log(nums); // [1, 2, 3, 4, 5, 6, 7]
We now got to do this ✅:
const nums = [5, 2, 6, 3, 1, 7, 4];
// ✅ toSorted() prevents mutation
const sorted = nums.toSorted();
console.log(sorted); // [1, 2, 3, 4, 5, 6, 7]
console.log(nums); // [5, 2, 6, 3, 1, 7, 4]
toSorted()
takes a callback for controlling sorting behavior – ascending or descending, alphabetical or numeric. Just like sort()
.
2. Array find from last
Searching from the first item isn’t always ideal:
const tasks = [
{ date: '2017-03-05', name: '👟run a 5k' },
{ date: '2017-03-04', name: '🏋️lift 100kg' },
{ date: '2017-03-04', name: '🎶write a song' },
// 10 million records...
{ date: '2024-04-24', name: '🛏️finally sleep on time' },
{ date: '2024-04-24', name: '📝1h writing with no breaks' },
];
const found = tasks.find((item) => item.date === '2024-03-25');
const foundIndex = tasks.findIndex((item) => item.date === '2024-03-25');
console.log(found); // { value: '2024-03-25', name: 'do 1000 pushups' }
console.log(foundIndex); // 9,874,910
You can easily see that it’ll be much faster for me to search our gigantic list from the end instead of start.
const tasks = [
{ date: '2017-03-05', name: 'run a 5k' },
{ date: '2017-03-04', name: 'lift 100kg' },
{ date: '2017-03-04', name: 'write a song' },
// 10 million records...
{ date: '2024-04-24', name: 'finally sleep on time' },
{ date: '2024-04-24', name: '1h writing with no breaks' },
];
// ✅ Much faster
const found = tasks.findLast((item) => item.date === '2024-03-25');
const foundIndex = tasks.findLastIndex((item) => item.date === '2024-03-25');
console.log(found); // { value: '2024-03-25', name: 'do 1000 pushups' }
console.log(foundIndex); // 9,874,910
And they’re also times you MUST search from the end for your program work.
Like we want to find the last even number in a list of numbers, find
and findIndex
will be incredibly off.
const nums = [7, 14, 3, 8, 10, 9];
// ❌ gives 14, instead of 10
const lastEven = nums.find((value) => value % 2 === 0);
// ❌ gives 1, instead of 4
const lastEvenIndex = nums.findIndex((value) => value % 2 === 0);
console.log(lastEven); // 14
console.log(lastEvenIndex); // 1
And calling reverse()
won’t work either, even as slow as it would be:
const nums = [7, 14, 3, 8, 10, 9];
// ❌ Copying the entire array with the spread syntax before
// calling reverse()
const reversed = [...nums].reverse();
// correctly gives 10
const lastEven = reversed.find((value) => value % 2 === 0);
// ❌ gives 1, instead of 4
const reversedIndex = reversed.findIndex((value) => value % 2 === 0);
// Need to re-calculate to get original index
const lastEvenIndex = reversed.length - 1 - reversedIndex;
console.log(lastEven); // 10
console.log(reversedIndex); // 1
console.log(lastEvenIndex); // 4
So in cases like where the findLast()
and findLastIndex()
methods come in handy.
const nums = [7, 14, 3, 8, 10, 9];
// ✅ Search from end
const lastEven = nums.findLast((num) => num % 2 === 0);
// ✅ Maintain proper indexes
const lastEvenIndex = nums.findLastIndex((num) => num % 2 === 0);
console.log(lastEven); // 10
console.log(lastEvenIndex); // 4
This code is shorter and more readable. Most importantly, it produces the correct result.
3. toReversed()
Another new Array method to promote immutability and functional programming.
Before – with reverse()
❌:
const arr = [5, 4, 3, 2, 1];
const reversed = arr.reverse();
console.log(reversed); // [1, 2, 3, 4, 5]
// ❌ Original modified
console.log(arr); // [1, 2, 3, 4, 5]
Now – with toReversed()
✅:
const arr = [5, 4, 3, 2, 1];
const reversed = arr.toReversed();
console.log(reversed); // [1, 2, 3, 4, 5]
// ✅ No modification
console.log(arr); // [5, 4, 3, 2, 1]
I find these immutable methods awesome for constantly chaining methods over and over without worrying about the original variables:
// ✅ Results are independent of each other
const nums = [5, 2, 6, 3, 1, 7, 4];
const result = nums
.toSorted()
.toReversed()
.map((n) => n * 2)
.join();
console.log(result); // 14,12,10,8,6,4,2
const result2 = nums
.map((n) => 1 / n)
.toSorted()
.map((n) => n.toFixed(2))
.toReversed();
console.log(result2);
// [ '1.00', '0.50', '0.33', '0.25',
// '0.20', '0.17', '0.14' ]
4. toSpliced()
Lovers of functional programming will no doubt be pleased with all these new Array methods.
This is the immutable counterpart of .splice()
:
const colors = ['red🔴', 'purple🟣', 'orange🟠', 'yellow🟡'];
// Remove 2 items from index 1 and replace with 2 new items
const spliced = colors.toSpliced(1, 2, 'blue🔵', 'green🟢');
console.log(spliced); // [ 'red🔴', 'blue🔵', 'green🟢', 'yellow🟡' ]
// Original not modified
console.log(colors); // ['red🔴', 'purple🟣', 'orange🟠', 'yellow🟡'];
5. Array
with()
method
with()
is our way of quickly change an array element with no mutation whatsoever.
Instead of this usual way:
const arr = [5, 4, 7, 2, 1]
// Mutates array to change element
arr[2] = 3;
console.log(arr); // [5, 4, 3, 2, 1]
ES14 now let us do this:
const arr = [5, 4, 7, 2, 1];
const replaced = arr.with(2, 3);
console.log(replaced); // [5, 4, 3, 2, 1]
// Original not modified
console.log(arr); // [5, 4, 7, 2, 1]
Final thoughts
They were other features but ES14 was all about easier functional programming and built-in immutability.
With the rise of React we’ve seen declarative JavaScript explode in popularity; it’s only natural that more of them come baked into the language as sweet syntactic sugar.
Every Crazy Thing JavaScript Does
A captivating guide to the subtle caveats and lesser-known parts of JavaScript.