ForEach в массиве undefined, созданный конструктором Array
Мне просто интересно, почему невозможно сделать forEach в массиве undefined.
код:
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];
Затем сделайте для него Each на нем.
Я пытаюсь создать массив с указанным размером и пропустить его, избегая цикла for
. Я думаю, что это более ясное использование forEach, чем для цикла.
С массивом длиной 5 это не проблема, но это было бы уродливо с большими массивами.
Почему возникает проблема, связанная с массивом значений undefined?
Ответы
Ответ 1
Array(5)
существенно эквивалентно
var arr = [];
arr.length = 5;
При изменении длины массива javascript не задаются никакие значения для его числовых свойств и не определяются эти свойства в объекте массива. Таким образом, числовые свойства undefined вместо значения undefined. Вы можете проверить это, используя:
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.
Ответ 2
Возможно, поможет упрощенная реализация .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);
}
}
};
Итак, вы можете видеть, что происходит то, что метод выполняет итерацию всего массива (согласно спецификации), но он вызывает только обратный вызов, если элемент действительно существует. Он проверяет, ищет ли свойство (индекс) с помощью оператора 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)
, он создал один без каких-либо элементов, но с .length
установлен на 5
. Итак, это пример редкого массива (очень редкого в этом случае). Поскольку ни один из индексов не будет найден с помощью in
, обратный вызов никогда не будет вызываться.