由 Array 构造函数创建的 undefined 数组上的 forEach

IT技术 javascript arrays foreach undefined
2021-01-16 00:08:27

我只是想知道为什么不可能在未定义的数组上创建 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 的数组,这不是问题,但是对于更大的数组,它会很丑陋。

为什么在遍历未定义值数组时会出现问题?

3个回答

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

你能解释一下spread operator在这种情况下的行为吗?
2021-03-25 00:08:27

查看 的简化实现.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删除成员,它会在 Array 中留下一个洞,现在将被忽略。

delete arr[1];

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

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

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

ES6 Spread 语法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>