Hey everyone! It’s time for another edition of Boring JavaScript, this time on the .slice() method. We’ll take a look at both the Array.slice() method and the String.slice() method.
It’s Not a Pie Slice
Since both Array.slice() and String.slice() work the same way, let’s take a look at the generic .slice() method.
.slice() will copy the the array or the string starting at an index or character position up to (but not including) another index or character position. The original array or string remains intact, and a new array or string is created.
It’s important to note that .slice() returns a copy. I know – the word ‘slice’ means to cut up. After all, when you take a ‘slice’ or pie, you remove that slice. But not so with the .slice() method. If you wish to actually take a piece of the Array, you need to use the .splice() method. Interestingly, there is no .splice() method for strings.
Slicing Up the Data
How does the .slice() method work? Although the following uses Arrays as an example, it works on Strings the exact same way. For Arrays, you specify index numbers. For Strings, you specify character position numbers.
The .slice() method takes two optional arguments:
- startIndex. The starting element index for – well – starting the slice. If this number is omitted, 0 is assumed. If this number is negative, the starting index will be offset from the end of the array.
- endingIndex. The array element on which to stop. Important! The last array element is not included in the slice, as we’ll see in the examples below. If this number is omitted, the length of the array is assumed. If this number is negative, then the ending element is the offset from the end. The ending index can never be smaller or equal to the starting index.
Let’s see how it works. Suppose you had this array:
const animals = [
"Cat", "Dog", "Horse", "Cow", "Coyote", "Road Runner", "Dolphin", "Whale", "Lizard"
];
Now let’s try some different numbers in the .slice() method.
Starting Index Only
If only the startIndex is specified, it will take the elements from the start all the way to the end of the array.
const slice = animals.slice(3);
console.log(slice);
// prints ["Cow", "Coyote", "Road Runner", "Dolphin", "Whale", "Lizard"]
Why “cow” and not “Horse”? Remember, array indexes begin a 0, not 1. Asking for a startIndex of three means we are taking the fourth element.
Both Indexes
How about specifying both?
const slice = animals.slice(3, 6);
console.log(slice);
// prints ["Cow", "Coyote", "Road Runner"]
Notice that “Dolphin” was not included, even though it was the sixth index. When using .slice(), the ending index specified is not included within the slice.
Negative Starting Index
How about a negative starting index?
const slice = animals.slice(-2);
console.log(slice);
// prints ["Whale", "Lizard"]
Specifying a negative number for the staring index will start the slice as an offset from the length. The length of our array is 9, so the starting index will be 7, which is “Whale”. Without an ending index, it will take the rest of the array
Both Negative Numbers
What if both numbers are negative?
const slice = animals.slice(-3, -1)
console.log(slice);
// prints ["Dolphin", "Whale"]
Let’s break down what happened here. The starting index of -3 means we take the length of 9, subtract 3, and that becomes our starting index (6). The ending index of -1 means we take the length of 9, subtract 1, and that becomes our ending index (8). Since the ending index is never included, that means we only copy index numbers 6 and 7, or “Dolphin” and “Whale”.
Starting Index Negative, Ending Index Positive
What happens when the starting index is negative, and the ending index is positive?
const slice = animals.slice(-3, 2);
console.log(slice);
// prints []
Ok, so what happened? Nothing! That is because we want to start at index 6 (length of 9 minus offset of 3), and the ending index is 2. Ending indexes cannot be smaller than starting indexes, so nothing is done. Also note that no error is thrown, so be careful.
Nothing specified
How about if none of the arguments are specified?
const slice = animals.slice();
console.log(slice);
// prints ["Cat", "Dog", "Horse", "Cow", "Coyote", "Road Runner", "Dolphin", "Whale", "Lizard"]
It copies the entire array! Why? The starting index defaults to 0, and the ending index defaults to the length of the array. Meaning we take all elements from Index 0 to Index 8 – which is the entire array.
One Warning on Arrays
This applies to Arrays, not Strings. The copy that is made is a shallow copy. What is that? JavaScript has nine data types (as of 10/21/2020). Six of them are primitives, two are structural, and one is null (which is a special primitive). Primitives are String, Number, Boolean, BigInt, undefined, null, and Symbol. Structurals are Object and Function
A shallow copy will copy the primitives as-is. For example, if the element of the array contains a String, a physical copy of the string is made and given to the new array. If that element in the new array changes, nothing changes in the old array. Which is correct since a copy was made.
However, for structurals, a shallow copy will copy the reference of the array. What is a reference? In memory, JavaScript will create an object in memory. When a it is added to our original array, what is stored in the element is the object’s reference – a fancy way of saying “The physical copy can be found at Memory Address xxxxxxx”. When the .slice() method ‘copies’ the object, it doesn’t make a new, physical copy of the object. Instead, it copies the reference to that object.
Now both arrays contain the object reference. Which means if you change the value of a property of that object in the new array, it will also change in the old array.
Want to prove it? Try this and see what you get:
const oldArray = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8},
{a: 9, b: 10}
];
// get the 2nd and 3rd elements of the array
const newArray = oldArray.slice(2, 4);
// print out the "a" property 2nd element of each array
console.log(`Old 'a': ${oldArray[2].a}`);
console.log(`New 'a': ${newArray[2].a}`);
// change the new array
newArray[2].a = 700;
// print them again
console.log(`Old 'a': ${oldArray[2].a}`);
console.log(`New 'a': ${newArray[2].a}`);
So be careful when working with Arrays that contain structural variables.
Video
As always, we have a video that explains the above. Check it out, and make sure you subscribe to our YouTube channel!
Categories: Boring JavaScript Javascript
thevirtuoid
Web Tinkerer. No, not like Tinkerbell.
Creator of the game Virtuoid. Boring JavaScript. Visit us at thevirtuoid.com
Leave a Reply