4

我一直使用.slice()不带参数的方法来制作 JavaScript 的副本Array。这在我尝试过的每个浏览器和 JavaScript 环境中都可以正常工作:它被视为与.slice(0).

这只是风格问题,但对我来说,完全省略start参数更清楚地表明我们没有采用数组的任何特殊子切片,而是想要整个事物的副本。

但是,MDNMSDN都说 to 的第一个参数array.slice()required。只有第二个参数是可选的。其他在线资源,例如TutorialsPointW3Schools也说了同样的话。(不,我不推荐 W3Schools!只是指出他们在这个问题上同意 MDN 和 MSDN。)

我只是幸运吗?是否有浏览器或其他 JavaScript 环境array.slice()不起作用?

4

1 回答 1

9

所有这些在线参考都是错误的。

至少如果我们谈论的是符合标准的浏览器和运行时。

ECMA-262 标准要求任何符合要求的实现array.slice()array.slice(0).

这是我们如何知道这一点的。

首先我们看第 15.4.4.10 节,“Array.prototype.slice (start, end)”:

slice方法接受两个参数startend,并返回一个数组,该数组包含从元素start到但不包括元素end的数组元素(如果end是,则通过数组的末尾undefined)...

这是什么?甚至没有提到end是可选的。开始结束都需要吗?

对,他们是。但我们需要看看别处才能理解这意味着什么。

第 15 节,“标准内置 ECMAScript 对象”说(在第四段中):

除非在特定函数的描述中另有规定,如果本节中描述的函数或构造函数的参数少于指定的函数所需的参数,则函数或构造函数的行为应与已给予足够的附加参数完全相同,每个这样的论点就是undefined价值。

这与指定其他方法的方式一致。例如,我们知道 compare 函数的参数array.sort()是可选的,但第 15.4.4.11 节“Array.prototype.sort (comparefn)”没有说明comparefn参数是可选的。它只是描述了comparefn是否存在时要做什么undefined

所以现在我们知道它array.slice()被解释为array.slice(undefined,undefined)。然后继续第 15.4.4.10 节,我们找到相关步骤:

5. 让relativeStart为 ToInteger( start )。

ToInteger第 9.4 节中进行了描述,其中前两个步骤是相关的:

1. 令number为对输入参数调用 ToNumber 的结果。
2. 如果 number 是NaN,则返回+0

ToNumber第 9.3 节中找到,其中表中的第一个条目表示当其参数​​类型为未定义时,结果为NaN

因此,缺少的第一个参数array.slice()被视为undefined并将该值传递给 ToNumber,后者返回NaN. 这会导致 ToInteger 返回0(或者+0他们在这里称之为),这就是array.slice()使用的值。

因此,array.slice()与 相同array.slice(0)。如果实现不以这种方式对待它,则它不符合 ECMA-262 标准。

当然,这是标准,然后才是现实世界。

如果我们对 的第二个参数进行相同的分析.slice(),我们将得出结论,所有这些都应该工作相同(以及其他类似的变体):

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

然而,正如@Pumbaa80 在评论中指出的那样,最后两个版本在 IE8 中不起作用(在 IE7 中也不适用)!

但至少array.slice()我担心的简单案例在这些旧浏览器中确实有效,并且应该继续在任何遵循标准的浏览器或运行时中工作。

于 2013-08-12T06:35:25.857 回答