Array.prototype.map当应用于具有值的数组时,该函数按预期工作undefined:
const array = [undefined, undefined, undefined];
console.log(array.map(x => 'x')); // prints ["x", "x", "x"]Run Code Online (Sandbox Code Playgroud)
但是,当在map具有空槽的稀疏数组上使用时,它不会像前面的示例那样将它们映射到“x”。相反,它返回undefined值:
const array = [,,,];
console.log(array.map(x => 'x')); // prints [undefined, undefined, undefined]Run Code Online (Sandbox Code Playgroud)
即使我们有一个混合了空槽和实际值的数组,也只有后者被映射:
const array = [,'a',,'b',];
console.log(array.map(x => 'x')); // prints [undefined, "x", undefined, "x"]Run Code Online (Sandbox Code Playgroud)
相反,我注意到Array.prototype.join空槽上的工作:
const array = [,,,,];
console.log(array.join('x')); // prints "xxx"Run Code Online (Sandbox Code Playgroud)
为什么join将空槽视为有效元素,但map事实并非如此?
此外,在join 文档中,他们提到如果一个元素是undefined、null或empty array [],它会被转换为空字符串。他们没有提到空槽,但似乎他们也将它们转换为空字符串。
那么这是 MDN 文档中的问题吗?为什么不以join同样的方式忽略空槽map呢?这似乎是文档或实现中的问题join。
const array = [,,,];
console.log([...array].map(x => 'x'));Run Code Online (Sandbox Code Playgroud)
...如果您需要初始大小的结果数组,或者
const array = [,'a',,'b',]
console.log([...array].filter(Boolean).map(x => x+'x'));Run Code Online (Sandbox Code Playgroud)
...如果您需要跳过空槽
join尝试生成数组的序列化表示。map通过某种转换函数生成数组元素的投影。
使用map,可以说:“当您单步遍历数组时,如果遇到没有属性的索引,则在输出数组中类似地保留该属性未设置。” 对于所有现有属性,输出索引仍将与其输入索引相对应,并且在输入和输出中都会跳过缺失的属性。
对于join字符串输出,我们无法真正做到这一点。如果我们加入[,\'a\',,\'b\',], 的输出,a,,b,是表示这一点的最佳方式。跳过缺失属性的输出(即,a,b)将具有极大的误导性,它看起来是一个长度为 2 的数组,其元素位于索引0和 处1。
与 不同的是map,它可以生成具有各种存在或不存在属性的数组,但join它在渲染字符串输出时遇到了困难,它无法轻松地区分输出中缺失的属性与空的属性,而不会产生巨大的误导性结果。
为了完整起见,以下是 ECMAScript 指定的实际行为,其中函数循环输入数组(每个数组中k都有循环变量):
\n\n\n重复,当k < len时
\n\n
\n- 如果k > 0,则将R设置为R和sep的字符串连接。
\n- 设元素为 ? Get( O ,!ToString( k ))。
\n- 如果element未定义或null,则让next为空字符串;否则,接下来是?ToString(元素).
\n- 将R设置为R和next的字符串连接。
\n- 将k增加1。
\n
\n\n重复,当k < len时
\n\n
\n- 就让Pk吧!ToString( k ).
\n- 设kPresent为 ? HasProperty( O , Pk ).
\n- 如果kPresent为true,则\n
\n\n
\n- 令kValue为 ? 获取(O,Pk)。
\n- 让mappedValue为?调用(callbackfn,T,\xc2\xab kValue,k,O \xc2\xbb)。
\n- 履行 ?CreateDataPropertyOrThrow(A,Pk,mappedValue)。
\n- 将k增加1。
\n
即使您不知道如何阅读所有这些内容,也很容易看到其中map包括HasProperty第二个循环步骤中的检查。join明确地说“如果元素是undefinedor null,则让next为空字符串。” Get(O, ! ToString(k))是一个常见的属性查找,对于普通对象,undefined当属性不存在时会产生结果,因此“If element is undefined”情况适用。
值得注意的是,MDN 文档简化了其信息,以便专注于最常见的情况,而不是遵守严格的完整性。(我想说稀疏数组是一种不常见的情况。)特别是,他们说空数组将序列化为空字符串,这是事实。toString对于任何具有返回空字符串的函数的值来说,这通常都是正确的:
["foo", { toString: a=>""}, "bar"].join()\nRun Code Online (Sandbox Code Playgroud)\n这将产生输出foo,,bar。