When it comes to working with JavaScript arrays, one of the most common mistakes is confusing slice with splice. They have similar names and similar functionalities, but using the wrong one can cause cause bugs which can be hard to track down. In the sections below, we'll review each Array method individually, the discuss the source of confusion between the two methods and what kinds of bugs can arise when the wrong method is used.
Slice
The slice method will return an array containing a portion of the items in the original array without changing the original array itself. There are three ways we can call this method:
- ar.slice(): the method will return a new array with the same elements as the original array.
- ar.slice(startInd): this will return a new array with the same elements as the original array starting from index startInd.
- ar.slice(startInd, endInd): this will return a new array with the same elements as the original array starting from index startInd up to the index endNum, not including the item at index endNum itself.
A few examples of how this method can be used are given below:
A few notes on how this method behaves with certain arguments:
- Negative numbers are used: when negative numbers are used, the method will treat those as offsets from the end position instead of normal indices.
- The first argument is not smaller than the second argument: the method will return an empty array.
- The first argument is larger than the array size: the method will return an empty array.
Splice
The splice method will remove elements from the array it is called on and return a new array which contains all of the removed elements. If additional arguments are given, it will also add new elements to the original array. There are three ways we can call this method:
- ar.splice(startInd): this will remove all elements from the original array starting from startInd and return an array containing those removed elements.
- ar.splice(startInd, numDelete): this will remove "numDelete" number of elements from the original array starting from startInd and return an array containing those removed elements.
- ar.splice(startInd, numDelete, ...insertValues): this will remove "numDelete" number of elements from the original array starting from startInd, insert all arguments provided after numDelete into the array at startInd, and return an array containing the elements that were removed. Note: the dots in ...insertValues means we can specify any number of additional arguments corresponding to the individual new elements we want to add to the array.
A few notes on how this method behaves with certain arguments:
- Negative numbers are used: when negative numbers are used, the method will treat those as offsets from the end position instead of normal indices.
- The first argument is not smaller than the second argument: the method will return an empty array and the original array will retain all of its elements.
- The first argument is larger than the array size and no other arguments are given: the method will return an empty array and the original array will retain all of its elements.
- No arguments are given: the method will return an empty array and the original array will retain all of its elements.
The three main ways this differs from slice:
- This method changes the array it is called on.
- The second argument is a count instead of an end index.
- This method also allows you to add elements to the original array.
The Source of Confusion
The reasons these methods are often confused with one another are as follows:
- The names are spelled similarly and are even pronounced similarly: s(p)lice
- Both take a start index as its first argument.
- Both return an array of items starting at the start index specified in the first argument.
The last point above is very important to note, as it will appear at first glance that the functionality is working properly even when the wrong method is being used, so it may go unnoticed for a long period of time.
Mismatch Bugs
When slice is used instead of splice, the array returned may be the same as if splice were used, especially when only one argument is provided, but unlike splice, slice will not modify the original array. Therefore, any elements which should have been removed will remain. This may lead to situations such as:
- Infinite loop: if we are continuously iterating over an array while elements exist inside of it, slice will not remove those elements and the iteration will never stop.
- Memory leak: if items which are no longer needed are kept in arrays, a memory leak may occur. Depending on the size of the elements and number of elements which should have been removed, but were not because slice was used instead of splice, the memory leak may cause performance issues.
- Security breach: if data should be removed based on some conditions related to user account access, user preferences, or similar, slice will not remove that data. This might, in certain situations, lead to a security breach, access breach, or something similar.
When splice is used instead of slice, the array returned may be the same as if splice were used, especially when only one argument is provided, but unlike slice, splice will modify the original array. Therefore, any elements which are returned by the method will no longer exist in the original array. This may lead to situations such as:
- Missing items in subsequent array access: if we need to use one array as a source of truth, then make copies of some elements, once splice is used (instead of slice), the original array will no longer be a valid source of truth; thus, subsequent uses will lead to missing data and related bugs.
- Missing items in recursive calls: if the slice method is used in a context of a recursive function, the intent may have been to copy part of an array without modifying the original. If so, then modifying the original may cause the recursive implementation to fail to traverse ceratain paths / scenarios.
Bugs which are caused by these scenarios, especially when splice is used instead of slice, can be difficult to track down because the bugs are caused by side effects. If we were to debug by checking what values are present / available at each line of code, we might miss the root cause because the array returned by the method might be the same whether slice or splice is used. To find the bug, we would need to do a deeper analysis during the debug session.