考虑:
var a = Array(3);
var b = [undefined,undefined,undefined];
a.map
和b.map
产生不同结果的原因是什么?
a.map(function(){ return 0; }); //produces -> [undefined,undefined,undefined]
b.map(function(){ return 0; }); //produces -> [0,0,0]
答案 0 :(得分:23)
数组构造函数创建一个具有给定长度的数组。它确实不创建密钥。 Array.prototype.map
的回调函数仅对列表中的元素执行
也就是说,与键相关的所有值(整数)0≤ i < 长度
Array(3)
没有键,因此永远不会触发.map
的回调。 [void 0, void 0, void 0]
有三个键,为其执行回调函数。
Array(3).hasOwnProperty(0); // false
[void 0, void 0, void 0].hasOwnProperty(0); // true
MDN提到了规范及其polyfill。在第47行,if (k in O) {
显示回调函数不处理不存在的键。
答案 1 :(得分:6)
来自MDN:
仅对已分配的数组的索引调用回调 值;对于已删除的索引或其中的索引,不会调用它 从未被赋予价值观。
对于数组a
,您已实例化了一个长度为3但尚未分配任何值的数组。 map函数找不到具有赋值的元素,因此它不会生成新数组。
对于数组b
,您实例化了一个包含3个元素的数组,每个元素的值为undefined
。 map函数查找具有指定值的3个元素,并在新数组中为每个元素返回“0”。
答案 2 :(得分:4)
a
是一个没有元素的空数组,因此map函数生成没有元素的空数组(根据规范,map仅在[[HasProperty]]为真时生成结果。) b
是一个包含三个元素的数组,因此map会生成一个包含三个元素的数组。
答案 3 :(得分:4)
map
只迭代现有属性,而不是空索引。
因此,如果您希望它工作,您必须先填充数组。
有多种方法可以做到这一点,例如:
console.log(new Array(3).fill().map(function(){ return 0; }));

使用concat
:
apply
var arr = [].concat.apply([], new Array(3));
console.log(arr.map(function(){ return 0; }));

旧的for
循环。
var arr = new Array(3);
for(var i=0; i<arr.length; ++i) arr[i] = 1; /* whatever */
console.log(arr.map(function(){ return 0; }));
&#13;
使用Most efficient way to create a zero filled JavaScript array?
等等。
答案 4 :(得分:0)
Array(len)
创建一个数组并相应地设置其长度,但是只有其长度是“可枚举的”,而不是包含的值。因此,您无法映射数组Array(100).map(/* nope */)
-它不是“真实数组” ,尽管长度正确,但实际上为空。
回调仅对数组的索引进行了调用,这些索引的赋值包括未定义。,
array
不包含任何值;甚至没有undefined
不会为缺少数组的元素(即从未设置,已删除或从未分配值的索引)调用。
要填充数组,您需要以某种方式对其进行迭代……例如:[...Array(100)]
或Array.from(Array(100))
我想这种初始化的目的是优化内存分配……数组中实际上没有任何东西。 MDN表示“空arrayLength
个对象”可能会误导,因为尝试访问任何“空项目”只会返回未定义的…。但是我们知道它们并不是真正的undefined
,因为map
会失败,因此我们可以确认它是一个真正的空数组。
此示例并非试图反映规范,而是说明为什么仍无法迭代从array
返回的Array
function * (length) {
const arr = [];
Object.defineProperty(arr, 'length', { value: length });
// Equivalent, but invokes assignment trap and mutates array:
// arr.length = length;
Object.defineProperty(arr, Symbol.iterator, {
value() {
let i = 0;
return {
next() {
return {
value: undefined, // (Not omitted for illustration)
done: i++ == length
};
}
}
}
})
return arr;
}
值得指出的是,尽管在generator value属性中提供了undefined
值,但它不能将其识别为值,因此数组为空。
Array(len)
规范https://www.ecma-international.org/ecma-262/6.0/#sec-array-len
Array(len)仅当Array时,此描述才适用 构造函数只用一个参数调用。
1)令
numberOfArgs
为传递给此函数的参数数目 打电话。2)断言:
numberOfArgs
= 1。3)如果NewTarget为
undefined
,则让newTarget
为活动函数对象,否则让newTarget
为NewTarget
。4)假设
proto
为GetPrototypeFromConstructor(newTarget, "%ArrayPrototype%")
。5)
ReturnIfAbrupt(proto)
。6)令数组为
ArrayCreate(0, proto)
。7)如果Type(
len
)不是Number,则a)假设
defineStatus
为CreateDataProperty(array, "0", len)
。b)断言:
defineStatus
是正确的。c)假设
intLen
为1。8)其他, a)假设
intLen
为ToUint32(len
)。 b)如果intLen
≠len
,则引发RangeError异常。9)让
setStatus
被设置(数组,“ length”,intLen,true)。10)断言:
setStatus
不是突然完成。11)返回数组。