JavaScript array methods 1/3 - altering arrays
The Array prototype in modern JavaScript contains many useful methods which every developer should know. However, some of them were introduced in the more recent ECMAScript. So if you don't keep up with the newest standards or you're just a beginner - it is a good time to learn something new. I'm also going to show you some tricks and trivia about these methods.
Table of contents
- How to add new items to an array?
- How to concat/merge arrays?
- Removing elements from the array
- Creating a string from an array - joining all elements into one string
- Creating an array from a string - splitting strings
- How to reverse an array?
- How to add new elements to the beginning of an array?
- How to sort an array in JavaScript?
- How to get first/last/any n elements from an array?
- How to flatten arrays?
- How to copy elements within an array?
Before you read
If you're an absolute beginner before reading this article you can check my brief introduction to JavaScript arrays where I discussed this construct in short.
How to add new items to an array?
push()! One of the most common operations that we can do on arrays. It simply adds new elements to the array.
const array = ["🐒", "🐬", "🐅"];
array.push("🐓");
console.dir(array) // Output: ["🐒", "🐬", "🐅", "🐓"]
push() will automatically extend the size of the array and add our new element at the end. We can push() more than one element at once:
const array = ["🐒", "🐬", "🐅"];
array.push("🐓", "🐉", "🐄");
console.dir(array) // Output: ["🐒", "🐬", "🐅", "🐓", "🐉", "🐄"]
It's also worth noting that push() returns the new length of the array.
const array = ["🐒", "🐬", "🐅"];
console.dir(array.push("🐉")); // Output: 4
console.dir(array); // Output: ["🐒", "🐬", "🐅", "🐉"]
Sometimes we may need to manually extend an array and add elements at certain indexes.
const array = [];
array[2] = "🐬";
console.dir(array); // Output: [undefined, undefined, "🐬"]
array[0] = "🐅";
array[1] = "🐉";
console.dir(array); // Output: ["🐅", "🐉", "🐬"]
In this example, we create an empty array. The next line extends its size to n+1 and adds 🐬 as the last value.
Thanks to the console.dir() in the third line you can see that there are some undefined values in this array. As I said in my brief introduction to JavaScript arrays, when you're extending the length of an array, JavaScript creates new elements with undefined values to meet the new size.
This method also works on existing arrays:
const array = ["🐅", "🐬"];
array[4] = "🐄";
console.dir(array); // Output: ["🐅", "🐬", undefined, undefined, "🐄"]
How to concat/merge arrays?
One of the possibilities is to use concat():
const array1 = ["🐒", "🐬", "🐅"];
const array2 = ["🐓", "🐉"];
const result = array1.concat(array2);
console.dir(result); // Output: ["🐒", "🐬", "🐅", "🐓", "🐉"]
It merges two or more arrays and returns the new array. Here's an example on three arrays:
const array1 = ["🐒", "🐬", "🐅"];
const array2 = ["🐓", "🐉"];
const array3 = ["🐎", "🐄"];
const result = array1.concat(array2, array3);
console.dir(result); // Output: ["🐒", "🐬", "🐅", "🐓", "🐉", "🐎", "🐄"]
But what if I want to merge one array INTO another array without the need to assign a third variable? ES2015 introduced a so-called destructuring assignment which in combination with push() can do it!
const array1 = ["🐒", "🐬", "🐅"];
const array2 = ["🐓", "🐉"];
array1.push(...array2);
console.dir(array1); // Output: ["🐒", "🐬", "🐅", "🐓", "🐉"]
Ta dam! Now we have all of the elements of the second array in our first array.
Using destructuring we can achieve a similar behavior to concat(). We just need to destruct the merged arrays into another array.
const array1 = ["🐒", "🐬", "🐅"];
const array2 = ["🐓", "🐉"];
const array3 = ["🐎", "🐄"];
const result = [...array1, ...array2, ...array3];
console.dir(result);
Removing elements from the array
How to remove the last element from the array?
It's as simple as calling the pop() function on the array.
const array = ["🐅", "🐬", "🐄"];
array.pop();
console.dir(array); // Output: ["🐅", "🐬"]
pop() has also a useful property because it returns the removed element!
const array = ["🐅", "🐬", "🐄"];
const lastElement = array.pop();
console.dir(lastElement); // Output: "🐄"
How to remove the first element from the array?
Here in handy comes shift(). Similar to pop() it also returns the element being removed.
const array = ["🐅", "🐬", "🐄"];
const firstElement = array.shift();
console.dir(firstElement); // Output: "🐅"
console.dir(array); // Output: ["🐬", "🐄"]
How to remove elements from the array on a specific index?
To remove a specific element we can use the delete operator.
const array = ["🐅", "🐬", "🐄"];
delete array[1];
console.dir(array); // Output: ["🐅", undefined, "🐄"]
It removes the element completely - the array now does not have an element with index 1. The interesting part of this is the fact, that we are still left with an array with a length of 3. If you want to leave the element and don't want it to have value just set it to undefined. Example:
const array = ["🐅", "🐬", "🐄"];
delete array[1];
console.dir(array.length); // Output: 3
console.dir(1 in array); // Output: false
console.dir(array); // Output: ["🐅", undefined, "🐄"]
array[1] = '🐬';
array[1] = undefined;
console.dir(array.length); // Output: 3
console.dir(1 in array); // Output: true
console.dir(array); // Output: ["🐅", undefined, "🐄"]
But what when we want to remove the element AND shorten the array? For this case, we can use splice().
const array = ["🐅", "🐬", "🐄"];
array.splice(1, 1);
console.dir(array); // Output: ["🐅", "🐄"]
The first argument of splice() is the startIndex, it sets the place where we want to start "cutting" our array. The second argument determines the length of the "cut". In 0ut case we only want to delete "🐬" so we just start "cutting" on index 1 and we want to remove just one element. Here is another example of removing more elements.
const array = ["🐅", "🐬", "🐄", "🐒", "🐓", "🐉"];
array.splice(2, 3);
console.dir(array); // Output: ["🐅", "🐬", "🐉"]
Now our "cut" has started on "🐄" and we wanted to remove three elements starting from that place.
With splice, we can also fill the gap of the removed elements by passing more arguments.
const array = ["🐅", "🐬", "🐄", "🐒", "🐓", "🐉"];
array.splice(2, 2, "🐖", "🦙");
console.dir(array); // Output: ["🐅", "🐬", "🐖", "🦙", "🐓", "🐉"]
or using destructuring, we can fill the gap with another array.
const array = ["🐅", "🐬", "🐄", "🐒", "🐓", "🐉"];
const fillArray = ["🐖", "🦙"];
array.splice(2, 2, ...fillArray);
console.dir(array); // Output: ["🐅", "🐬", "🐖", "🦙", "🐓", "🐉"]
Now let's compare all three methods and see the results!
const array = ["🐅", "🐬", "🐄"];
delete array[1];
console.dir(array.length); // Output: 3
console.dir(1 in array); // Output: false
console.dir(array); // Output: ["🐅", undefined, "🐄"]
array[1] = "🐬";
array[1] = undefined;
console.dir(array.length); // Output: 3
console.dir(1 in array); // Output: true
console.dir(array); // Output: ["🐅", undefined, "🐄"]
array[1] = "🐬";
array.splice(1,1);
console.dir(array.length); // Output: 2
console.dir(1 in array); // Output: true
console.dir(array); // Output: ["🐅", "🐄"]
Reassuming:
- delete removes the element but does not affect the array's size.
- setting an element to undefined does not remove it completely nor affects the array's size.
- splice() removes the element and affects the array's size.
Creating a string from an array - joining all elements into one string
Sometimes we need to create one string from all of the elements of the array, we can do it by using join().
const array = ["🐅", "🐬", "🐄", "🐒", "🐓", "🐉"];
const result = array.join();
console.dir(result); // Output: "🐅,🐬,🐄,🐒,🐓,🐉"
We can also specify the separator by passing it as the first argument.
const array = ["🐅", "🐬", "🐄", "🐒", "🐓", "🐉"];
const result = array.join(' | ');
console.dir(result); // Output: "🐅 | 🐬 | 🐄 | 🐒 | 🐓 | 🐉"
Creating an array from a string - splitting strings
We can achieve this by calling split() on our string. I know that split() is not a part of the Array prototype, but I thought that I should mention it when I'm talking about its counterpart - join().
const string = "🐅,🐬,🐄,🐒,🐓,🐉";
const result = string.split();
console.dir(result); // Output: ["🐅", "🐬", "🐄", "🐒", "🐓", "🐉"]
The default separator for split() is "," but we can change it to whatever we want.
const string = "🐅|🐬|🐄|🐒|🐓|🐉";
const result = string.split("|");
console.dir(result); // Output: ["🐅", "🐬", "🐄", "🐒", "🐓", "🐉"]
How to reverse an array?
JavaScript also has a method for this - and (how surprising...) it's named... reverse().
const array = ["🐅", "🐬", "🐄"];
const result = array.reverse();
console.dir(result); // Output: ["🐄", "🐬", "🐅"]
But there is one problem with this method. It's mutating our original array. Well, it is only a problem if you want to preserve the original array.
const array = ["🐅", "🐬", "🐄"];
const result = array.reverse();
console.dir(result); // Output: ["🐄", "🐬", "🐅"]
console.dir(array); // Output: ["🐄", "🐬", "🐅"]
What can we do to solve this issue? Well... just call concat() or slice() without any arguments.
const array = ["🐅", "🐬", "🐄"];
const result = array.concat().reverse();
console.dir(result); // Output: ["🐄", "🐬", "🐅"]
console.dir(array); // Output: ["🐅", "🐬", "🐄"]
NOTE. This works because concat() and slice() are returning a copy of the array - not a reference. By using reverse() after them we're only altering the copy.
Or (a cleaner solution) using our best friend, the hero we all needed but didn't deserve him, destructuring assignment.
const array = ["🐅", "🐬", "🐄"];
const result = [...array].reverse();
console.dir(result); // Output: ["🐄", "🐬", "🐅"]
console.dir(array); // Output: ["🐅", "🐬", "🐄"]
NOTE. Here we are just destructuring our array into another array, which is going to be reversed. So it's basically also calling reverse() on a copy.
We can also implement our own reverse function (this is only for absolute geeks).
Just kidding, we're not going to reinvent the wheel. I mean, you can, but... I'm too busy and we have to cover some more methods. However, these guys have time to do this, and you can check their thread for some funky solutions.
How to add new elements to the beginning of an array?
If JavaScript methods were people, push() and shift() would be a couple with a kid named unshift(). unshift() like push() will add new elements to the array but at the beginning.
const array = ["🐅", "🐬", "🐄"];
array.unshift("🐉", "🐓");
console.dir(array); // Output: ["🐉", "🐓", "🐅", "🐬", "🐄"]
And like push() it also accepts more than one element.
const array1 = ["🐅", "🐬", "🐄"];
const array2 = ["🐎", "🐄"];
array1.unshift(...array1);
console.dir(array1); // Output: ["🐉", "🐓", "🐅", "🐬", "🐄"]
Also, we can use destructuring to merge an array to the beginning of another.
Also similarly to push(), unshift() returns the new length of the array.
const array = ["🐒", "🐬", "🐅"];
console.dir(array.unshift("🐓")); // Output: 4
console.dir(array); // Output: ["🐓", "🐒", "🐬", "🐅"]
How to sort an array in JavaScript?
Sorting in JS is achieved with the sort() method. It utilizes an in-place algorithm so it doesn't copy the array, it alters the original.
const array = ["🐅", "🐬", "🐄", "🐒", "🐓", "🐉"];
array.sort();
console.dir(array); // Output: ["🐄", "🐅", "🐉", "🐒", "🐓", "🐬"]
If we want to keep the original we can do the same trick that we have done with reverse().
const array = ["🐅", "🐬", "🐄", "🐒", "🐓", "🐉"];
const result = array.slice().sort();
console.dir(array); // Output: ["🐅", "🐬", "🐄", "🐒", "🐓", "🐉"]
console.dir(result); // Output: ["🐄", "🐅", "🐉", "🐒", "🐓", "🐬"]
const array = ["🐅", "🐬", "🐄", "🐒", "🐓", "🐉"];
const result = [...array].sort();
console.dir(array); // Output: ["🐅", "🐬", "🐄", "🐒", "🐓", "🐉"]
console.dir(result); // Output: ["🐄", "🐅", "🐉", "🐒", "🐓", "🐬"]
NOTE. Emojis are just unicode characters and every emoji has it's unique code. For example 🐄 is U+1F404 and 🐉 is U+1F409. The algorithm is going to sort by this codes.
By default, this method sorts the elements using an ascending order - from lower to higher. If we want to sort in descending order we can write our own compare function (more on that in a moment) or just reverse() the sorted array (as it's more performant).
const array = ["🐅", "🐬", "🐄", "🐒", "🐓", "🐉"];
array.sort().reverse();
console.dir(array); // Output: ["🐬", "🐓", "🐒", "🐉", "🐅", "🐄"]
The default behavior of the sort() method causes also a very interesting problem, let's try to sort an array consisting of only numbers.
const array = [3, 45, 12, 1, 78, 369];
array.sort();
console.dir(array); // Output: [1, 12, 3, 369, 45, 78]
It provides us with one conclusion.
This is because by default sort is converting the elements to strings and comparing them in UTF-16. So when comparing words like "water" and "fire", "fire" comes first but when converting numbers to strings like 100 and 5 we end up with "100" coming before "5". To solve this we need to provide our own compare function as the first argument.
const array = [3, 45, 12, 1, 78, 369];
array.sort((first, second) => first - second);
console.dir(array); // Output: [1, 3, 12, 45, 78, 369]
Ah, much better.
NOTE. We usefirst - second
rather thanfirst > second
because it's more performant.
The problem with sorting number arrays is not our only concern. If you're French, Polish, German, Czech, Spanish or a citizen of another country whose native language has some letters with diacritics and you want to compare some local strings... well your life is not easy then. Here's hows sort() is working with accent letters.
const array = ["turkuć podjadek", "konik polny", "komar", "mucha", "ćma"];
array.sort();
console.dir(array); // Output: ["komar", "konik polny", "mucha", "turkuć podjadek", "ćma"]
This example is using some Polish insect names. The words with an accent are just put at the end. For example "ćma" should be first but it's last. To fix this we need to provide our own compare function again.
const array = ["turkuć podjadek", "konik polny", "komar", "mucha", "ćma"];
array.sort((first, second) => first.localeCompare(second));
console.dir(array); // Output: ["ćma", "komar", "konik polny", "mucha", "turkuć podjadek"]
Now it's working. localeCompare() checks if the reference string comes after or before the string given.
How to get first/last/any n elements from an array?
slice() is the solution you're looking for. It accepts two arguments, the start index and the end index, both are optional, but when we provide neither of them - nothing happens. Here are some useful snippets.
Get the first 3 elements of an array
const array = ["🐄", "🐅", "🐉", "🐒", "🐓", "🐬"];
const result = array.slice(0, 3);
console.dir(result); // Output: ["🐄", "🐅", "🐉"]
Get the last element of an array
const array = ["🐄", "🐅", "🐉", "🐒", "🐓", "🐬"];
const result = array.slice(-1);
console.dir(result); // Output: ["🐬"]
Get the second half of an array
const array = ["🐄", "🐅", "🐉", "🐒", "🐓", "🐬"];
const result = array.slice(array.length / 2);
console.dir(result); // Output: ["🐒", "🐓", "🐬"]
Get the first half of an array
const array = ["🐄", "🐅", "🐉", "🐒", "🐓", "🐬"];
const result = array.slice(0, array.length / 2);
console.dir(result); // Output: ["🐄", "🐅", "🐉"]
Get elements after the fourth element
const array = ["🐄", "🐅", "🐉", "🐒", "🐓", "🐬"];
const result = array.slice(4);
console.dir(result); // Output: ["🐓", "🐬"]
Get a slice of the array
const array = ["🐄", "🐅", "🐉", "🐒", "🐓", "🐬"];
const result = array.slice(2, 4);
console.dir(result); // Output: ["🐉", "🐒"]
As you can see, slice() can do many things.
How to flatten arrays?
Flattening means reducing the dimensions of an array. For example, if we got a two-dimensional array we can reduce it to only one dimension using flat().
const array = [["🐓", "🐄"], ["🐅", "🐒"]];
const result = array.flat();
console.dir(result); // Output: ["🐓", "🐄", "🐅", "🐒"]
Flattening doesn't affect the original array. It's copying its values.
By default flat() is going to flatten only one dimension. If you need to flatten a three (or more) dimensional array to just one dimension you have to provide the depth argument.
const array = [["🐓", "🐄"], ["🐅", ["🐒", "🐒"]]];
const result = array.flat(2);
console.dir(result); // Output: ["🐓", "🐄", "🐅", "🐒", "🐒"]
How to copy elements within an array?
Sometimes you want to copy an element from one position to another. For this, you can use copyWithin(). Like slice() this method has many possible use cases.
Copy first two elements to the last two elements
const array = ["🐉", "🐒", "🐓", "🐬", "🐄", "🐅"];
array.copyWithin(-2);
console.dir(array); // Output: ["🐉", "🐒", "🐓", "🐬", "🐉", "🐒"]
Replacing one value with another
const array = ["🐉", "🐒", "🐓", "🐬", "🐄", "🐅"];
array.copyWithin(2, 0, 1);
console.dir(array); // Output: ["🐉", "🐒", "🐉", "🐬", "🐄", "🐅"]
Here we replaced the 🐓 on index 2, with the piece that goes from index 0 to index 1, which is the 🐉. By changing the second argument to 2 we would also affect the 🐬, basically inserting the 🐉 and 🐒 on the positions where 🐓 and 🐬 were.
const array = ["🐉", "🐒", "🐓", "🐬", "🐄", "🐅"];
array.copyWithin(2, 0, 2);
console.dir(array); // Output: ["🐉", "🐒", "🐉", "🐒", "🐄", "🐅"]
For now - that's all. We've discussed all methods from the Array prototype that are used to alter arrays. This article series is going to be divided into 3 parts, the next part will deal with array iterators and looping through them, and the third would be about searching elements in arrays.