我可以使用Array()
来创建一个带有固定数量未定义条目的数组。例如
Array(2); // [empty × 2]
但是,如果我去使用map方法,比如说在我的新数组上,条目仍然是未定义的:
Array(2).map( () => "foo"); // [empty × 2]
如果我复制数组,则映射确实起作用:
[...Array(2)].map( () => "foo"); // ["foo", "foo"]
为什么需要一个副本才能使用数组?
答案 0 :(得分:50)
使用Array(arrayLength)
创建数组时,您将have:
一个新的JavaScript数组,其length属性设置为该数字(注意:这意味着一个arrayLength空插槽数组,而不是具有实际未定义值的插槽)。
该数组实际上不包含任何值,甚至不包含undefined
值-它只是具有length
属性。
当您将具有length
属性的可迭代对象扩展到数组中时,spread语法将访问每个索引并在新数组中设置该索引处的值。例如:
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);
答案 1 :(得分:9)
原因是未分配数组元素。 See here说明的第一段。 ...回调仅对已分配了值(包括未定义)的数组索引进行调用。
考虑:
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
。
答案 2 :(得分:2)
正如@CertainPerformance所指出的那样,您的数组除了其length
之外没有任何其他属性,您可以使用以下行验证这一点:new Array(1).hasOwnProperty(0)
,该行返回false
。
从15.4.4.19 Array.prototype.map看,在 7.3 处,检查数组中是否存在 key 。
1..6。 [...]
7.重复,
而 k < len
让 Pk 是ToString( k )。
让 kPresent 是调用[[HasProperty]]的结果 O 的内部方法,参数为 Pk 。
让 kValue 是调用内部[[Get]]的结果 参数为 Pk 的 O 方法。
让 mappedValue 是调用内部[[Call]]的结果 callbackfn 的方法,其中 T 作为 this 包含 kValue , k 和 O 。
呼叫 A 的[[DefineOwnProperty]]内部方法, 参数 Pk ,属性描述符{[[Value]]: mappedValue , [[Writable]]: true ,[[Enumerable]]: true , [[可配置]]: true }和 false 。
增加 k 乘1。
答案 3 :(得分:0)
正如已经指出的那样,Array(2)
将仅创建两个无法映射的空插槽的数组。
就some
和every
而言,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);