考虑:
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]
考虑:
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]
数组构造函数创建一个具有给定长度的数组。它不会创建密钥。Array.prototype.map
的回调函数只对列表中的元素执行。
也就是说,所有与键(整数)关联的值 0 ≤ i < length。
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) {
显示回调函数不处理不存在的键。
来自MDN:
回调仅针对已分配值的数组索引调用;对于已被删除或从未被赋值的索引,它不会被调用。
对于数组a
,您已经实例化了一个长度为 3 的数组,但尚未分配任何值。map 函数找不到具有赋值的元素,因此它不会生成新数组。
对于数组b
,您已经实例化了一个包含 3 个元素的数组,每个元素的值都是undefined
。map 函数找到 3 个具有赋值的元素,并在新数组中返回 '0' 作为每个元素的新值。
map
仅迭代现有属性,而不是空索引。
因此,如果你想让它工作,你必须先填充数组。
有多种方法可以做到这一点,例如:
.fill()
, 在 ES6 中引入
console.log(new Array(3).fill().map(function(){ return 0; }));
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; }));
等等。
a
是一个没有元素的空数组,所以 map 函数产生一个没有元素的空数组(根据规范,只有当 [[HasProperty]] 为真时,map 才会产生结果。) b
是一个由三个元素组成的数组,所以 map 产生一个三个要素。
Array(len)
创建一个数组并相应地设置它的长度,但只有它的长度是“可枚举的”,而不是包含的值。所以,你不能映射数组Array(100).map(/* nope */)
——它还不是一个“真正的数组” ,尽管长度正确,它实际上是空的。
回调仅对分配了包括 undefined 在内的值的数组索引调用。,
array
不包含任何值;甚至不undefined
对于数组的缺失元素(即从未设置、已删除或从未分配值的索引),不会调用它。
要填充数组,您需要以某种方式对其进行迭代......例如:[...Array(100)]
或Array.from(Array(100))
我想这个初始化的目的是优化内存分配......数组中实际上没有任何东西。MDN 说“空arrayLength
对象”可能会误导,因为尝试访问任何“空项目”只会返回未定义……但我们知道它们不是真的,undefined
因为map
失败了,因此我们可以确认它是一个真正的空数组。
此示例不寻求镜像规范,而是说明为什么array
返回的 fromArray
还不能被迭代
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;
}
值得指出的是,尽管undefined
在生成器 value 属性中提供了一个值,但它不会将其识别为一个值,因此数组是空的。
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,那么
defineStatus
a ) 让CreateDataProperty(array, "0", len)
。b) 断言:
defineStatus
是真的。c)
intLen
设为 1。8) 否则,a)
intLen
设为 ToUint32(len
)。b) 如果intLen
≠len
,则抛出 RangeError 异常。9)
setStatus
设为 Set(array, "length", intLen, true)。10) Assert:
setStatus
不是突然完成。11) 返回数组。