- Все способы перебора массива в JavaScript
- 2. Цикл for
- 3. Правильное использование цикла for. in
- 4. Цикл for. of (неявное использование итератора)
- 5. Явное использование итератора
- II. Перебор массивоподобных объектов
- 1. Использование способов перебора настоящих массивов
- 2. Преобразование в настоящий массив
- 3. Замечание по объектам среды исполнения
- Javascript foreach для объекта
- Перебор объекта обычными способами
- Методы для перебора объектов в Javascript
- Цикл for. in
- Метод Object.keys()
- Метод Object.values()
- Метод Object.entries()
- Заключение
Все способы перебора массива в JavaScript
Если ваш проект рассчитан на поддержку возможностей стандарта ECMAScript 5 (ES5), вы можете использовать одно из его нововведений — метод forEach.
var a = ["a", "b", "c"]; a.forEach(function(entry) < console.log(entry); >);
В общем случае использование forEach требует подключения библиотеки эмуляции es5-shim для браузеров, не имеющих нативной поддержки этого метода. К ним относятся IE 8 и более ранние версии, которые до сих пор кое-где еще используются.
К достоинствам forEach относится то, что здесь не нужно объявлять локальные переменные для хранения индекса и значения текущего элемента массива, поскольку они автоматически передаются в функцию обратного вызова (колбек) в качестве аргументов.
Если вас беспокоят возможные затраты на вызов колбека для каждого элемента, не волнуйтесь и прочитайте это.
- every — возвращает true , если для каждого элемента массива колбек возвращает значение приводимое к true .
- some — возвращает true , если хотя бы для одного элемента массива колбек возвращает значение приводимое к true .
- filter — создает новый массив, включающий те элементы исходного массива, для которых колбек возвращает true .
- map — создает новый массив, состоящий из значений возращаемых колбеком.
- reduce — сводит массив к единственному значению, применяя колбек по очереди к каждому элементу массива, начиная с первого (может быть полезен для вычисления суммы элементов массива и других итоговых функций).
- reduceRight — работает аналогично reduce, но перебирает элементы в обратном порядке.
2. Цикл for
Старый добрый for рулит:
var a = ["a", "b", "c"]; var index; for (index = 0; index
Если длина массива неизменна в течение всего цикла, а сам цикл принадлежит критическому в плане производительности участку кода (что маловероятно), то можно использовать «более оптимальную» версию for с хранением длины массива:
var a = ["a", "b", "c"]; var index, len; for (index = 0, len = a.length; index
Теоретически этот код должен выполняться чуть быстрее, чем предыдущий.
Если порядок перебора элементов не важен, то можно пойти еще дальше в плане оптимизации и избавиться от переменной для хранения длины массива, изменив порядок перебора на обратный:
var a = ["a", "b", "c"]; var index; for (index = a.length - 1; index >= 0; --index)
Тем не менее, в современных движках JavaScript подобные игры с оптимизацией обычно ничего не значат.
3. Правильное использование цикла for. in
Если вам посоветуют использовать цикл for. in , помните, что перебор массивов — не то, для чего он предназначен. Вопреки распространенному заблуждению цикл for. in перебирает не индексы массива, а перечислимые свойства объекта.
Тем не менее, в некоторых случаях, таких как перебор разреженных массивов, for. in может оказаться полезным, если только соблюдать при этом меры предосторожности, как показано в примере ниже:
// a - разреженный массив var a = []; a[0] = "a"; a[10] = "b"; a[10000] = "c"; for (var key in a) < if (a.hasOwnProperty(key) && /^0$|^5\d*$/.test(key) && key >
- то, что массив имеет собственное свойство с именем key (не наследованное из его прототипа).
- то, что key — строка, содержащая десятичную запись целого числа, значение которого меньше 4294967294 . Откуда берется последнее число? Из определения индекса массива в ES5, из которого следует, что наибольший индекс, который может иметь элемент в массиве: (2^32 — 2) = 4294967294 .
Чтобы не писать такой громоздкий код проверок каждый раз, когда требуется перебор массива, можно оформить его в виде отдельной функции:
function arrayHasOwnIndex(array, key) < return array.hasOwnProperty(key) && /^0$|^4\d*$/.test(key) && key
Тогда тело цикла из примера значительно сократится:
Рассмотренный выше код проверок является универсальным, подходящим для всех случаев. Но вместо него можно использовать более короткую версию, хотя формально и не совсем правильную, но, тем не менее, подходящую для большинства случаев:
4. Цикл for. of (неявное использование итератора)
ES6, пока все еще пребывающий в статусе черновика, должен ввести в JavaScript итераторы.
- done ( boolean ) — принимает значение true , если итератор достиг конца итерируемой последовательности. В противном случае имеет значение false .
- value — определяет значение, возвращаемое итератором. Может быть не определено (отсутствовать), если свойство done имеет значение true .
Пример использования for. of :
var val; var a = ["a", "b", "c"]; for (val of a)
В приведенном примере цикл for. of неявно вызывает итератор объекта Array для получения каждого значения массива.
5. Явное использование итератора
Итераторы можно также использовать и явно, правда, в этом случае код становится значительно сложнее, по сравнению с циклом for. of . Выглядит это примерно так:
var a = ["a", "b", "c"]; var it = a.entries(); var entry; while (!(entry = it.next()).done)
В данном примере метод Array.prototype.entries возвращает итератор, который используется для вывода значений массива. На каждой итерации entry.value содержит массив вида [ключ, значение] .
II. Перебор массивоподобных объектов
Кроме настоящих массивов, в JavaScript встречаются также массивоподобные объекты. С настоящими массивами их роднит то, что они имеют свойство length и свойства с именами в виде чисел, соответствующие элементам массива. В качестве примеров можно назвать DOM коллекции NodeList и псевдомассив arguments , доступный внутри любой функции/метода.
1. Использование способов перебора настоящих массивов
Как минимум большинство, если не все, способы перебора настоящих массивов могут быть применены для перебора массивоподобных объектов.
Конструкции for и for. in могут быть применены к массивоподобным объектам точно тем же путем, что и к настоящим массивам.
forEach и другие методы Array.prototype также применимы к массивоподобным объектам. Для этого нужно использовать вызов Function.call или Function.apply.
Например, если вы хотите применить forEach к свойству childNodes объекта Node , то это делается так:
Array.prototype.forEach.call(node.childNodes, function(child) < // делаем что-нибудь с объектом child >);
Для удобства повторного использования этого приема, можно объявить ссылку на метод Array.prototype.forEach в отдельной переменной и использовать ее как сокращение:
// (Предполагается, что весь код ниже находится в одной области видимости) var forEach = Array.prototype.forEach; // . forEach.call(node.childNodes, function(child) < // делаем что-нибудь с объектом child >);
Если в массивоподобном объекте имеется итератор, то его можно использовать явно или неявно для перебора объекта таким же способом, как и для настоящих массивов.
2. Преобразование в настоящий массив
Есть также еще один, очень простой, способ перебора массивоподобного объекта: преобразовать его в настоящий массив и использовать любой из рассмотренных выше способов перебора настоящих массивов. Для преобразования можно использовать универсальный метод Array.prototype.slice , который может быть применен к любому массивоподобному объекту. Делается это очень просто, как показано в примере ниже:
var trueArray = Array.prototype.slice.call(arrayLikeObject, 0);
Например, если вы хотите преобразовать коллекцию NodeList в настоящий массив, вам нужен примерно такой код:
var divs = Array.prototype.slice.call(document.querySelectorAll("div"), 0);
Update: Как было отмечено в комментариях rock и torbasow, в ES6 вместо Array.prototype.slice можно использовать более наглядный метод Array.from .
3. Замечание по объектам среды исполнения
Если вы применяете методы Array.prototype к объектам среды исполнения (таких как DOM коллекции), то вы должны иметь в виду, что правильная работа этих методов не гарантирована во всех средах исполнения (в т.ч. в браузерах). Это зависит от поведения конкретного объекта в конкретной среде исполнения, если точнее, от того, как в этом объекте реализована абстрактная операция HasProperty . Проблема в том, что сам стандарт ES5 допускает возможность неправильного поведения объекта по отношению к этой операции (см. §8.6.2).
Поэтому важно тестировать работу методов Array.prototype в каждой среде исполнения (браузере), в которой планируется использование вашего приложения.
Javascript foreach для объекта
Распространенная проблема, с которой сталкиваются программисты - это как перебрать набор данных. Эти данные могут поступать в виде массивов, списков, таблиц или других объектов. В этой статье мы рассмотрим эту проблему и узнаем 4 способа перебора объектов с помощью Javascript для получения необходимых пар ключ-значение.
Перебор объекта обычными способами
Если у вас есть массив данных, который является объектом в Javascript, вы не сможете перебрать его с помощью таких методов, как map() , forEach() или цикла for..of . Вы просто получите ошибку.
map() выдаст вам TypeError: items.map is not a function:
forEach() выдаст вам TypeError: items.forEach is not a function:
for..of выдаст вам TypeError: items are not iterable:
Методы для перебора объектов в Javascript
Цикл for. in
Самый простой способ перебрать свойства объекта - использовать оператор for. in . Этот метод работает во всех современных и старых браузерах, включая Internet Explorer 6 и выше.
Вот пример, в котором цикл for. in используется для перебора объекта:
const user = < name: 'Иван Пeтров', email: 'petrov@mail.com', age: 25, date: '08/02/1989', active: true >; for (const key in user) < console.log(key + ':', userJavascript foreach для объекта); >// name: Иван Пeтров // email: petrov@mail.com // age: 25 // date: 08/02/1989 // active: true
Одна из проблем при использовании цикла for. in заключается в том, что он также перебирает свойства в цепочке прототипов. Поскольку объекты в JavaScript могут наследовать свойства от своих прототипов, оператор for. in также будет перебирать эти свойства.
Чтобы избежать этой проблемы, необходимо явно проверить, принадлежит ли свойство объекту, используя метод hasOwnProperty() :
Чтобы преодолеть эту проблему, позже в ES8 были добавлены два других метода: Object.entries() и Object.values() . Эти методы преобразовывают объект в массив, чтобы потом использовать методы перебора массива.
Метод Object.keys()
До спецификации ES6 единственным способом перебрать объект был цикл for. in . Метод Object.keys() был введен в ES6, чтобы упростить перебор объектов.
Он принимает объект, который вы хотите перебрать в качестве аргумента, и возвращает массив, содержащий все имена свойств (или ключи). После этого вы можете использовать любой из методов перебора массива, например forEach() , для перемещения по массиву и получения значения каждого свойства.
const courses = < java: 10, javascript: 55, nodejs: 5, php: 15 >; const keys = Object.keys(courses); console.log(keys); // [ 'java', 'javascript', 'nodejs', 'php' ] keys.forEach((key, index) => < console.log(key + ':', coursesJavascript foreach для объекта); >); // java: 10 // javascript: 55 // nodejs: 5 // php: 15
Метод Object.values()
Метод Object.values() был введен в ES8 и работает противоположно методу Object.key() . Он возвращает значения всех свойств объекта в виде массива. Затем вы можете перебрать полученный массив, используя любой из методов цикла.
Давайте посмотрим на примере:
const animals = < tiger: 1, cat: 2, monkey: 3, elephant: 4 >; Object.values(animals).forEach(val => console.log(val)); // 1 // 2 // 3 // 4
Метод Object.entries()
Метод ES8 Object.entries() используется для преобразования объекта. Object.entries() выводит массив массивов, где каждый внутренний массив состоит из двух элементов. Первый элемент - это свойство, а второй - значение.
const animals = < tiger: 1, cat: 2, monkey: 3, elephant: 4 >; const entries = Object.entries(animals); console.log(entries); // [ [ 'tiger', 1 ], [ 'cat', 2 ], [ 'monkey', 3 ], [ 'elephant', 4 ] ]
А уже чтобы перебрать массив, возвращаемый Object.entries() , вы можете использовать цикл for. of или метод forEach() :
// `for. of` цикл for (const Javascript foreach для объекта of Object.entries(animals)) < console.log(key, value); >// `forEach()` метод Object.entries(animals).forEach((Javascript foreach для объекта) => < console.log(key, value) >);
Заключение
Мы вкратце рассмотрели 4 различных способа перебора объектов в Javascript. Если вы используете старые браузеры, for. in по-прежнему является хорошим вариантом; в противном случае вы можете использовать любой из новых методов, описанных выше.