So here’s the method that I came up with:
(The above composes all of the items before the item that’s to be removed together with all the items after it into a single array.) This can end up becoming quite costly as slice and concat operations aren’t terribly fast. We can circumvent this by doing a single slice operation and doing a push instead. This is where the trickiness comes in.
Now, we know that the front of the array is never going to change (even if the “front” contains no elements, there’s no need for us to do an additional slice operation). Thus, making that assumption, we can do this trick:
array.length = i - 1; array.push.apply( array, slicedResults );
Here’s what that does:
- Modifying the length of an array effectively removes all results from the end of it. If length or elegance isn’t an issue for you, you could modify the above method to check for calls like .remove(-2) and optimize it to be a single operation: this.length += from;
- Thus, since we’ve already removed all the dangling items from the array (along with the items that we wanted to remove, to begin with) we need to merge the sliced items back onto the original array.
- An array’s push method is capable of taking any number of arguments (meaning statements like this are valid: array.push(1,2,3,4)). Thus, if we call that method using apply and put in the sliced array all of the resulting items will be “concatenated” onto the end of the array, in one, single super-fast operation.
Fun Fact: I use this technique to construct the array-like results of DOM elements in a jQuery object.
The only other tricky bit of the function is the following snippet:
(to || from) + 1 || this.length
“(to || from) + 1” is, effectively, saying “start the slice just after where the remove operation ended”. Thus, if you did .remove(1,2) we’d need to start the slice at the index of 3. However, if we just did .remove(1) we’d start the slice at 2. We get to cheat a little bit since a to of 0 is irrelevant and can be ignored.
Now, the second part, “|| this.length” is just a tricky way of saying “if the end index was -1, make sure that we don’t start the slice operation at 0, and instead start it after the end of the array”. This issue arrives because doing .slice(0) returns the full array. Thus, in order to simulate our intended result (an empty array) we just pass in an index that’ll always return an empty result (this.length).