我可以使用Array()
具有固定数量的未定义条目的数组。例如
Array(2); // [empty × 2]
但是如果我去使用 map 方法,比如说,在我的新数组上,条目仍然是未定义的:
Array(2).map( () => "foo"); // [empty × 2]
如果我复制数组,则 map 确实有效:
[...Array(2)].map( () => "foo"); // ["foo", "foo"]
为什么我需要一个副本才能使用数组?
我可以使用Array()
具有固定数量的未定义条目的数组。例如
Array(2); // [empty × 2]
但是如果我去使用 map 方法,比如说,在我的新数组上,条目仍然是未定义的:
Array(2).map( () => "foo"); // [empty × 2]
如果我复制数组,则 map 确实有效:
[...Array(2)].map( () => "foo"); // ["foo", "foo"]
为什么我需要一个副本才能使用数组?
当您使用Array(arrayLength)
创建数组时,您将拥有:
一个新的 JavaScript 数组,其 length 属性设置为该数字(注意:这意味着 arrayLength 空插槽的数组,而不是具有实际未定义值的插槽)。
该数组实际上不包含任何值,甚至不包含undefined
值——它只有一个length
属性。
当您将具有属性的可迭代对象扩展length
到数组中时,扩展语法访问每个索引并在新数组中设置该索引处的值。例如:
const arr1 = [];
arr1.length = 4;
// arr1 does not actually have any index properties:
console.log('1' in arr1);
const arr2 = [...arr1];
console.log(arr2);
console.log('2' in arr2);
并且.map
仅映射属性实际存在于您正在映射的数组中的属性/值。
使用数组构造函数令人困惑。我建议使用Array.from
,当从头开始创建数组时 - 您可以向它传递一个具有length
属性的对象,以及一个映射函数:
const arr = Array.from(
{ length: 2 },
() => 'foo'
);
console.log(arr);
原因是数组元素未赋值。请参阅此处描述的第一段。...回调仅针对已分配值(包括未定义)的数组索引调用。
考虑:
var array1 = Array(2);
array1[0] = undefined;
// pass a function to map
const map1 = array1.map(x => x * 2);
console.log(array1);
console.log(map1);
输出:
Array [undefined, undefined]
Array [NaN, undefined]
当数组被打印时,它的每个元素都会被询问。第一个已分配undefined
,另一个默认为undefined
。
映射操作调用第一个元素的映射操作,因为它已被定义(通过赋值)。它不会为第二个参数调用映射操作,而只是传递undefined
.
正如@CertainPerformance 所指出的,您的数组除了它的 之外没有任何属性length
,您可以使用以下行验证:new Array(1).hasOwnProperty(0)
,它返回false
.
查看15.4.4.19 Array.prototype.map可以看到,在7.3 处,检查数组中是否存在键。
1..6. [...]
7. 重复,而k < len
令 Pk为 ToString( k )。
令 kPresent是使用参数Pk调用O的 [[HasProperty]] 内部方法的结果。
令 kValue是使用参数Pk调用O的 [[Get]] 内部方法的结果。
让 mappingValue是调用callbackfn的 [[Call]] 内部方法的结果,其中T作为this 值和包含kValue、k和 O 的参数列表。
调用[[DefineOwnProperty]的内部方法甲带参数PK,属性描述符{[[价值]]:mappedValue,[可写]]:真,[可枚举]]:真,[[配置]]:真} ,和假的。
将k增加 1。
正如已经指出的那样,Array(2)
只会创建一个由两个无法映射的空槽组成的数组。
就some
andevery
而言,Array(2)
确实是一个空数组:
Array(2).some(() => 1 > 0); //=> false
Array(2).every(() => 1 < 0); //=> true
然而,这个空槽数组可以以某种方式“迭代”:
[].join(','); //=> ''
Array(2).join(','); //=> ','
JSON.stringify([]) //=> '[]'
JSON.stringify(Array(2)) //=> '[null,null]'
因此,我们可以利用这些知识想出有趣且有点讽刺的方法来在此类“空”数组上使用 ES5 数组函数。
你自己想出了那个:
[...Array(2)].map(foo);
来自@charlietfl 的建议的变体:
Array(2).fill().map(foo);
我个人推荐这个:
Array.from(Array(2)).map(foo);
有点老派:
Array.apply(null, Array(2)).map(foo);
这个是相当冗长的:
Array(2).join(',').split(',').map(foo);