Подсчет количества элементов в массиве JavaScript
Давайте подсчитаем количество элементов ‘a’ в этом массиве. Для этого будем перебирать массив циклом и каждый раз, когда нам будет встречаться элемент с нужным значением, будем увеличивать какой-нибудь счетчик на единицу:
Дан следующий массив:
Подсчитайте количество цифр 3 в этом массиве.
Модифицируйте предыдущую задачу так, чтобы в одном цикле одновременно подсчитывалось и количество троек, и количество двоек.
Результат в виде объекта
Пусть у нас опять дан наш массив:
Давайте подсчитаем сколько каких элементов есть в этом массиве и представим результат в виде объекта вот такого объекта:
Для решения сделаем объект count со следующим начальным значением:
Будем перебирать массив циклом и увеличивать соответствующее значение в объекте count :
Пойдем дальше: то, что у объекта count в начальном значении перечислены символы, ведь мы обычно не знаем, какие элементы есть в массиве.
Пусть объект count формируется автоматически таким образом: если такого элемента в count нет, то ему следует присвоить значение 1 , а если есть — просто увеличить значение на единицу:
Дана строка. Подсчитайте сколько раз в ней встречается каждый из ее символов.
Руководство по JavaScript, часть 5: массивы и циклы
Сегодня, в пятой части перевода курса по JavaScript, мы поговорим о массивах и циклах. Массивы используются в ходе решения множества задач. Часто с массивами работают, используя циклы.
Массивы
Массивы, объекты типа Array , развиваются вместе с остальными механизмами языка. Они представляют собой списки пронумерованных значений.
Первый элемент массива имеет индекс (ключ) 0, такой подход используется во многих языках программирования.
В этом разделе мы рассмотрим современные методы работы с массивами.
▍Инициализация массивов
Вот несколько способов инициализации массивов.
Для того чтобы получить доступ к отдельному элементу массива, используют конструкцию, состоящую из квадратных скобок, в которых содержится индекс элемента массива. Элементы массивов можно как считывать, так и записывать.
Конструктор Array для объявления массивов использовать не рекомендуется.
Этот способ следует использовать лишь при объявлении типизированных массивов.
▍Получение длины массива
Для того чтобы узнать длину массива, нужно обратиться к его свойству length .
▍Проверка массива с использованием метода every()
Метод массивов every() можно использовать для организации проверки всех их элементов с использованием некоего условия. Если все элементы массива соответствуют условию, функция возвратит true , в противном случае она возвратит false .
Этому методу передаётся функция, принимающая аргументы currentValue (текущий элемент массива), index (индекс текущего элемента массива) и array (сам массив). Он может принимать и необязательное значение, используемое в качестве this при выполнении переданной ему функции.
Например, проверим, превышают ли значения всех элементов массива число 10.
Здесь нас, в функции test() , интересует лишь первый передаваемый ей аргумент, поэтому мы объявляем её, указывая лишь параметр el , в который и попадёт соответствующее значение.
▍Проверка массива с использованием метода some()
Этот метод очень похож на метод every() , но он возвращает true , если хотя бы один из элементов массива удовлетворяет условию, заданному переданной ему функцией.
▍Создание массива на основе существующего массива с использованием метода map()
Метод массивов map() позволяет перебирать массивы, применяя к каждому их элементу, переданную этому методу, функцию, преобразующую элемент, и создавать из полученных значений новые массивы. Вот, например, как получить новый массив, являющийся результатом умножения всех элементов исходного массива на 2.
▍Фильтрация массива с помощью метода filter()
Метод filter() похож на метод map() , но он позволяет создавать новые массивы, содержащие лишь те элементы исходных массивов, которые удовлетворяют условию, задаваемому передаваемой методу filter() функцией.
▍Метод reduce()
Метод reduce() позволяет применить заданную функцию к аккумулятору и к каждому значению массива, сведя массив к единственному значению (это значение может иметь как примитивный, так и объектный тип). Этот метод принимает функцию, выполняющую преобразования, и необязательное начальное значение аккумулятора. Рассмотрим пример.
Здесь мы ищем произведение всех элементов массива, описанного с помощью литерала, задавая в качестве начального значения аккумулятора 1.
▍Перебор массива с помощью метода forEach()
Метод массивов forEach() можно использовать для перебора значений массивов и для выполнения над ними неких действий, задаваемых передаваемой методу функцией. Например, выведем, по одному, элементы массива в консоль.
Если при переборе массива нужно остановить или прервать цикл, то при использовании forEach() придётся выбрасывать исключение. Поэтому если в ходе решения некоей задачи может понадобиться прерывание цикла, лучше всего выбрать какой-нибудь другой способ перебора элементов массива.
▍Перебор массива с использованием оператора for. of
Оператор for. of появился в стандарте ES6. Он позволяет перебирать итерируемые объекты (в том числе — массивы). Вот как им пользоваться.
На каждой итерации цикла в переменную v попадает очередной элемент массива a .
▍Перебор массива с использованием оператора for
Оператор for позволяет организовывать циклы, которые, в частности, можно использовать и для перебора (или инициализации) массивов, обращаясь к их элементам по индексам. Обычно индекс очередного элемента получают, пользуясь счётчиком цикла.
Если, в ходе выполнения цикла, нужно пропустить его итерацию, можно воспользоваться командой continue . Для досрочного завершения цикла можно воспользоваться командой break . Если в цикле, например, расположенном в некоей функции, использовать команду return , выполнение цикла и функции завершится, а возвращённое с помощью return значение попадёт туда, откуда была вызвана функция.
▍Метод @@iterator
Этот метод появился в стандарте ES6. Он позволяет получать так называемый «итератор объекта» — объект, который в данном случае позволяет организовывать перебор элементов массива. Итератор массива можно получить, воспользовавшись символом (такие символы называют «известными символами») Symbol.iterator . После получения итератора можно обращаться к его методу next() , который, при каждом его вызове, возвращает структуру данных, содержащую очередной элемент массива.
Если вызвать метод next() после того, как будет достигнут последний элемент массива, он возвратит, в качестве значения элемента, undefined . Объект, возвращаемый методом next() , содержит свойства value и done . Свойство done принимает значение false до тех пор, пока не будет достигнут последний элемент массива. В нашем случае, если вызвать it.next() в четвёртый раз, он возвратит объект < value: undefined, done: true >, в то время как при трёх предыдущих вызовах этот объект имел вид < value: значение, done: false >.
Метод массивов entries() возвращает итератор, который позволяет перебирать пары ключ-значение массива.
Метод keys() позволяет перебирать ключи массива.
▍Добавление элементов в конец массива
Для добавления элементов в конец массива используют метод push() .
▍Добавление элементов в начало массива
Для добавления элементов в начало массива используют метод unshift() .
▍Удаление элементов массива
Удалить элемент из конца массива, одновременно возвратив этот элемент, можно с помощью метода pop() .
Аналогичным образом, с помощью метода shift() , можно удалить элемент из начала массива.
То же самое, но уже с указанием позиции удаления элементов и их количества, делается с помощью метода splice() .
▍Удаление элементов массива и вставка вместо них других элементов
Для того чтобы, воспользовавшись одной операцией, удалить некие элементы массива и вставить вместо них другие элементы, используется уже знакомый вам метод splice() .
Например, здесь мы удаляем 3 элемента массива начиная с индекса 2, после чего в то же место добавляем два других элемента:
▍Объединение нескольких массивов
Для объединения нескольких массивов можно воспользоваться методом concat() , возвращающим новый массив.
▍Поиск элементов в массиве
В стандарте ES5 появился метод indexOf() , который возвращает индекс первого вхождения искомого элемента массива. Если элемент в массиве найти не удаётся — возвращается -1 .
Метод lastIndexOf() возвращает индекс последнего вхождения элемента в массив, или, если элемент не найден, -1 .
В ES6 появился метод массивов find() , который выполняет поиск по массиву с использованием передаваемой ему функции. Если функция возвращает true , метод возвращает значение первого найденного элемента. Если элемент найти не удаётся, функция возвратит undefined .
Выглядеть его использование может следующим образом.
Здесь в массиве, содержащем объекты, осуществляется поиск элемента, свойство id которого равняется заданному.
Метод findIndex() похож на find() , но он возвращает индекс найденного элемента или undefined .
В ES7 появился метод includes() , который позволяет проверить наличие некоего элемента в массиве. Он возвращает true или false , найдя или не найдя интересующий программиста элемент.
С помощью этого метода можно проверять на наличие некоего элемента не весь массив, а лишь некоторую его часть, начинающуюся с заданного при вызове этого метода индекса. Индекс задаётся с помощью второго, необязательного, параметра этого метода.
▍Получение фрагмента массива
Для того чтобы получить копию некоего фрагмента массива в виде нового массива, можно воспользоваться методом slice() . Если этот метод вызывается без аргументов, то возвращённый массив окажется полной копией исходного. Он принимает два необязательных параметра. Первый задаёт начальный индекс фрагмента, второй — конечный. Если конечный индекс не задан, то массив копируется от заданного начального индекса до конца.
▍Сортировка массива
Для организации сортировки элементов массива в алфавитном порядке ( 0-9A-Za-z ) используется метод sort() без передачи ему аргументов.
Этому методу можно передать функцию, задающую порядок сортировки. Функция принимает, для сравнения двух элементов, параметры a и b . Она возвращает отрицательное число в том случае, если a меньше b по какому-либо критерию, 0 — если они равны, и положительное число — если a больше b . При написании подобной функции для сортировки числовых массивов она может возвратить результат вычитания a и b . Так, возврат результата вычисления выражения a — b означает сортировку массива по возрастанию, возврат результата вычисления выражения b — a даст сортировку массива по убыванию.
Для того чтобы обратить порядок следования элементов массива можно воспользоваться методом reverse() . Он, так же, как и sort() , модифицирует массив для которого вызывается.
▍Получение строкового представления массива
Для получения строкового представления массива можно воспользоваться его методом toString() .
Похожий результат даёт метод join() , вызванный без аргументов.
Ему, в качестве аргумента, можно передать разделитель элементов.
▍Создание копий массивов
Для создания копии массива путём копирования в новый массив значений исходного массива можно воспользоваться методом Array.from() . Он подходит и для создания массивов из массивоподобных объектов (из строк, например).
Метод Array.of() тоже можно использовать для копирования массивов, а также для «сборки» массивов из различных элементов. Например, для копирования элементов одного массива в другой можно воспользоваться следующей конструкцией.
Для копирования элементов массива в некое место самого этого массива используется метод copyWithin() . Его первый аргумент задаёт начальный индекс целевой позиции, второй — начальный индекс позиции источника элементов, а третий параметр, необязательный, указывает конечный индекс позиции источника элементов. Если его не указать, в указанное место массива будет скопировано всё, начиная от начального индекса позиции источника до конца массива.
Циклы
Выше, говоря о массивах, мы уже сталкивались с некоторыми способами организации циклов. Однако циклы в JavaScript используются не только для работы с массивами, да и рассмотрели мы далеко не все их виды. Поэтому сейчас мы уделим некоторое время рассмотрению разных способов организации циклов в JavaScript и поговорим об их особенностях.
▍Цикл for
Рассмотрим пример применения этого цикла.
Как уже было сказано, прерывать выполнение такого цикла можно, используя команду break , а пропускать текущую итерацию и переходить сразу к следующей можно с помощью команды continue .
▍Цикл forEach
Этот цикл мы тоже обсуждали. Приведём пример перебора массива с его помощью.
Напомним, что для прерывания такого цикла надо выбрасывать исключение, то есть, если при использовании цикла может понадобиться прервать его, лучше выбрать какой-нибудь другой цикл.
▍Цикл do. while
Это — так называемый «цикл с постусловием». Такой цикл будет выполнен как минимум один раз до проверки условия завершения цикла.
Его можно прерывать с использованием команды break , можно переходить на его следующую итерацию командой continue .
▍Цикл while
Это — так называемый «цикл с предусловием». Если, на входе в цикл, условие продолжения цикла ложно, он не будет выполнен ни одного раза.
▍Цикл for. in
Этот цикл позволяет перебирать все перечислимые свойства объекта по их именам.
▍Цикл for. of
Цикл for. of совмещает в себе удобство цикла forEach и возможность прерывать его работу штатными средствами.
Обратите внимание на то, что здесь, в заголовке цикла, используется ключевое слово const , а не, как можно было бы ожидать, let . Если внутри блока цикла переменные не нужно переназначать, то const нам вполне подходит.
Если сравнить циклы for. in и for. of , то окажется, что for. in перебирает имена свойств, а for. of — значения свойств.
Циклы и области видимости
С циклами и с областями видимости переменных связана одна особенность JavaScript, которая может доставить разработчику некоторые проблемы. Для того чтобы с этими проблемами разобраться, поговорим о циклах, об областях видимости, и о ключевых словах var и let .
В цикле производится 5 итераций, на каждой из которых в массив operations добавляется новая функция. Эта функция выводит в консоль значение счётчика цикла — i . После того, как функции добавлены в массив, мы этот массив перебираем и вызываем функции, являющиеся его элементами.
Выполняя подобный код можно ожидать результата, показанного ниже.
Но на самом деле он выводит следующее.
Почему это так? Всё дело в том, что в качестве счётчика цикла мы используем переменную, объявленную с использованием ключевого слова var .
Так как объявления подобных переменных поднимаются в верхнюю часть области видимости, вышеприведённый код аналогичен следующему.
В результате оказывается, что в цикле for. of , в котором мы перебираем массив, переменная i всё ещё видна, она равна 5, в результате, ссылаясь на i во всех функциях, мы выводим число 5.
Как изменить поведение программы таким образом, чтобы она делала бы то, что от неё ожидается?
Самое простое решение этой проблемы заключается в использовании ключевого слова let . Оно, как мы уже говорили, появилось в ES6, его использование позволяет избавиться от некоторых странностей, характерных для var .
В частности, в вышеприведённом примере достаточно изменить var на let и всё заработает так, как нужно.
Теперь на каждой итерации цикла каждая функция, добавленная в массив operations , получает собственную копию i . Помните о том, что в данной ситуации нельзя использовать ключевое слово const , так как значение i в цикле меняется.
Ещё один способ решения этой проблемы, который часто применялся до появления стандарта ES6, когда ключевого слова let ещё не было, заключается в использовании IIFE.
При таком подходе значение i сохраняется в замыкании, а в массив попадает функция, возвращаемая IIFE и имеющая доступ к замыканию. Эту функцию можно выполнить тогда, когда в ней возникнет необходимость. Вот как это выглядит.
Итоги
Сегодня мы поговорили о массивах и о циклах в JavaScript. Тема нашего следующего материала — обработка исключений, особенности использования точки с запятой и шаблонные литералы.
Уважаемые читатели! Какими методами для работы с массивами в JavaScript вы пользуетесь чаще всего?
Array.length
Свойство length объекта, который является экземпляром типа Array , устанавливает или возвращает число элементов этого массива. Значение данного свойства 32-битное безнаковое целое число, которое всегда численно больше чем самый наибольший индекс в массиве.
Синтаксис
Описание
Свойство length является целым числом с положительным знаком и значением, меньшим чем 2 в степени 32 (2 32 ).
В любой момент вы можете установить свойство length для обрезки массива. Когда вы расширяете массив, изменяя его свойство length , реальное количество элементов в массиве увеличивается; например, если вы установите свойство length в 3, когда оно равно 2, массив будет из 3 элементов, где значение третьего элемента будет равно undefined .
Таким образом, свойство length ничего не говорит о количестве определённых значений в массиве. Также смотрите раздел Взаимосвязь свойства length с числовыми свойствами.
| Атрибуты свойства Array.length | |
|---|---|
| Записываемое | да |
| Перечисляемое | нет |
| Настраиваемое | нет |
Примеры
Пример: итерирование по массиву
В следующем примере массив numbers итерируется до значения свойства length , показывающего, сколько элементов содержит массив. Значение каждого элемента удваивается.
Пример: сокращение массива
Следующий пример сокращает массив statesUS до длины в 50 элементов, если текущая длина массива больше 50.