Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I be sure that array.slice() will always work the same as array.slice(0)?

Tags:

javascript

I've always used the .slice() method with no arguments to make a copy of a JavaScript Array. This works fine in every browser and JavaScript environment I've tried: it is treated the same as .slice(0).

It's just a matter of style, but to me omitting the start argument entirely makes it more clear that we aren't taking any special sub-slice of the array but want a copy of the whole thing.

However, both MDN and MSDN say that the first argument to array.slice() is required. Only the second argument is optional. Other online sources such as TutorialsPoint and W3Schools say the same thing. (No, I'm not recommending W3Schools! Just pointing out that they agree with MDN and MSDN on this issue.)

Have I just been lucky with this? Could there be a browser or other JavaScript environment where array.slice() doesn't work?

like image 569
Michael Geary Avatar asked Jan 12 '23 16:01

Michael Geary


1 Answers

All of these online references are mistaken.

At least if we're talking about standards-complant browsers and runtimes.

The ECMA-262 standard requires any conforming implementation to treat array.slice() identically to array.slice(0).

Here is how we know this.

First we look at Section 15.4.4.10, "Array.prototype.slice (start, end)":

The slice method takes two arguments, start and end, and returns an array containing the elements of the array from element start up to, but not including, element end (or through the end of the array if end is undefined)…

What is this? There's not even any mention of end being optional. Are both start and end required?

Yes, they are. But we need to look elsewhere to understand what this means.

Section 15, "Standard Built-in ECMAScript Objects" says (in the fourth paragraph):

Unless otherwise specified in the description of a particular function, if a function or constructor described in this clause is given fewer arguments than the function is specified to require, the function or constructor shall behave exactly as if it had been given sufficient additional arguments, each such argument being the undefined value.

And this is consistent with how other methods are specified. We know, for example, that the compare function argument to array.sort() is optional, but Section 15.4.4.11 "Array.prototype.sort (comparefn)" doesn't say anything about the comparefn argument being optional. It just describes what to do when comparefn is undefined or not.

So now we know that array.slice() is interpreted as array.slice(undefined,undefined). Continuing, then, with Section 15.4.4.10, we find the relevant step:

5 . Let relativeStart be ToInteger(start).

ToInteger is described in Section 9.4, where the first two steps are relevant:

1 . Let number be the result of calling ToNumber on the input argument.
2 . If number is NaN, return +0.

ToNumber is found in Section 9.3, where the first entry in the table says that when its Argument Type is Undefined, the result is NaN.

So, the missing first argument to array.slice() is treated as undefined and that value is passed into ToNumber, which returns NaN. This causes ToInteger to return 0 (or +0 as they call it here), and that's the value that array.slice() uses.

Therefore, array.slice() is the same as array.slice(0). If an implementation doesn't treat it that way, it doesn't conform to the ECMA-262 standard.

Of course, that's the standard, and then there is the real world.

If we follow this same analysis for the second argument to .slice(), we'll come to the conclusion that all of these should work the same (among other similar variations):

array.slice()
array.slice( 0 )
array.slice( undefined )
array.slice( 0, undefined )
array.slice( undefined, undefined )

However, as @Pumbaa80 points out in a comment, the last two versions do not work in IE8 (nor in IE7)!

But at least the simple array.slice() case I was concerned about does work in these old browsers, and should continue to work in any browser or runtime that follows the standard.

like image 130
Michael Geary Avatar answered Jan 16 '23 01:01

Michael Geary