考虑:
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) 返回数组。