[英]Why does Array.prototype.map ignore empty slots in a sparse array whereas Array.prototype.join does not?
The Array.prototype.map
function works as expected when applied on an array with undefined
values: Array.prototype.map
函数在应用于具有undefined
值的数组时按预期工作:
const array = [undefined, undefined, undefined]; console.log(array.map(x => 'x')); // prints ["x", "x", "x"]
However, when using map
on a sparse array with empty slots, it does not map them to 'x' as in the previous example.但是,在具有空槽的稀疏数组上使用
map
时,它不会像前面的示例那样将它们映射到 'x'。 Instead, it returns undefined
values:相反,它返回
undefined
值:
const array = [,,,]; console.log(array.map(x => 'x')); // prints [undefined, undefined, undefined]
Even if we have an array with a mix of empty slots and actual values, only the latter ones are mapped:即使我们有一个混合了空槽和实际值的数组,也只有后者被映射:
const array = [,'a',,'b',]; console.log(array.map(x => 'x')); // prints [undefined, "x", undefined, "x"]
In contrast, I noticed Array.prototype.join
works on empty slots:相比之下,我注意到
Array.prototype.join
适用于空插槽:
const array = [,,,,]; console.log(array.join('x')); // prints "xxx"
Why does join
treat empty slots as valid elements, but map
does not?为什么
join
将空槽视为有效元素,而map
则不然?
Furthermore, in the join documentation , they mention that if an element is undefined
, null
or an empty array []
, it is converted to an empty string.此外,在join 文档中,他们提到如果元素是
undefined
、 null
或empty array []
,则将其转换为空字符串。 They do not mention empty slots, but it seems they are also converting them to an empty string.他们没有提到空插槽,但似乎他们也在将它们转换为空字符串。
Is it then a problem in the MDN documentation?那么它是 MDN 文档中的问题吗? And why not having
join
also ignore empty slots in the same way map
does?为什么不让
join
也像map
一样忽略空槽呢? It seems to be either a problem in the documentation or in the implementation of join
.这似乎是文档中的问题或
join
的实现中的问题。
join
attempts to produce a serialized representation of the array. join
尝试生成数组的序列化表示。 map
produces a projection of the elements of an array through some transforming function. map
通过一些转换函数生成数组元素的投影。
With map
, it is possible to say: "As you step through the array, if you encounter an index that has no property, leave that property similarly unset in the output array."使用
map
,可以说:“当您逐步遍历数组时,如果遇到没有属性的索引,请在输出数组中类似地保留该属性未设置。” For all existing properties, output indices will still correspond to their input indices, and the missing properties are skipped in both the input and output.对于所有现有属性,输出索引仍将对应于它们的输入索引,并且在输入和输出中都会跳过缺失的属性。
With join
's string output, we can't really do this.使用
join
的字符串输出,我们无法真正做到这一点。 If we join [,'a',,'b',]
, an output of ,a,,b,
is the best way to represent this.如果我们加入
[,'a',,'b',]
,输出,a,,b,
是表示这一点的最佳方式。 An output that skips missing properties -- ie, a,b
-- would be hugely misleading, appearing to be a length-2 array with elements at indices 0
and 1
.跳过缺失属性(即
a,b
的输出会产生极大的误导,看起来是一个长度为 2 的数组,其元素在索引0
和1
。
Unlike map
, which can produce an array with variously present or absent properties, join
is stuck rendering a string output, which cannot readily distinguish missing vs. empty properties in its output without hugely misleading results.与可以生成具有各种存在或不存在属性的数组的
map
不同, join
被卡在呈现字符串输出中,它无法轻易区分其输出中的缺失属性和空属性,而不会产生极大的误导性结果。
For completeness, here are the actual ECMAScript-specified behaviors where the function loops through the input array (in each, k
is the loop variable):为完整起见,以下是 ECMAScript 指定的实际行为,其中函数循环遍历输入数组(在每个数组中,
k
是循环变量):
Array.prototype.join Array.prototype.join
Repeat, while k < len
重复,而k < len
- If k > 0, set R to the string-concatenation of R and sep .
如果k > 0,则将R设置为R和sep的字符串连接。
- Let element be ?
让元素是? Get( O , ! ToString( k )).
Get( O , !ToString( k ))。
- If element is undefined or null , let next be the empty String;
如果element是undefined或null ,让next为空字符串; otherwise, let next be ?
否则,让下一步是? ToString( element ).
ToString(元素)。
- Set R to the string-concatenation of R and next .
将R设置为R和next的字符串连接。
- Increase k by 1.
将k增加 1。
Array.prototype.map 数组.prototype.map
Repeat, while k < len
重复,而k < len
- Let Pk be !
让Pk吧! ToString( k ).
ToString( k )。
- Let kPresent be ?
让kPresent是? HasProperty( O , Pk ).
HasProperty( O , Pk )。
- If kPresent is true , then
如果kPresent为true ,则
- Let kValue be ?
让kValue为 ? Get( O , Pk ).
获取( O , Pk )。
- Let mappedValue be ?
让mappedValue是? Call( callbackfn , T , « kValue , k , O »).
调用( callbackfn , T , « kValue , k , O »)。
- Perform ?
履行 ? CreateDataPropertyOrThrow( A , Pk , mappedValue ).
CreateDataPropertyOrThrow( A , Pk , mappingValue )。
- Increase k by 1.
将k增加 1。
Even if you don't know how to read all of this, it's plain to see that map
includes a HasProperty
check in the second loop step.即使您不知道如何阅读所有这些内容,也很容易看到该
map
在第二个循环步骤中包含HasProperty
检查。 join
explicitly says "If element is undefined
or null
, let next be the empty String." join
明确表示“如果 element 是undefined
或null
,让下一个是空字符串。” Get(O, ! ToString(k))
is a usual property lookup which, for ordinary objects, yields undefined
when a property is absent, so the "If element is undefined
" case applies. Get(O, ! ToString(k))
是一种常见的属性查找,对于普通对象,当属性不存在时,它会产生undefined
,因此“如果元素undefined
”的情况适用。
It's worth noting that the MDN documentation simplifies its information in order to focus on the most common cases instead of adhering to rigorous completeness.值得注意的是,MDN 文档简化了其信息,以专注于最常见的情况,而不是坚持严格的完整性。 (I would say that sparse arrays are an uncommon case.) In particular, they say that an empty array will serialize to the empty string, which is true.
(我会说稀疏数组是一种不常见的情况。)特别是,他们说空数组将序列化为空字符串,这是真的。 This is true in general for any value that has a
toString
function which returns an empty string:对于任何具有返回空字符串的
toString
函数的值,这通常是正确的:
["foo", { toString: a=>""}, "bar"].join()
This will produce the output foo,,bar
.这将产生输出
foo,,bar
。
const array = [,,,]; console.log([...array].map(x => 'x'));
...if you need resulting array of initial size, or ...如果您需要初始大小的结果数组,或
const array = [,'a',,'b',] console.log([...array].filter(Boolean).map(x => x+'x'));
...if you need to skip empty slots ...如果您需要跳过空槽
This is how JS handles sparse arrays.这就是 JS 处理稀疏数组的方式。 Consider:
考虑:
> let a = [,,,,,]
> a
[ <5 empty items> ]
> let b = [undefined,undefined,undefined,undefined,undefined]
> b
[ undefined, undefined, undefined, undefined, undefined ]
> let c = [,,'x',,]
> c
[ <2 empty items>, 'x', <1 empty item> ]
Empty items do not actually take up any space (beyond some overhead).空项目实际上不占用任何空间(超出一些开销)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.