29

考虑:

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]
4

5 回答 5

24

数组构造函数创建一个具有给定长度的数组。它不会创建密钥。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) {显示回调函数不处理不存在的键。

于 2012-06-29T17:20:41.300 回答
6

来自MDN

回调仅针对已分配值的数组索引调用;对于已被删除或从未被赋值的索引,它不会被调用。

对于数组a,您已经实例化了一个长度为 3 的数组,但尚未分配任何值。map 函数找不到具有赋值的元素,因此它不会生成新数组。

对于数组b,您已经实例化了一个包含 3 个元素的数组,每个元素的值都是undefined。map 函数找到 3 个具有赋值的元素,并在新数组中返回 '0' 作为每个元素的新值。

于 2012-06-29T17:24:33.817 回答
5

map仅迭代现有属性,而不是空索引。

因此,如果你想让它工作,你必须先填充数组。

有多种方法可以做到这一点,例如:

于 2016-07-23T03:44:35.717 回答
4

a是一个没有元素的空数组,所以 map 函数产生一个没有元素的空数组(根据规范,只有当 [[HasProperty]] 为真时,map 才会产生结果。) b是一个由三个元素组成的数组,所以 map 产生一个三个要素。

于 2012-06-29T17:21:41.040 回答
2

构造数组可枚举但为空

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为活动函数对象,否则newTargetNewTarget

4 )让protoGetPrototypeFromConstructor(newTarget, "%ArrayPrototype%")

5) ReturnIfAbrupt(proto)

6) 设数组为ArrayCreate(0, proto)

7) 如果 Type( len) 不是 Number,那么

defineStatusa ) 让CreateDataProperty(array, "0", len)

b) 断言:defineStatus是真的。

c)intLen设为 1。

8) 否则,a)intLen设为 ToUint32( len)。b) 如果intLenlen,则抛出 RangeError 异常。

9) setStatus设为 Set(array, "length", intLen, true)。

10) Assert:setStatus不是突然完成。

11) 返回数组。

于 2019-01-31T22:52:13.750 回答