Чем коллекция отличается от массива js
Перейти к содержимому

Чем коллекция отличается от массива js

  • автор:

Живые и неживые коллекции в JavaScript

Найти несколько DOM-элементов и получить к ним доступ из JavaScript можно разными способами: querySelectorAll , getElementsByTagName , children и так далее. В итоге в каждом случае будет возвращена коллекция — сущность, которая похожа на массив объектов, но при этом им не является, на самом деле это набор DOM-элементов. Стоит учесть, что фактически разные методы возвращают разные коллекции:

  • HTMLCollection — коллекция непосредственно HTML-элементов.
  • NodeList — коллекция узлов, более абстрактное понятие. Например, в DOM-дереве есть не только узлы-элементы, но также текстовые узлы, узлы-комментарии и другие, поэтому NodeList может содержать другие типы узлов.

При работе с DOM-элементами тип коллекции значительной роли не играет, поэтому для удобства будем рассматривать их как одну сущность — коллекцию.

Во время работы с коллекциями можно столкнуться с поведением, которое покажется странным, если не знать один нюанс — они бывают живыми (динамическими) и неживыми (статическими). То есть либо реагируют на любое изменение DOM, либо нет. Вид коллекции зависит от способа, с помощью которого она получена. Рассмотрим на примере.

Разница между живыми и неживыми коллекциями

Допустим, в разметке есть список книг:

Для взаимодействия с книгами получим с помощью JavaScript список всех нужных элементов. Чтобы в дальнейшем увидеть разницу между видами коллекций, используем разные способы поиска элементов — свойство children и метод querySelectorAll :

let booksList = document.querySelector(`.books`); let liveBooks = booksList.children; // Выведем все дочерние элементы списка .books console.log(liveBooks); 
let notLiveBooks = document.querySelectorAll(`.book`); // Выведем коллекцию, содержащую все элементы с классом book console.log(notLiveBooks); 

Пока никакой разницы не видно. В обоих случаях console.log выведет одни и те же элементы. Но что, если попробовать удалить из DOM одну из книг?

let booksList = document.querySelector(`.books`); let liveBooks = booksList.children; // Удалим первую книгу liveBooks[0].remove(); // Получим 2 console.log(liveBooks.length); // Получим элемент book--two, который теперь стал первым в коллекции console.log(liveBooks[0]); 
let notLiveBooks = document.querySelectorAll(`.book`); // Удалим первую книгу notLiveBooks[0].remove(); // Получим 3 console.log(notLiveBooks.length); // Получим ссылку на удалённый элемент book--one console.log(notLiveBooks[0]); 

В первом случае информация о количестве элементов внутри коллекции автоматически обновилась после удаления одного элемента из DOM — эта коллекция живая. Во втором случае в переменной notLiveBooks хранится первоначальное состояние коллекции, которое было актуально на момент вызова метода querySelectorAll . Эта коллекция неживая, она ничего не знает об изменении DOM. При этом доступна ссылка на удалённый элемент book—one , которого фактически больше нет в DOM.

Другие способы получить коллекцию

Кроме children и querySelectorAll есть другие способы поиска DOM-элементов:

  • getElementsByTagName(tag) — находит все элементы с заданным тегом,
  • getElementsByClassName(className) — находит все элементы с заданным классом,
  • getElementsByName(name) — находит все элементы с заданным атрибутом name .

Все эти методы возвращают живые коллекции. Они используются реже, потому что в большинстве случаев удобнее применять querySelectorAll , но могут встречаться в старом коде.

Как использовать

Для решения большинства задач можно ограничиться неживыми коллекциями. Но если нужно сохранить ссылку на реальное состояние DOM — понадобится живая коллекция. Это удобно в тех случаях, когда программе нужно постоянно манипулировать списком элементов, которые могут регулярно удаляться и добавляться. Хороший пример — задачи в таск-трекере. С помощью живой коллекции можно хранить именно те задачи, которые фактически существуют в данный момент времени.

Структура и некоторые свойства коллекции имеют много общего с массивом. Например, у неё тоже есть свойство length , и элементы коллекции можно перебирать в цикле for. of , потому что это перечисляемая сущность. Но, как упоминалось ранее, коллекции не во всём похожи на обычные массивы. С коллекциями не работают такие методы массивов, как push , splice и другие. Для их использования нужно преобразовать коллекцию в массив — например, с помощью метода Array.from :

let booksList = document.querySelector(`.books`); let books = booksList.children; // Выведет обычный массив с элементами из коллекции books console.log(Array.from(books)); 

При этом нужно помнить — массив статичен, поэтому при таком преобразовании теряются преимущества живых коллекций.

«Доктайп» — журнал о фронтенде. Читайте, слушайте и учитесь с нами.

Тонкости ES6: Коллекции (часть 1)

Ранее на этой неделе (статья от 19 июня — прим.) спецификация ES6, официально названная ECMA-262, 6th Edition, ECMAScript 2015 Language Specification, преодолела последний барьер и была утверждена как стандарт Ecma. Мои поздравления TC39 и всем остальным, кто помогал. ES6 закончен!

Даже лучше: больше не надо будет ждать следующего обновления 6 лет. Комитет собирается выпускать новую версию в срок около года. Предложения по ES7 уже примаются!

Я считаю, что уместно отпраздновать это событие поговорив о той части Javascript, которую я так желал в нем увидеть, и у которая все еще имеет потенциал к улучшению.

Сложности коэволюции

JS не очень похож на другие языки програмирования, и это временами влияет на эволюцию языка самыми неожиданными способами. Хороший пример — модули в ES6. Модули есть в других языках — Racket (отличная реализация), Python. Когда комитет решил добавить модули в ES6, почему не скопировать существующую имплементацию?

JS отличается, так как он исполняется в браузерах. I/O операции могут занять приличное время. Поэтому система модулей ES6 должна поддерживать асинхронную загрузку. Она не может периодически искать модули по разным директориям. Поэтому копирование текущих имплементаций не лучший вариант.

Как это повлияло на конечный дизайн — в другой раз. Мы не станем сейчас говорить о модулях. Мы поговорим о том, что ES6 называет “keyed collections”: Set, Map, WeakSet, WeakMap. Эти структуры похожи на хэш-таблицы (hash tables) в других языках. Но в процессе дискуссий комитет пошел на некоторые компромиссы, из-за особенностей JS.

Зачем коллекции?

Каждый, кто знаком с JS, знает что в нем уже есть что-то наподобии хэш-таблиц — объекты. Обычный Object , в конце концов немногим более чем коллекция key-value пар. Вы можете добавлять, итерировать, считывать и удалять свойства (properties) — все как в хэш-таблицах. Зачем тогда эти новые фичи в языке?

Ну, в некоторых программах объекты так и используются, и если это работает, то особых причин использовать на Map или Set у вас нет. Однако в использовании обычных объектов таким образом есть проблемы:

  • Объекты, используемые таким образом, не могут содержать методы не рискуя коллизией.
  • Из-за первого пункта, программы должны использовать Object.create(null) вместо простого <> , или внимательно следить чтобы встроенные методы (типа Object.prototype.toString ) не интерпретировались как данные.
  • Ключами могут быть только строки (strings) или, в случае ES6, символы. Объекты ключами быть не могут.
  • Нет эффективного способа получить количество свойств (properties) у объекта.

Опять-таки, во многих программах это не важно и можно продолжать использовать обычные объекты. Map и Set — для остальных случаев. Для защиты от коллизий между данными и встроенными свойствами (properties), коллекции в ES6 не выставляют данные как свойства. Это значит что нельзя добраться до данных с помощью выражений типа obj.key или obj[key] . Придется писать map.get(key) . Также, записи в хэш-таблице (в отличие от свойств) не наследуются с помощью прототипной цепочки (prototype chain).
Преимущество в том, что Map и Set , в отличие от обычных объектов, могут иметь методы, как стандартные, так и кастомные без конфликтов.

Set

Set — это множество значений. Оно изменяемо, поэтому элементы можно добавлять и удалять. Выглядит как простой массив, не так ли? Но есть различия.

Во-первых, Set , в отличие от массива, никогда не содержит один элемент дважды. Если попытаться добавить существующее значение, ничего не произойдет.

> var desserts = new Set("abcd"); > desserts.size 4 > desserts.add("a"); Set [ "a", "b", "c", "d" ] > desserts.size 4 

Примечание: в оригинале использовались emoji, которые проблемно скопировать. Смысл в любом случае тот же.

В примере выше используются строки, но Set может содержать любые объекты. И, как и со строками, при попытке добавления дубликата, ничего не добавится.

Во-вторых, Set хранит данные таким образом, что проверка наличия элемента во множестве выполняется очень быстро.

> // Проверяем, является ли "zythum" словом. > arrayOfWords.indexOf("zythum") !== -1 // медленно true > setOfWords.has("zythum") // быстро true 

Индексирование в Set не доступно.

> arrayOfWords[15000] "anapanapa" > setOfWords[15000] // set индексы не поддерживает undefined 
  • new Set создает новое пустое множество.
  • new Set(iterable) создает множество и заполняет данными из любого итерируемого источника.
  • set.size возвращает кол-во элементов во множестве.
  • set.has(value) возвращает true если множество содержит данное значение.
  • set.add(value) добавляет элемент во множество. Как помните, если пытаться добавить существующий, ничего не произойдет.
  • set.delete(value) удаляет элемент из множества. Как и add(), возвращает ссылку на множество, что позволяет вызывать методы друг за другом (а-ля Fluid Interface — прим.)
  • set[Symbol.iterator]() возвращает новый итератор по значениям во множестве. Обычно не вызывается напрямую, но именно это делает множества итерируемыми. Значит, можно писать for (v of set) <. >и тд.
  • set.forEach(f) легче всего объяснить в коде. Это краткая запись следующего выражения:
for (let value of set) f(value, value, set); 

Я вам обещал на прошлой неделе пожаловаться по поводу новых коллекций в ES6. Пожалуй, начну. Как бы Set ни был хорош, есть методы которые неплохо было бы включить в следующие версии стандарта:

  • Функциональные хэлперы, которые есть в массивах типа ap(), .filter(), .some() и .every() .
  • Немутирующие операции set1.union(set2) и set1.intersection(set2).
  • Методы, которые оперируют многими значениями сразу, типа set.addAll(iterable), set.removeAll(iterable) и set.hasAll(iterable)

Из-за объема материала решил разделить на 2 части. Во второй части про Map и слабые коллекции.

  • javascript
  • ecmascript
  • front-end
  • mozilla
  • никто не читает теги.
  • Веб-разработка
  • JavaScript

Отличие коллекций от массивов

Мне кажется, что вы путаете понятия. Если вам достаточно функционала массива, то используйте его, проблем никаких. Но в коллекциях значительно больше возможностей найти что-то действительно подходящее под задачи.

Классический алгоритм выбора коллекции (для Java под рукой нет, у кого есть замените, но идея от этого не изменится):

введите сюда описание изображения

При этом массивы здесь находятся в блоке array . vector — это уже динамический массив ближе к ArrayList<> .

Безусловно любой алгоритм и любую структуру из коллекций можно реализовать самому, но зачем.

Непосредственно по вопросам:

В них больше функционала, делать это над массивами зачастую нецелесообразно (или плохое качество кода или долго реализовывать или требуют хорошего понимания алгоритмов).

Когда лучше использовать массивы, чем коллекции?

Когда нужно хранить набор данных фиксированного размера. Смотри картинку с выбором.

Отслеживать
28.5k 12 12 золотых знаков 58 58 серебряных знаков 118 118 бронзовых знаков
ответ дан 31 авг 2016 в 15:32
9,799 3 3 золотых знака 29 29 серебряных знаков 42 42 бронзовых знака

Давайте по порядку:

  1. Чем коллекции лучше массивов?

Если вы работаете с примитивными типами, и не хотите тратить время на boxing/unboxing , то массивы предпочтительнее. Но если вы используете обычные классы, то лучше воспользоваться коллекциями, потому что массивы коварианты. Т.е. с ними легко написать не type-safe код.

 Integer[] a1 = new Integer[10]; Object[] a2 = a1; a2[0] = "привет ArrayStoreException!"; 

При этом компилятор ни разу не скажет, что это не правильно.

  1. В чем преимущества коллекций над массивами?

Все зависит сильно от ваших задач. В коллекциях много различных структур данных, с разными свойствами. Например, Set — множество уникальных элементов, TreeSet — множество уникальных отсортированных элементов, List — список, сохраняющий порядок вставки, и т.д. Тут нельзя дать определенный ответ, тут скорее вопрос о целесообразности применения. Если вам в какой то момент не будет хватать простого массива, то смело используйте collection .

  1. Когда лучше использовать массивы, чем коллекции?

Массив — JS: Коллекции

Массив — это самая распространенная структура данных во всех языках программирования. В этом уроке мы узнаем, что такое массив и объект, а также подробно разберем встроенные методы для работы с массивами в JavaScript.

Что такое массив

Массив — это структура данных, которая содержит упорядоченный набор элементов и предоставляет произвольный доступ к своим элементам.

Рассмотрим пример массива:

У нас есть массив a , и у него длина n . Он проиндексирован — каждое его значение хранится под определенным номером. Они идут по порядку и начинаются с нуля. Первый индекс всегда нуль — это стандарт.

Последний индекс будет n-1 , так как количество элементов всегда на единицу больше, чем количество индексов.

Чтобы обратиться к элементам, нужно указать его имя и в квадратных скобках — индекс.

На изображении видно, что элементы идут подряд — это верное представление с точки зрения работы с массивом, но его реализация может отличаться. То, как физически массив хранится в памяти, зависит от языка программирования, там порядок набора элементов может быть другой. Но эти детали скрыты от разработчика, поэтому мы всегда представляем массив в виде элементов, которые идут друг за другом.

Определение массива в JavaScript

В JavaScript пустой массив создается с помощью квадратных скобок:

const arr1 = []; 

Если массив инициализируется какими-то значениями, то их нужно указать в квадратных скобках через запятую:

const arr2 = [1, 'string', <>, [3, NaN]]; 

В JavaScript и других динамических языках нет ограничений на типы этих значений. Здесь можно смешивать любые типы. При этом элементами массива могут быть сами массивы.

Чтобы обратиться к элементу, нужно после имени массива написать квадратные скобки и индекс:

arr2[0]; // 1 arr2[3]; //[3, NaN] 

В итоге мы получим значения, с которыми можем работать дальше.

Также мы можем запросить элемент, которого нет в массиве. Например, используем индекс 4 :

arr2[4]; // undefined 

У нас нет элемента с таким индексом. В результате мы не получим ошибку. В этом случае в JavaScript мы получаем undefined .

Что такое объект

В работе с массивами в JavaScript есть особенность:

const arr2 = [1, 'string', <>, [3, NaN]]; typeof arr2; // object 

С помощью операции typeof мы смотрим, какой тип у массива. Получаем object .

Дело в том, что когда мы создаем массив, то создается объект. Квадратные скобки заменяют такую конструкцию:

new Array(1, 'string', <>, [3, NaN]); 

Фактически мы создаем новый элемент с типом array , в котором через запятую перечисляем элементы внутри него, и он является объектом.

Array — это подтип объекта, который обладает определенными свойствами. Мы можем обращаться к нему, как к другим объектам. Например, array определяет свойство length , которое возвращает длину этого массива:

// length возвращает длину массива arr2.length; // 4 arr2['length']; // 4 

Свойство length обновляется автоматически. Например, если мы что-то добавляем или удаляем, то оно будет меняться в зависимости от того, что мы делаем.

При этом квадратные скобки при обращении к массиву не являются специфичными для массива. В примере мы обратились к свойству через квадратные скобки arr2[‘length’] — это работает. Также к свойствам можно обращаться через точку arr2.length . Оба варианта делают одно и то же.

Теперь представим, как бы мы определили массив в терминах объекта. Мы сделали объект, у которого ключи являются числовыми — как индексы:

const obj =  0: 1, 1: 'string', 2: <>, 3: [3, NaN] > console.log(obj[0]); // 1 

Этот объект по своему виду соответствует массиву, который разобрали выше. Используются те же значения.

Если обратиться к нему также через скобки и поставить туда индекс 0, то мы получим единицу. Это работает практически как массив. Массив синтаксически ничего не добавляет кроме конструкции [] , которая заменяет new Array() . Все остальное — это часть типа данных object в JavaScript. Из-за того, что они смешиваются в одну сущность, это добавляет некоторые неожиданные эффекты, с которыми мы познакомимся позже.

В большинстве языков программирования массивы так не пересекаются с объектами, так как являются разными типами данных. Например, в PHP вообще нет массивов, а есть только объекты или так называемые ассоциативные массивы, с которыми мы тоже познакомимся попозже.

Что можно делать с массивом

Рассмотрим манипуляции, которые можно делать с массивом в JavaScript:

  • Обновление
  • Произвольное добавление
  • Последовательное добавление
  • Удаление
  • Добавление и удаление элементов в начале или конце массива
  • Итерация
  • Функции высшего порядка
  • Другие функции

Разберем каждый метод подробнее.

Обновление

Мы можем переустановить значение любого элемента в массиве. Для этого обращаемся к соответствующему индексу и приравниваем его:

const arr = [1, 'string', [3, 2]]; arr[0] = 'hello'; arr[0]; // hello arr.length; // 3 

Синтаксис такой же, как и с константами переменными. Мы просто присваиваем новое значение в индекс массива arr[0] = ‘hello’ . Если мы потом выведем его, то увидим новое значение hello . При этом длина массива не изменилась, так как мы просто заменили значение под индексом 0.

В данном примере используется const , а не let . Мы сохраняем в константе массив, и константа не меняется. Мы всегда работаем через константу с одним и тем же массивом.

При этом JavaScript не гарантирует, что сам массив не будет меняться. Мы можем изменить его добавлением, удалением или заменой каких-то элементов. Но сам массив остается тот же. Поэтому, если у нас не происходит замены всего массива на новый, то нужно всегда использовать const . Это применимо и к другим типам данных.

Напомним, что const пишется один раз при создании массива.

Произвольное добавление

Также мы можем делать произвольное добавление. Нам необязательно добавлять значение в тот индекс, который уже существует. Например:

const arr = [1, 'string', <>]; arr[5] = 'world' ; 

Здесь мы добавляем значение не в последний индекс. Сейчас их у нас три, а мы добавляем значение world в индекс 5.

В этом случае мы не получим ошибку. Если распечатать массив, то можно увидеть следующее:

console.log(arr); // [1, 'string', <>, , , 'world' ] 

Если мы выведем длину массива, то она будет равна 6:

arr.length; // 6 

Получается, что пустые места — это реальные элементы — чем-то заполнились. Если мы попытаемся вывести на экран значение под индексом 4, то получим undefined :

arr[4]; // undefined 

Сам элемент существует, но его значение равно undefined . Если мы обращаемся к индексу, которого не существует, то тоже получаем undefined .

Получается, что в одном случае индекс с элементом есть, а в другом случае индекса нет. Но мы в любом случае получаем undefined .

Иногда разница в этих значениях есть, и ее нужно учитывать. А иногда ее нет. Главное помнить, что undefined не всегда означает, что этого индекса не существует. Там действительно может лежать значение undefined .

Последовательное добавление

Чтобы добавить что-то в массив, используют метод push :

const arr = [1, 'string', <>]; arr.push(10); 

push берет последний индекс, прибавляет к нему единицу и размещает по этому индексу то значение, которое мы передаем в push .

Если распечатать его, то мы получим 10:

arr[3]; // 10 // длина массива увеличивается на единицу: arr.length; // 4 

Это стандартный подход при работе с массивом.

Удаление

При работе с массивами есть механизм удаления элемента, но он работает не так, как ожидается:

// Создаем массив const arr = [1, 'string', <>]; // Используем специальную конструкцию delete, в которой передаем элемент массива с индексом delete arr[1]; // Длина массива не изменилась arr.length; // 3 // Элемент стал undefined arr[1]; // undefined 

Вместо удаления элемента происходит его очистка, а значением элемента становится undefined .

Если распечатать, то увидим пропущенное значение:

console.log(arr); // [ 1, , <> ] 

Удалять что-то из массива — это плохая практика, которая может приводить к проблемам. О них мы поговорим позже. Поэтому так не стоит делать.

Если вам нужно получить массив, в котором отсутствуют какие-то элементы, то нужно применять фильтрацию. По факту нужно сформировать новый массив и добавить в него только те элементы из оригинального массива, которые нам нужны.

Добавление и удаление элементов в начало или конец массива

Чтобы добавить или удалить элементы в начало или конец массива, используются методы shift , unshift , pop и push . Эта группа методов позволяет работать с массивом как с очередью — метод доступа FIFO, или стеком — метод доступа LIFO. Рассмотрим это на примере:

// Инициализируем демонстрационный массив const planets = ['Mercury', 'Venus', 'Earth', 'Mars']; 

Очередь является упорядоченным набором данных, организованным по принципу FIFO — first in — first out. То есть элементы всегда добавляются в конец очереди, а удаляются из ее начала:

// push добавляет один или несколько элементов в конец массива // и возвращает длину измененного (мутированного) массива // (если точнее, то метод возвращает обновленное свойство length массива, // которое является значением последнего индекса, увеличенным на единицу) planets.push('Jupiter'); // 5 planets.push('Saturn', 'Uranus'); // 7 console.log(planets); // => [ 'Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus' ] // shift удаляет первый элемент массива и возвращает его значение planets.shift(); // удалили элемент из начала массива, возвращаемое значение: 'Mercury' planets.shift(); // еще раз удалили элемент из начала массива, возвращаемое значение: 'Venus' console.log(planets); // => [ 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus' ] 

Стек является упорядоченным набором данных, организованным по принципу LIFO — last in — first out. То есть элементы добавляются и удаляются всегда из конца такой коллекции:

// Добавим элемент в конец массива уже известным нам способом planets.push('Neptune'); // 6 console.log(planets); // => [ 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune' ] // pop удаляет последний элемент массива и возвращает его значение planets.pop(); // 'Neptune' planets.pop(); // 'Uranus' console.log(planets); // => [ 'Earth', 'Mars', 'Jupiter', 'Saturn' ] 

Итерация

Классический способ итерации для императивных языков — это цикл. В JavaScript много циклов, для работы с массивами часто применяется for…of :

const iterable = [10, 20, 30]; for (const value of iterable)  // В value каждый раз оказывается текущее значение по порядку console.log(value); > // 10 // 20 // 30 

Функции высшего порядка

Канонический способ работы с коллекциями в JavaScript — функции высшего порядка.

Представим, что у нас есть массив numbers :

const numbers = [1, 4, 9]; 

Мы хотим выполнить с ним стандартные операции: map , filter , reduce и reduceRight :

Пример работы с map :

const roots = numbers.map((value) => Math.sqrt(value)); // Передаем в map анонимную функцию, внутри которой вызываем `Math.sqrt()` и передаем в него текущее значение из списка `value` console.log(roots); // [1, 2, 3] 
const roots = numbers.map(Math.sqrt); console.log(roots); // [1, 2, 3] 

В JavaScript все функции являются объектами первого рода, и мы можем их передавать как аргументы. Во втором примере мы вызываем метод map на массиве numbers и передаем туда саму функцию Math.sqrt() , так как она принимает тот же параметр, что и наша функция-обертка.

В итоге получаются корни — roots . Если их распечатать, у нас появляется 1, 2, 3.

Следующий пример — это фильтрация:

// Передаем анонимную функцию, которая выбирает элементы больше 3 const filtered = numbers.filter(n => n > 3); console.log(filtered); // [4, 9] 

Если мы распечатаем получившийся массив, то получим 4,9, так как у нас единица меньше 3, она сюда не попадает.

Наиболее комплексный пример из функций высшего порядка — это reduce :

const sum = numbers.reduce( // reduce принимает на вход два параметра. Первый — анонимная функция (acc, value, index, arr) => acc + value, // Второй параметр — начальный счетчик. В данном случае мы находим сумму, поэтому начальный счетчик равен нулю 0 ); console.log(sum); // 14 

В итоге возвращаем тело функции в преобразованный новый аккумулятор и считаем сумму элементов массива. Если его распечатать, то получаем 14.

У анонимной функции достаточно много параметров. В JavaScript это сделано для удобства. Чаще всего используются только первые два параметра. Список параметров:

  • acc — аккумулятор
  • value — значение текущего, которое обрабатывается
  • index — индекс, что может быть полезно в определенных случаях
  • arr — сам массив

Пример работы с reduceRight :

// reduceRight — зеркальное отражение reduce, осуществляет свертку, обрабатывая элементы справа налево const planets = ['Меркурий', 'Венера', 'Земля', 'Марс']; const closer = planets.reduceRight((acc, planet) => `$acc> $planet>`, 'всё ближе к Солнцу:'); // 'всё ближе к Солнцу: Марс Земля Венера Меркурий' const further = planets.reduce((acc, planet) => `$acc> $planet>`, 'всё дальше от Солнца:'); // 'всё дальше от Солнца: Меркурий Венера Земля Марс' 

Другие функции

Чтобы строки превратить в массив, а также сделать обратное, используют split и join :

const planets = 'Mercury,Venus,Earth,Mars'; console.log(planets.split(',')); // => [ 'Mercury', 'Venus', 'Earth', 'Mars' ] console.log(planets.split(',').join('-')); // => 'Mercury-Venus-Earth-Mars' 

Поиск в массиве и проверка соблюдения условий элементами массива производится с помощью find , findIndex , indexOf , lastIndexOf , some , every , includes и так далее. Например:

// includes определяет наличие элемента в массиве, возвращая true/false const planets = ['Mercury', 'Venus', 'Earth', 'Mars']; planets.includes('Earth'); // true planets.includes('Earth', 3); // ищет с третьей индексной позиции, поэтому false planets.includes('Saturn'); // false 

Сортировка массива происходит с помощью sort , reverse .

const planets = ['Mercury', 'Venus', 'Earth', 'Mars'] planets.sort(); // ['Earth', 'Mars', 'Mercury', 'Venus'] planets.reverse(); // ['Venus', 'Mercury', 'Mars', 'Earth'] 

Разберем еще один метод flat() . Он делает содержимое вложенных элементов-массивов исходного массива элементами самого исходного массива. Он словно выравнивает массив. Посмотрим на код:

const arr = [1, 2, [1.1, 1.2, [2.1, [3.1, 3.2]]], 3]; // метод не изменяет исходный массив, а возвращает новый, поэтому результат присваиваем в новую переменную const flattenArr = arr.flat(); console.log(flattenArr); // => [1, 2, 1.1, 1.2, [2.1, [3.1, 3.2]], 3] 

Как видно из предыдущего примера, нам удалось выровнять все элементы на один уровень ниже лежащих массивов. При этом элементы более глубоко лежащих массивов остались невыровненными.

Можно управлять уровнем глубины выравнивания, который указывается в параметре метода:

console.log(arr.flat(1)); // => [1, 2, 1.1, 1.2, [2.1, [3.1, 3.2]], 3] console.log(arr.flat(2)); // => [1, 2, 1.1, 1.2, 2.1, [3.1, 3.2], 3] console.log(arr.flat(3)); // => [1, 2, 1.1, 1.2, 2.1, 3.1, 3.2, 3] Для полного выравнивания нужно передать в параметр `Infinity`: ```javascript const flattenDeepArr = arr.flat(Infinity); console.log(flattenDeepArr); // => [1, 2, 1.1, 1.2, 2.1, 3.1, 3.2, 3] 

Библиотека lodash

Существуют библиотеки, которые позволяют пользоваться множеством готовых функций. Одной из наиболее актуальных на текущей момент Javascript-библиотек является lodash . В ней реализованы различные функции по работе с массивами, коллекциями, строками и другими объектами языка.

Эта библиотека предоставляет большое количество функций высшего порядка, которые поддерживают функциональный стиль программирования. Подробнее ознакомиться со всеми возможностями lodash можно на сайте библиотеки .

Изменяемость VS Неизменяемость

Изменить объект в императивном стиле, когда можно писать код в неизменяемом — часто является не самым удачным решением. Это ведет к изменению состояния программы и усложняет ее. Поэтому, когда изучаете методы, всегда обращайте внимание, изменяют ли они исходный массив или нет.

Например, большинство примененных к массиву функций высшего порядка результатом возвращают новый массив. При этом они оставляют исходный нетронутым. Метод sort , как сказано в документации , необратимым образом модифицирует исходный массив. Поэтому такую сортировку лучше сделать на копии массива, если нам не нужно, чтобы исходный массив менялся.

Возьмем для примера типичную ситуацию, когда необходимо добавить новый элемент в массив. Рассмотрим, как справиться с этой задачей на примeре изменяющего метода push и неизменяющего concat :

push

const colours = ['red', 'orange', 'yellow']; colours.push('green'); // возвращаемое значение: 4 console.log(colours); // теперь colours - [ 'red', 'orange', 'yellow', 'green' ] 

push добавляет один или более элементов в конец массива, тем самым изменяет его, и возвращает новую длину массива.

concat

const colours = ['red', 'orange', 'yellow']; const myFavColours = colours.concat('green'); console.log(colours); // colours остался неизменен — [ 'red', 'orange', 'yellow' ] console.log(myFavColours); // новый массив myFavColours — [ 'red', 'orange', 'yellow', 'green' ] // аргументом можно передать и массив значений console.log(myFavColours.concat(myFavColours)); // => [ 'red', 'orange', 'yellow', 'green', 'red', 'orange', 'yellow', 'green' ] 

concat возвращает новый массив, который содержит элементы исходного массива и элементы, переданные в качестве аргументов.

Выводы

В этом уроке мы узнали, что такое массив. Это структура данных, которая содержит упорядоченный набор элементов и предоставляет произвольный доступ к своим элементам. Также мы рассмотрели манипуляции, которые можно делать с массивом в JavaScript. К ним относятся:

  • Обновление
  • Произвольное добавление
  • Последовательное добавление
  • Удаление
  • Добавление и удаление элементов в начале или конце массива

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов

Наши выпускники работают в компаниях:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *