Array(len)初始值设定项中的未定义值

时间:2012-06-29 17:14:45

标签: javascript arrays undefined

考虑:

var a = Array(3);
var b = [undefined,undefined,undefined];

a.mapb.map产生不同结果的原因是什么?

a.map(function(){  return 0;  });  //produces -> [undefined,undefined,undefined]
b.map(function(){  return 0;  });  //produces -> [0,0,0]

5 个答案:

答案 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只迭代现有属性,而不是空索引。

因此,如果您希望它工作,您必须先填充数组。

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

    在ES6中引入的
  • .fill()

    
    
    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;
    &#13;
    &#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为活动函数对象,否则让newTargetNewTarget

     

4)假设protoGetPrototypeFromConstructor(newTarget, "%ArrayPrototype%")

     

5)ReturnIfAbrupt(proto)

     

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

     

7)如果Type(len)不是Number,则

     

a)假设defineStatusCreateDataProperty(array, "0", len)

     

b)断言:defineStatus是正确的。

     

c)假设intLen为1。

     

8)其他, a)假设intLen为ToUint32(len)。 b)如果intLenlen,则引发RangeError异常。

     

9)让   setStatus被设置(数组,“ length”,intLen,true)。

     

10)断言:setStatus不是突然完成。

     

11)返回数组。