Arrays in Javascript
An array is a collection of values that are stored in contiguous memory locations. An array can hold values of any data type, including other arrays, objects, and functions. Each element in an array is identified by an index, starting from zero for the first element.
What are Iterables and Array-like objects
An iterable object is any object that has a [Symbol.iterator] property, which returns an iterator object. The iterator object must have a next() method that returns an object with value and done properties. e.g. Arrays, Strings, Sets, Maps, Generators.
You can check if an object is iterable or not by using the Symbol.iterator property. If an object has a Symbol.iterator property, then it is iterable.
An array-like object is an object that has a length property and contains elements with numeric indices, but is not actually an array. Examples of array-like objects include the arguments object and DOM collections like document.getElementsByTagName().
Here are some key differences between iterable and array-like objects:
- Iterable objects have a Symbol.iterator method that returns an iterator object, while array-like objects do not have this method.
- Iterable objects can be iterated over using a for. of loop or the Array.from() method, while array-like objects can be iterated over using a for loop or converted to an array using the Array.from() method.
- Iterable objects can be used with other iterable-specific methods, such as the entries() method, which returns an iterator over the [index, value] pairs of the iterable object. Array-like objects do not have these methods.
- Iterable objects can be created using the generator function, which allows for more flexible and customized iteration. Array-like objects are typically created by other functions or methods, such as querySelectorAll().
Some of the objects which are both Iterator and Array-like are NodeList, HTMLCollection, TypedArray and String.
Ways of Creating an Array
There are various ways of creating an Array in javascript. Let’s look at some of the most common ways to do so.
- Using square brackets notation: This is the most common way to create an array in JavaScript. It involves enclosing a list of elements in square brackets.
- Using the Array constructor: You can also create an array using the Array constructor, which takes a comma-separated list of values as arguments. The point to note here if you just provide one argument as number to the constructor function, then it considers it as the length of the array and not the element.
- Using the Array.from() method: This method creates a new array from an iterable object (as discussed above), such as an array-like object or a string.
- Using the Array.of() method: This creates a new array with the specified number of elements, each initialized with the provided value.
Adding and Removing elements from an array
Adding Elements
- push() method: Adds one or more elements to the end of an array.
- unshift() method: Adds one or more elements to the beginning of an array.
- splice() method: Adds or removes elements from an array at a specified index. Performs inplace updations.
In the above example, splice() adds the value 4 at index 1 and removes 0 elements.
- concat() method: Returns a new array that combines two or more arrays.
Removing Elements
- pop() method: Removes the last element of an array and returns it.
- shift() method: Removes the first element of an array and returns it.
- splice() method: Removes elements from an array at a specified index.
In the above example, splice() removes 1 element at index 1.
- slice() method: Returns a new array that contains a portion of the original array.
In the above example, slice() returns a new array that contains elements from index 1 to index 4 (excluding index 4). The original array is not modified.
Finding a value in an array
- indexOf() method: Returns the index of the first occurrence of a specified element in an array, or -1 if the element is not found.
- lastIndexOf() method: Returns the index of the last occurrence of a specified element in an array, or -1 if the element is not found.
- find() method: Returns the value of the first element in an array that satisfies a specified condition, or undefined if no such element is found.
- filter() method: Returns a new array containing all elements in an array that satisfy a specified condition.
- includes() method: Returns true if an array contains a specified element, and false otherwise.
NOTE: indexOf() and lastIndexOf() methods doesn’t work well with reference types like object.
Sorting and Reversing Arrays
The sort() method is used to sort the elements of an array in place, i.e., it modifies the original array. The default sort order is based on the string Unicode code points. However, you can also specify a custom sort function as an argument to the sort() method.
Good to Know: sort() function uses tim sort alogrithm in backend to sort the elements.
The reverse() method is used to reverse the order of the elements of an array in place, i.e., it modifies the original array.
map, forEach, reduce methods
- map() function: The map function creates a new array by applying a given function to each element in the original array. The resulting array will have the same length as the original array, but each element will have been transformed in some way.
- forEach() function: The forEach function allows you to iterate over each element in an array and perform some action on it. This function does not create a new array; it simply executes a function for each element in the original array.
I’ve covered reduce method in this blog post since it require greater attention.
The Spread Operator and Array destructuring
Spread Operator
The Spread operator in JavaScript is denoted by three dots . . It allows an iterable (like an array or a string) to be expanded into individual elements. The Spread operator can be used in multiple ways:
- Expanding an array into individual elements:
- Passing an array as function arguments:
- Copying an array:
Array Destructuring
Array Destructuring is a way to unpack values from an array into separate variables. It allows you to assign array elements to variables in a concise and readable way. The syntax for Array Destructuring is also denoted by square brackets [].
Array Destructuring also allows you to set default values for variables
Array Destructuring can also be used with the Rest parameter to capture the remaining elements of an array
Array
Массив ( Array ) в JavaScript является глобальным объектом, который используется для создания массивов; которые представляют собой высокоуровневые спископодобные объекты.
Создание массива
Доступ к элементу массива по индексу
Итерирование по массиву
Добавление элемента в конец массива
Удаление последнего элемента массива
Удаление первого элемента массива
Добавление элемента в начало массива
Поиск номера элемента в массиве
Удаление элемента с определённым индексом
Удаление нескольких элементов, начиная с определённого индекса
Создание копии массива
Синтаксис
Массив в JavaScript инициализируется с помощью переданных элементов, за исключением случая, когда в конструктор Array передаётся один аргумент и этот аргумент является числом (см. ниже). Стоит обратить внимание, что этот особый случай применяется только к JavaScript-массивам, создаваемым с помощью конструктора Array , а не к литеральным массивам, создаваемым с использованием скобочного синтаксиса.
Если конструктору Array передаётся единственный аргумент, являющийся целым числом в диапазоне от 0 до 232-1 (включительно), будет возвращён новый пустой JavaScript-массив, длина которого установится в это число (примечание: это означает массив, содержащий arrayLength пустых ячеек, а не ячеек со значениями undefined ). Если аргументом будет любое другое число, возникнет исключение RangeError .
Описание
Массивы являются спископодобными объектами, чьи прототипы содержат методы для операций обхода и изменения массива. Ни размер JavaScript-массива, ни типы его элементов не являются фиксированными. Поскольку размер массива может увеличиваться и уменьшаться в любое время, то нет гарантии, что массив окажется плотным. То есть, при работе с массивом может возникнуть ситуация, что элемент массива, к которому вы обратитесь, будет пустым и вернёт undefined . В целом, это удобная характеристика; но если эта особенность массива не желательна в вашем специфическом случае, вы можете рассмотреть возможность использования типизированных массивов.
Некоторые полагают, что вы не должны использовать массив в качестве ассоциативного массива. В любом случае, вместо него вы можете использовать простые объекты , хотя у них есть и свои подводные камни. Смотрите пост Легковесные JavaScript-словари с произвольными ключами(англ.) в качестве примера.
Доступ к элементам массива
Массивы в JavaScript индексируются с нуля: первый элемент массива имеет индекс, равный 0 , а индекс последнего элемента равен значению свойства массива length минус 1.
Элементы массива являются свойствами, точно такими же, как, например, свойство toString , однако попытка получить элемент массива по имени его свойства приведёт к синтаксической ошибке, поскольку имя свойства не является допустимым именем JavaScript:
Это не особенность массивов или их свойств. В JavaScript к свойствам, начинающимся с цифры, невозможно обратиться посредством точечной нотации; к ним можно обратиться только с помощью скобочной нотации. Например, если у вас есть объект со свойством, названным ‘3d’ , вы сможете обратиться к нему только посредством скобочной нотации. Примеры:
Обратите внимание, что во втором примере 3d заключено в кавычки: ‘3d’ . Индексы можно заключать в кавычки (например years[‘2’] вместо years[2] ), но в этом нет необходимости. Значение 2 в выражении years[2] будет неявно приведено к строке движком JavaScript через метод преобразования toString . Именно по этой причине ключи ‘2’ и ’02’ будут ссылаться на два разных элемента в объекте years и следующий пример выведет true :
Аналогично, к свойствам объекта, являющимся зарезервированными словами(!) можно получить доступ только посредством скобочной нотации:
Взаимосвязь свойства length с числовыми свойствами
Свойство массивов length взаимосвязано с числовыми свойствами. Некоторые встроенные методы массива (например, join , slice , indexOf и т.д.) учитывают значение свойства length при своём вызове. Другие методы (например, push , splice и т.д.) в результате своей работы также обновляют свойство length массива.
При установке свойства в массиве, если свойство имеет действительный индекс и этот индекс выходит за пределы текущих границ массива, движок соответствующим образом обновит свойство length :
Увеличиваем свойство length
Однако, уменьшение свойства length приведёт к удалению элементов.
Более подробно эта тема освещена на странице, посвящённой свойству Array.length .
Создание массива с использованием результата сопоставления
Результатом сопоставления регулярного выражения строке является JavaScript-массив. Этот массив имеет свойства и элементы, предоставляющие информацию о сопоставлении. Подобные массивы возвращаются методами RegExp.exec , String.match и String.replace . Чтобы было проще понять, откуда и какие появились свойства и элементы, посмотрите следующий пример и обратитесь к таблице ниже:
Свойства и элементы, возвращаемые из данного сопоставления, описаны ниже:
| Свойство/Элемент | Описание | Пример |
|---|---|---|
| input | Свойство только для чтения, отражающее оригинальную строку, с которой сопоставлялось регулярное выражение. | cdbBdbsbz |
| index | Свойство только для чтения, являющееся индексом (отсчёт начинается с нуля) в строке, с которого началось сопоставление. | 1 |
| [0] | Элемент только для чтения, определяющий последние сопоставившиеся символы. | dbBd |
| [1], . [n] | Элементы только для чтения, определяющие сопоставившиеся подстроки, заключённые в круглые скобки, если те включены в регулярное выражение. Количество возможных подстрок не ограничено. | [1]: bB [2]: d |
Свойства
Значение свойства length конструктора массива равно 1.
Позволяет добавлять свойства ко всем объектам массива.
Методы
Создаёт новый экземпляр Array из массивоподобного или итерируемого объекта.
Возвращает true , если значение является массивом, иначе возвращает false .
Асинхронно наблюдает за изменениями в массиве, подобно методу Object.observe() для объектов. Метод предоставляет поток изменений в порядке их возникновения.
Создаёт новый экземпляр Array из любого количества аргументов, независимо от их количества или типа.
Массивы
Объекты позволяют хранить данные со строковыми ключами. Это замечательно.
Но довольно часто мы понимаем, что нам необходима упорядоченная коллекция данных, в которой присутствуют 1-й, 2-й, 3-й элементы и т.д. Например, она понадобится нам для хранения списка чего-либо: пользователей, товаров, элементов HTML и т.д.
В этом случае использовать объект неудобно, так как он не предоставляет методов управления порядком элементов. Мы не можем вставить новое свойство «между» уже существующими. Объекты просто не предназначены для этих целей.
Для хранения упорядоченных коллекций существует особая структура данных, которая называется массив, Array .
Объявление
Существует два варианта синтаксиса для создания пустого массива:
Практически всегда используется второй вариант синтаксиса. В скобках мы можем указать начальные значения элементов:
Элементы массива нумеруются, начиная с нуля.
Мы можем получить элемент, указав его номер в квадратных скобках:
Мы можем заменить элемент:
…Или добавить новый к существующему массиву:
Общее число элементов массива содержится в его свойстве length :
Вывести массив целиком можно при помощи alert .
В массиве могут храниться элементы любого типа.
Список элементов массива, как и список свойств объекта, может оканчиваться запятой:
«Висячая запятая» упрощает процесс добавления/удаления элементов, так как все строки становятся идентичными.
Получение последних элементов при помощи «at»
Допустим, нам нужен последний элемент массива.
Некоторые языки программирования позволяют использовать отрицательные индексы для той же цели, как-то так: fruits[-1] .
Однако, в JavaScript такая запись не сработает. Её результатом будет undefined , поскольку индекс в квадратных скобках понимается буквально.
Мы можем явно вычислить индекс последнего элемента, а затем получить к нему доступ вот так: fruits[fruits.length — 1] .
Немного громоздко, не так ли? Нам нужно дважды написать имя переменной.
К счастью, есть более короткий синтаксис: fruits.at (-1) :
Другими словами, arr.at(i) :
- это ровно то же самое, что и arr[i] , если i >= 0 .
- для отрицательных значений i , он отступает от конца массива.
Методы pop/push, shift/unshift
Очередь – один из самых распространённых вариантов применения массива. В области компьютерных наук так называется упорядоченная коллекция элементов, поддерживающая два вида операций:
- push добавляет элемент в конец.
- shift удаляет элемент в начале, сдвигая очередь, так что второй элемент становится первым.
Массивы поддерживают обе операции.
На практике необходимость в этом возникает очень часто. Например, очередь сообщений, которые надо показать на экране.
Существует и другой вариант применения для массивов – структура данных, называемая стек.
Она поддерживает два вида операций:
- push добавляет элемент в конец.
- pop удаляет последний элемент.
Таким образом, новые элементы всегда добавляются или удаляются из «конца».
Примером стека обычно служит колода карт: новые карты кладутся наверх и берутся тоже сверху:
Массивы в JavaScript могут работать и как очередь, и как стек. Мы можем добавлять/удалять элементы как в начало, так и в конец массива.
В компьютерных науках структура данных, делающая это возможным, называется двусторонняя очередь.
Методы, работающие с концом массива:
Удаляет последний элемент из массива и возвращает его:
И fruits.pop() и fruits.at(-1) возвращают последний элемент массива, но fruits.pop() также изменяет массив, удаляя его.
Добавляет элемент в конец массива:
Вызов fruits.push(. ) равнозначен fruits[fruits.length] = . .
Методы, работающие с началом массива:
Удаляет из массива первый элемент и возвращает его:
Добавляет элемент в начало массива:
Методы push и unshift могут добавлять сразу несколько элементов:
Внутреннее устройство массива
Массив – это особый подвид объектов. Квадратные скобки, используемые для того, чтобы получить доступ к свойству arr[0] – это по сути обычный синтаксис доступа по ключу, как obj[key] , где в роли obj у нас arr , а в качестве ключа – числовой индекс.
Массивы расширяют объекты, так как предусматривают специальные методы для работы с упорядоченными коллекциями данных, а также свойство length . Но в основе всё равно лежит объект.
Следует помнить, что в JavaScript существует 8 основных типов данных. Массив является объектом и, следовательно, ведёт себя как объект.
Например, копируется по ссылке:
…Но то, что действительно делает массивы особенными – это их внутреннее представление. Движок JavaScript старается хранить элементы массива в непрерывной области памяти, один за другим, так, как это показано на иллюстрациях к этой главе. Существуют и другие способы оптимизации, благодаря которым массивы работают очень быстро.
Но все они утратят эффективность, если мы перестанем работать с массивом как с «упорядоченной коллекцией данных» и начнём использовать его как обычный объект.
Например, технически мы можем сделать следующее:
Это возможно, потому что в основе массива лежит объект. Мы можем присвоить ему любые свойства.
Но движок поймёт, что мы работаем с массивом, как с обычным объектом. Способы оптимизации, используемые для массивов, в этом случае не подходят, поэтому они будут отключены и никакой выгоды не принесут.
Варианты неправильного применения массива:
- Добавление нечислового свойства, например: arr.test = 5 .
- Создание «дыр», например: добавление arr[0] , затем arr[1000] (между ними ничего нет).
- Заполнение массива в обратном порядке, например: arr[1000] , arr[999] и т.д.
Массив следует считать особой структурой, позволяющей работать с упорядоченными данными. Для этого массивы предоставляют специальные методы. Массивы тщательно настроены в движках JavaScript для работы с однотипными упорядоченными данными, поэтому, пожалуйста, используйте их именно в таких случаях. Если вам нужны произвольные ключи, вполне возможно, лучше подойдёт обычный объект <> .
Эффективность
Методы push/pop выполняются быстро, а методы shift/unshift – медленно.
Почему работать с концом массива быстрее, чем с его началом? Давайте посмотрим, что происходит во время выполнения:
Просто взять и удалить элемент с номером 0 недостаточно. Нужно также заново пронумеровать остальные элементы.
Операция shift должна выполнить 3 действия:
- Удалить элемент с индексом 0 .
- Сдвинуть все элементы влево, заново пронумеровать их, заменив 1 на 0 , 2 на 1 и т.д.
- Обновить свойство length .
Чем больше элементов содержит массив, тем больше времени потребуется для того, чтобы их переместить, больше операций с памятью.
То же самое происходит с unshift : чтобы добавить элемент в начало массива, нам нужно сначала сдвинуть существующие элементы вправо, увеличивая их индексы.
А что же с push/pop ? Им не нужно ничего перемещать. Чтобы удалить элемент в конце массива, метод pop очищает индекс и уменьшает значение length .
Действия при операции pop :
Метод pop не требует перемещения, потому что остальные элементы остаются с теми же индексами. Именно поэтому он выполняется очень быстро.
Аналогично работает метод push .
Перебор элементов
Одним из самых старых способов перебора элементов массива является цикл for по цифровым индексам:
Но для массивов возможен и другой вариант цикла, for..of :
Цикл for..of не предоставляет доступа к номеру текущего элемента, только к его значению, но в большинстве случаев этого достаточно. А также это короче.
Технически, так как массив является объектом, можно использовать и вариант for..in :
Но на самом деле это – плохая идея. Существуют скрытые недостатки этого способа:
Цикл for..in выполняет перебор всех свойств объекта, а не только цифровых.
В браузере и других программных средах также существуют так называемые «псевдомассивы» – объекты, которые выглядят, как массив. То есть, у них есть свойство length и индексы, но они также могут иметь дополнительные нечисловые свойства и методы, которые нам обычно не нужны. Тем не менее, цикл for..in выведет и их. Поэтому, если нам приходится иметь дело с объектами, похожими на массив, такие «лишние» свойства могут стать проблемой.
Цикл for..in оптимизирован под произвольные объекты, не массивы, и поэтому в 10-100 раз медленнее. Увеличение скорости выполнения может иметь значение только при возникновении узких мест. Но мы всё же должны представлять разницу.
В общем, не следует использовать цикл for..in для массивов.
Немного о «length»
Свойство length автоматически обновляется при изменении массива. Если быть точными, это не количество элементов массива, а наибольший цифровой индекс плюс один.
Например, единственный элемент, имеющий большой индекс, даёт большую длину:
Обратите внимание, что обычно мы не используем массивы таким образом.
Ещё один интересный факт о свойстве length – его можно перезаписать.
Если мы вручную увеличим его, ничего интересного не произойдёт. Зато, если мы уменьшим его, массив станет короче. Этот процесс необратим, как мы можем понять из примера:
Таким образом, самый простой способ очистить массив – это arr.length = 0; .
new Array()
Существует ещё один вариант синтаксиса для создания массива:
Он редко применяется, так как квадратные скобки [] короче. Кроме того, у него есть хитрая особенность.
Если new Array вызывается с одним аргументом, который представляет собой число, он создаёт массив без элементов, но с заданной длиной.
Давайте посмотрим, как можно оказать себе медвежью услугу:
Как мы видим, в коде, представленном выше, в new Array(number) все элементы равны undefined .
Чтобы избежать появления таких неожиданных ситуаций, мы обычно используем квадратные скобки, если, конечно, не знаем точно, что по какой-то причине нужен именно Array .
Многомерные массивы
Массивы могут содержать элементы, которые тоже являются массивами. Это можно использовать для создания многомерных массивов, например, для хранения матриц:
toString
Массивы по-своему реализуют метод toString , который возвращает список элементов, разделённых запятыми.
Disclaimer
![]()
This article will be among a series of article on JavaScript and front-end development that I’m making. These articles are meant to be relatively simple, concise and free of excess jargon. Also, please note that not all array methods are mentioned (You can find them here JavaScript Array Reference), only the ones I believe are practically more commonly used than others.
Also, if you find any mistakes, please give me a heads up by pointing them out in the comments or by sending me an email: haleesammar@gmail.com
Background
An array is a data structure of an indexed collection of values. Unlike many other languages (such as C++ and C); JS array elements are not confined to being of the same data type. Different elements within the same array may have different types.
Declaring Arrays
There are 3 different ways for creating arrays in JS:
1. Array Literal syntax (Recommended)
Notice how the array elements are not necessarily of the same data type. One of them is even a function, which by the way, may be invoked by first accessing the index of the function element within the array, and then invoking it as a function:
2. Using the “new” keyword (Not conventional)
3. On the fly (Created when a function is called)
An array is created when it’s passed to a function that takes an array as its parameter. Or more precisely; the array is created and gets stored in memory when that function is evoked and currently resides on the execution stack.
In the above code; an array got created as soon as a call is made to displayArray .
Before moving any further: Remember that:
Array elements can be accessed (for either read or write) using square brackets.
Array Methods
There are several ways of categorizing array methods. I found the most convenient way is to categorize them based whether or not these methods mutate (change) the original array. I then sub-categorized these methods based on their return type.
1. Array Methods which do not alter the original array
2. Array Methods which alter the original array
Most array methods require at least 1 mandatory argument. Most also have -optional arguments which can be useful. Other methods require non at all.
In many cases; that mandatory argument is a callback function, which will run for each element in the array, with that element as its input.
It is conventional to use ES6’s arrow function syntax for the cb function.
As a developer, you will find yourself using some methods more frequently than others. Let’s examine some of these methods in more detail:
- Purpose: Iterate over the array elements.
- Input: A callback function to run for each array element.
- Output: A new array of mapped elements.
- Modifies the Original Array? No.
filter
- Purpose: Iterate over the array elements, filtering out certain elements
- Input: A callback function to run for each array element. This function would have some kind of conditional logic to determine whether or not an element fits a specific filtering criteria.
- Output: A new array of filtered elements. Elements that fulfill the condition.
- Modifies the Original Array? No.
concat
- Purpose: Merge two or more arrays.
- Input: Arrays to be merged with the original array.
- Output: A new merged array.
- Modifies the Original Array? No.
Watch out because order matters:
splice
- Purpose: Removes/Adds elements at a specified index in the array.
- Input:
- Start Index (Mandatory)
- Number of elements to be removed starting from the specified index (Optional)
- New elements to be add in place of the removed elements (Optional)
- Output: An array of the removed elements.
- Modifies the Original Array? Yes.
In the above example: we passed 1 as the start index and 1 as the number of elements to be removed starting from there, but we didn’t specify any elements to be inserted in place of the removed elements. This code above will result in the following:
a) The removal of the element at index 1.
b) The indexes of all array elements after the removed element will be updated.
c) The length of the original array is updated.
Therefore, array1 becomes: [“a”, “g”, “c”, “d”] .
What if we don’t want to remove elements, only add?
We simply set the second argument to 0 (Which basically means that we want to remove 0 elements), and set the rest of the arguments with our desired elements to-be-added:
What if we specify only the mandatory first argument?
In that case: all elements starting from the start index, will be removed:
slice
- Purpose: Removes elements at a specified index in an array.
- Input:
1.Start Index (Mandatory) ,
2. Number of elements to be removed starting from the specified index (Optional)
- Output: An array of the removed elements.
- Modifies the Original Array? No.
slice is quite similar to splice, except that:
- slice only removes elements, does not add.
- slice does not modify the original array on which the method is applied, instead, it creates a copy of the “sliced” array elements.
One odd thing about slice which you may have noticed is that the second optional parameter is count -1. For example, consider the code above:
You’d expect that 2 elements to be removed starting from index 1. But in reality; the second parameter is count -1. This is just something to keep in mind when using this method.
forEach
- Purpose: Iterate over the array elements.
- Input: A callback function to run for each array element.
- Output: undefined
- Modifies the Original Array? No.
forEach is similar to other iterative methods like map and filter But unlike those: it does not return an array: it returns undefined .So use it when you want to produce a side-effect and not when you need a return value.
find
- Purpose: Finds, then returns the first element in the array that passes the condition provided by the callback function.
- Input: A callback function that will run for each array element and test that element against a condition (Mandatory)
- Output: The first element that passes that condition (if found). Or undefined if no such element exists.
- Modifies the Original Array? No.
When the element is found for the first time; the method stops executing and returns.
findLast
- Purpose: Finds the last element in an array that passes the condition provided by the callback function.
- Input: A callback function that will run for each array element and test that element against a condition (Mandatory)
- Output: The first element that passes that condition (if found). Or undefined if no such element exists.
- Modifies the Original Array? No.
When the element is found for the first time; the method stops executing and returns.
indexOf
- Purpose: Finds, then returns the index of the first element in the array that matches the passed element.
- Input:
- The element whose index we want (Mandatory)
- Start Index (Optional).
- Output: The index of the element (if found) or -1 if none is found.
- Modifies the Original Array? No.
- The passed element may only be a primitive value (String, Number etc.) . For instance we can’t attempt to get the index of an object element within the array using the indexOf method. There’s another method for that.
- Notice that in the above code: there are multiple occurrences of 7 , but the indexOf method will return the index of the first found 7 only.
findIndex
- Purpose: Finds, then returns the index of the first element in the array that passes a condition provided by the callback function.
- Input: A callback function that will run for each array element and test that element against a condition (Mandatory)
- Output: The index of the element (if found) or -1 if none is found.
- Modifies the Original Array? No.
Similar to indexOf ; This method’s job is to find the index of a certain element.
- It takes a callback function as a parameter enabling a more dynamic approach to search. This is especially useful when you don’t know exactly what you’re looking for and you only know that it fits within a known approximate range of description.
- With findIndex ; we are able to search for more complex types such as objects through maybe a property attached to them.
Examine the following:
Searching through an array of Objects, using the age property as our anchor.
includes
- Purpose: Checks whether or not an array contains the passed element.
- Input:
- The element whose existence in the array we’re investigating (Mandatory)
- The index from which to start (Optional).
- Output: true if the element is found. false if the element is not found.
- Modifies the Original Array? No.
The above example will return false because although the array does include a 3 , twice, we defined the start index to be 5 . No 3 can be found in the array starting from index 5 and on.
This method is quite useful. However, there’s a pitfall in the fact that: just like in the indexOf case; we are not able to pass a callback function. We have to pass the specific element; a primitive. This prevents us from performing more complex querying i.e. querying that is reliant on a condition or a range. This also prevents us from searching through an array of complex types such as objects.
We’ll see how we can take care of that in the upcoming method…
- Purpose: Checks whether or not an array contains at least one element which passes the condition provided by the callback function
- Input: A callback function that will run for each array element and test that element against a condition (Mandatory)
- Output: true if at least one element passes the condition provided by the callback function. false otherwise.
- Modifies the Original Array? No.
The above example will return true because at least one element in the array is less than 3 .
some can be used in the same way as includes but with extended functionality by allowing us to pass call back function and therefore enabling us to search through an array of objects.
every
- Purpose: Checks if all the elements in the array pass the condition provided by the callback function
- Input: A callback function that will run for each array element and test that element against a condition (Mandatory)
- Output: true if all the elements pass the condition provided by the callback function. false otherwise.
- Modifies the Original Array? No.
push
- Purpose: Adds items to the end of the array
- Input: Items to be added: item1, item2, …, itemX
- Output: New length of the array
- Modifies the Original Array? Yes.
unshift
- Purpose: Adds items to the start of the array
- Input: Items to be added: item1, item2, …, itemX
- Output: New length of the array
- Modifies the Original Array? Yes.
- Purpose: Removes items from the end of the array
- Input: none
- Output: The removed item
- Modifies the Original Array? Yes.
shift
- Purpose: Removes items from the start of the array
- Input: none
- Output: The removed item
- Modifies the Original Array? Yes.
- Purpose: Re-arrange array elements in a particular order, based upon the return value of the compare function.
- Input: Compare Function (Optional)
- Output: A new sorted array
- Modifies the Original Array? No.
Using sort without the compare function parameter
When we supply no parameters to sort ; it will revert to its underlying sorting mechanism: that is to convert the array elements intro strings and then to arrange them in an ascending order, based upon their corresponding UTF-16 code points (The character encoding scheme JavaScript uses).
But that puts a lot of limitations, doesn’t it? I mean, what if we don’t want to sort our string array in ascending order? What if our array elements aren’t even strings?
And besides, in UTF-16 encoding code point representation: Capital letters are chronologically lower than small letters. Of course you could work around that by converting the string to lowercase using toLowerCase .
Using sort with the compare function parameter
Now that we have established that in order to perform any meaningful or real world sorting operation on arrays you need use a compare function; let’s see how they work:
The compare callback function takes two parameters representing the two numbers being compared (Because that’s part of how the in-space algorithm works; Only two elements are compared at a time) and returns either a positive number or a negative number or 0 . Based on the return value of the compare function: sort will decide how to arrange the elements:
- If the return value of compareFunction(x,y) is negative : place x in a lower index than y .
- If the return value of compareFunction(x,y) is positive : place x in a higher index than y .
- If the return value of compareFunction(x,y) is 0 : don’t change order.
So, you as a programmer , are tasked with designing how sort should behave, by deciding when the compare function returns (- or+ or 0).
Example : Sorting an array of numbers in a descending Order:
A nice shortcut to the above code is to simply return the subtract result between a and b because that will either be (- or+ or 0) and so it will give the same result.
Just a thought: What if there are undefined values in your array? What happens to them?
undefined values get sorted to the end of the array.
Reduce
- Purpose: Reduce an array into a single value by accumulating its elements.
- Input:
- Reducer function (Mandatory)
- initial value (Optional)
The reducer function takes the following input:
- Accumulator ( acc ) — mandatory: A value which persists across each iteration. It also gets updated at each iteration. At the end: the accumulator value becomes the result of the reduce.
- Current Value ( cur )- mandatory : the current element we are at.
- Current Index ( idx)
- Source Array ( src )
- Output: A single value
- Modifies the Original Array? No.
If no initial value is provided:
Then the accumulator is initialized as the fist element and the currentval starts at the second element.
Bonus: Modern Array Methods and Techniques
Recent JS releases have brought along an interesting number of new array features and methods:
- Purpose: Gets rid of nesting in arrays
- Input: The depth of nesting to be flattened (default is 1 level deep)
- Output: The new flattened array.
- Alters Original Array? No, It creates a shallow copy.
As the name suggests; flat flattens the array.
Prior to that, we used concat.apply :
flat provides a cleaner, more readable syntax. Let’s take a look:
Flattening is useful in scenarios where it is needed to expose the elements of an inner array, to the outer array. But of course, it depends on the case as maybe it is within your intention to create a nested array.
If there’s more nesting which you would like to be flattened; you can always specify the depth by passing it as a parameter:
In the first example the depth was 1 , but that’s the default so we don’t need to pass anything.
Additional Usage for flat :
flat can also be used to get rid of gaps (empty elements) in the array:
flatMap
- Purpose: Gets rid of nesting in arrays upon mapping an array.
- Input: The depth of nesting to be flattened (default is 1 level deep)
- Output: The new flattened array.
- Alters Original Array? No, It creates a shallow copy.
As the name suggests; flatMap combines the functionality of flat and map . flat is performed immediately after map . This has many benefits especially in linear algebra where there’s frequent mapping to 2-D matrices.
copyWithin
- Purpose: Shallow copies a part of the array to another part within the same array, without altering the length of the array.
- Input:
- Target index : Where should the copied portion get transferred to.
- Start Index (Optional): What is the start index of the copied portion.
- End index (Optional): What is the end index of the copied portion.
- Output: The new array.
- Alters Original Array? Yes.
The method is useful when you need to perform relatively complex array alterations in which parts of the array must replace others. Check out this example:
The start index is 2 . The end index is 4 . The end index is count -1, so the copied portion is an array from index 2 to index 3 (2 elements).
The target index is 1 ; so that copied portion will be placed in the array starting from index 1 . This will cause two elements to be replaced with the copied array elements, starting from index 1. The result is:
Notice how, elements before the start index and elements after the end index -1 , were not affected.
Different (exceptional) argument cases:
- If no start index is specified: The portion will be copied from index 0 and will end at the specified end index (if any):
- If no end index is specified: The portion will be copied from the specified startindex (if any)and will end at the index Array.length (because remember : end index is count -1)
- If neither a start index or an end index is specified (Effectively no arguments are passed): Then the copied portion would be the whole array, and that would be useless.
- If a negative target value is supplied; then the index will be counted backwards (starting from the end), with -1 (not 0 ,cause that’s reserved to the forward index count) being the first reverse index.
End of Part I.
Stay tuned for part II where we’ll discuss more array methods as well as different topics surrounding arrays. Thank you for sticking around \( * ‘- ‘ *)/