【问题标题】:forEach on a 'new Array' isn't doing what I expect“新数组”上的 forEach 没有达到我的预期
【发布时间】:2014-04-24 23:19:20
【问题描述】:

我只是在学习如何使用 JS 高阶函数(map、forEach、reduce 等),并陷入了混乱。我正在尝试编写一个简单的“范围”函数,但似乎无法填充我的输出数组。这是目标:

range(1, 4) // [1, 2, 3, 4]

我明白了:

[undefined × 4]

这是我的代码:

 function range(num1, num2) {
      var rangeArr = new Array((num2 + 1) - num1);
      return rangeArr.map(function(e, i, arr) {return arr[i] = num1 + i});
    }

我在这里缺少什么?据我所知,这个问题似乎与我使用“新阵列”的方式有关,但除此之外我迷路了。

哦,这才是真正让我困惑的部分。这工作正常:

function bleck() {
    var blah = [1, 2, 3, 4];
    var x = 'wtf';
    return blah.map(function(e, i, arr) {return arr[i] = x})
}

["wtf", "wtf", "wtf", "wtf"]

谢谢!!

【问题讨论】:

  • 不要认为你需要 "(num2 + 1) - num1)",因为 javascript 使用动态数组。
  • @Serdnad 这不是必需的,但它确实构造了一个该长度的空数组:Array(4) = [undefined x 4]
  • 注意使用与您的问题无关的.map():在您的回调中不需要return arr[i] = num1 + i,您可以直接说return num1 + i;。在arr 中设置值是没有意义的——它与rangeArr 是同一个数组——因为map 构造了一个新数组,这就是你从range() 函数返回的内容。
  • @Serdnad 你的意思是我可以简单地声明一个空数组吗?
  • @i_made_that 好吧,你可以。 Javascript 使用动态数组,因此它会在需要时增长。当然,你牺牲了一点性能,但有时它更方便,如果你不确定你需要多大的阵列,并且不想从一个庞大的阵列开始补偿。正如 cincodenada 所澄清的那样,没有必要。

标签: javascript arrays higher-order-functions


【解决方案1】:

forEach 方法迭代数组的索引。有趣的是,当您通过new Array(n) 创建一个新数组时,它根本没有索引。相反,它只是设置其.length 属性。

> var a = new Array(3);
> console.info(a)
[]
> console.info([undefined, undefined, undefined])
[undefined, undefined, undefined]

MDN 描述了forEach,并具体说明:

forEach 为每个元素执行一次提供的回调 具有赋值的数组。 不为具有 已被删除或省略

这是一种巧妙的技术,可以获取一个包含空但现有索引的数组。

var a = Array.apply(null, Array(3));

这是有效的,因为.apply 将省略的元素“扩展”为适当的参数,结果最终类似于Array(undefined, undefined, undefined)

【讨论】:

  • 非常酷,像魅力一样工作!!!将在 t-minus 4 分钟内接受您的答案,而且还在继续;)
  • 出于好奇,知道为什么要一个没有索引的数组吗?这不是违背了目的吗?
  • @i_made_that:我真的想不出它的用例。在我看来,这只是 JavaScript 标准 API 的另一个向后兼容的藤壶。 :]
【解决方案2】:

数组定义了 4 个整体,每个都未定义。

Map 不会遍历未定义的整体,它会跳过它们。

回调仅针对已分配的数组索引调用 价值观;它不会为未定义的索引调用,那些 已被删除或从未被赋值。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

【讨论】:

    【解决方案3】:

    当您创建new Array(x) 时,它会创建一个所谓的稀疏数组,其行为可能会有所不同,如您所见,如果您刚刚设置,某些浏览器会显示[undefined x 20,"foo", undefined x 5]一个值,我相信它不会迭代这些值。

    【讨论】:

    • 不确定我是否完全遵循。你的意思是如果我在var rangeArr 声明下面添加了这个:rangeArr[0] = num1
    【解决方案4】:

    问题在于map 不会迭代未定义的条目 (*)。

    我建议改用for 循环:

    var rangeArr = new Array((num2 + 1) - num1);
    for(var i=0; i<=num2-num1; ++i)
        rangeArr[i] = num1 + i;
    return rangeArr;
    

    (*) 未定义的条目 我的意思是rangeArr.hasOwnProperty(i) === false,不要与rangeArr[i] === void 0 混淆。

    【讨论】:

    • [undefined, undefined, undefined].map() 实际上会迭代
    • @CristiMihai 我的意思是这种类型的未定义:[,,,].map()
    • 我知道 .map() 不应该遍历从未被赋值的索引,但是为什么 OP 的代码会返回一个包含四个未定义元素的数组和一个 .length 4 个?
    • @nnnnnn 因为返回的数组是使用new Array(len) 创建的(参见spec),其中len 是初始数组的长度。
    • 啊。那么.map() 将始终返回一个与调用它的数组长度相同的数组,即使它可能不会为某些元素调用回调?
    猜你喜欢
    • 2021-10-15
    • 2016-09-05
    • 1970-01-01
    • 1970-01-01
    • 2016-03-11
    • 2012-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多