对array构造函数创建的未定义数组执行forEach操作

forEach on array of undefined created by Array constructor

本文关键字:数组 执行 forEach 操作 未定义 array 构造函数 创建      更新时间:2023-09-26

我只是想知道为什么不可能使forEach对未定义的数组

代码:

var arr = new Array(5); // [undefined x 5]
//ES5 forEach
arr.forEach(function(elem, index, array) {
    console.log(index);
});
//underscore each
_.each(arr, function(elem, index, array) {
    console.log(index);
});

两个例子都没有执行函数

现在要生成foreach,我必须输入:

var arr = [0,0,0,0,0];

然后在上面创建forEach

我试图使一个数组具有指定的大小和循环通过它,避免for循环。我认为使用forEach比for循环更清楚。对于长度为5的数组,这不是问题,但对于更大的数组,这将是丑陋的。

为什么在未定义值的数组中循环出现问题?

Array(5)本质上等同于

var arr = []; 
arr.length = 5;

在javascript中,改变数组的长度不会为它的数值属性设置任何值,也不会在数组对象中定义这些属性。数字属性是未定义的而不是未定义的值。您可以使用以下命令检查:

Object.keys(arr)

在迭代时,javascript遍历数组的数字属性,因此如果这些不存在,则没有什么可迭代的

你可以这样检查:

var arr = Array(5)
//prints nothing
arr.forEach(function(elem, index, array) {
    console.log(index);
});
arr[3] = 'hey'
//prints only 'hey' even though arr.length === 5
arr.forEach(function(elem, index, array) {
    console.log(index);
});

以下代码:

var arr = [undefined, undefined];

创建length ===2数组,设置数值属性0和1为undefined

查看.forEach()的简化实现可能会有所帮助。

Array.prototype.my_for_each = function(callback, thisArg) {
    for (var i = 0; i < this.length; i++) {
        if (i in this) {
            callback.call(thisArg, this[i], i, this);
        }
    }
};

因此,您可以看到,方法确实遍历整个Array (根据规范),但它只在成员实际存在时调用回调。它通过使用in操作符查找属性(索引)来进行检查,该操作符测试对象是否具有或继承了该属性。

如果in显示索引存在,则调用回调。


那么给定这个数组:

var arr = ["foo", "bar", "baz"];

这将输出所有3项:

arr.my_for_each(function(item) {
    console.log(item);
});
// "foo" "bar" "baz"

但是如果我们使用delete删除一个成员,它会在数组中留下一个洞,这个洞现在会被忽略。

delete arr[1];
arr.my_for_each(function(item) {
    console.log(item);
});
// "foo" "baz"

当您使用Array(5)创建Array时,它创建了一个没有任何成员的Array,但是.length设置为5。这是一个稀疏数组的例子(在这个例子中非常稀疏)。因为in找不到任何索引,所以永远不会调用回调。

您可以使用Array.from创建一个数组并传递lambda函数,该函数将在数组中的每个项目上调用。

详细文档

  const arr = Array.from(
      { length: 5 },
      () => 0
  )
  console.log(arr)

其他答案解释了问题,但没有提供解决方案。

ES6扩展语法用undefined填充稀疏值。Array也是如此。apply(null, sparseArray),它具有在旧浏览器中工作的好处,但需要更多的工作来理解。

const sparseArray = new Array(5);
const unsparseArray1 = Array.apply(null, sparseArray);
const unsparseArray2 = [...sparseArray];
function arrayApply() {
  // ES5 forEach works with either approach
  unsparseArray1.forEach(function(elem, index, array) {
    console.log(index);
  });
}
function es6Spread() {
  // Lodash each works with either approach
  _.each(unsparseArray2, function(elem, index, array) {
    console.log(index);
  });
}
<html><head>
  <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
  <title>Making sparse arrays unsparse</title>
</head><body>
  <p><button onclick="arrayApply();">Array.apply(null, sparseArray)</button></p>
  <p><button onclick="es6Spread();">[...sparseArray]</button></p>
</body>
</html>

在我的情况下,我正在寻找一个优雅的解决方案来创建从0X开始的数字数组。

以一种优雅的方式使用箭头函数,它出现了一行代码

const arrayLength = 10;
const arrayOfDigits = Array.apply(null, Array(arrayLength)).map((_, index) => index);

在我看来是一个相当复杂的代码,比一个带有for循环的单独代码块要复杂得多。