考虑:
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 函数找不到具有指定值的元素,因此它不会生成新数组。
对于 array 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 函数生成没有元素的空数组(根据规范,map 仅在 [[HasProperty]] 为真时才生成结果。) b
是一个包含三个元素的数组,因此 map 生成一个数组三个要素。
Array(len)
创建一个数组并相应地设置其长度,但只有它的长度是“可枚举的”,而不是包含的值。所以,你不能阵图Array(100).map(/* nope */)
-它不是一个“真正的数组”然而,它是尽管有正确的长度就是空的。
仅对已分配值(包括未定义)的数组索引调用回调。,
将array
不包含任何值; 甚至不undefined
对于数组中缺失的元素(即从未设置、已删除或从未赋值的索引),不会调用它。
要填充数组,您需要以某种方式对其进行迭代……例如:[...Array(100)]
或Array.from(Array(100))
我想这个初始化的目的是优化内存分配……数组中没有任何东西。MDN 说“空arrayLength
对象”可能会产生误导,因为尝试访问任何“空项目”只会返回 undefined ……但我们知道它们不是真的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,则a)设
defineStatus
是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) 返回数组。