我只是想知道为什么不可能使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>
在我的情况下,我正在寻找一个优雅的解决方案来创建从0
到X
开始的数字数组。
以一种优雅的方式使用箭头函数,它出现了一行代码
const arrayLength = 10;
const arrayOfDigits = Array.apply(null, Array(arrayLength)).map((_, index) => index);
在我看来是一个相当复杂的代码,比一个带有for
循环的单独代码块要复杂得多。