Array.isArray
Массивы не образуют отдельный тип языка. Они основаны на объектах.
Поэтому typeof
не может отличить простой объект от массива:
alert(typeof {}); // object
alert(typeof []); // тоже object
…Но массивы используются настолько часто, что для этого придумали специальный метод: Array.isArray(value). Он возвращает true
, если value
массив, и false
, если нет.
alert(Array.isArray({})); // false
alert(Array.isArray([])); // true
Большинство методов поддерживают «thisArg»
Почти все методы массива, которые вызывают функции – такие как find
, filter
, map
, за исключением метода sort
, принимают необязательный параметр thisArg
.
Этот параметр не объяснялся выше, так как очень редко используется, но для наиболее полного понимания темы мы обязаны его рассмотреть.
Вот полный синтаксис этих методов:
arr.find(func, thisArg);
arr.filter(func, thisArg);
arr.map(func, thisArg);
// ...
// thisArg - это необязательный последний аргумент
Значение параметра thisArg
становится this
для func
.
Например, вот тут мы используем метод объекта army
как фильтр, и thisArg
передаёт ему контекст:
let army = {
minAge: 18,
maxAge: 27,
canJoin(user) {
return user.age >= this.minAge && user.age < this.maxAge;
}
};
let users = [
{age: 16},
{age: 20},
{age: 23},
{age: 30}
];
// найти пользователей, для которых army.canJoin возвращает true
let soldiers = users.filter(army.canJoin, army);
alert(soldiers.length); // 2
alert(soldiers[0].age); // 20
alert(soldiers[1].age); // 23
Если бы мы в примере выше использовали просто users.filter(army.canJoin)
, то вызов army.canJoin
был бы в режиме отдельной функции, с this=undefined
. Это тут же привело бы к ошибке.
Вызов users.filter(army.canJoin, army)
можно заменить на users.filter(user => army.canJoin(user))
, который делает то же самое. Последняя запись используется даже чаще, так как функция-стрелка более наглядна.
Итого
Шпаргалка по методам массива:
- Для добавления/удаления элементов:
push (...items)
– добавляет элементы в конец,pop()
– извлекает элемент с конца,shift()
– извлекает элемент с начала,unshift(...items)
– добавляет элементы в начало.splice(pos, deleteCount, ...items)
– начиная с индексаpos
, удаляетdeleteCount
элементов и вставляетitems
.slice(start, end)
– создаёт новый массив, копируя в него элементы с позицииstart
доend
(не включаяend
).concat(...items)
– возвращает новый массив: копирует все члены текущего массива и добавляет к немуitems
. Если какой-то изitems
является массивом, тогда берутся его элементы.
- Для поиска среди элементов:
indexOf/lastIndexOf(item, pos)
– ищетitem
, начиная с позицииpos
, и возвращает его индекс или-1
, если ничего не найдено.includes(value)
– возвращаетtrue
, если в массиве имеется элементvalue
, в противном случаеfalse
.find/filter(func)
– фильтрует элементы через функцию и отдаёт первое/все значения, при прохождении которых через функцию возвращаетсяtrue
.findIndex
похож наfind
, но возвращает индекс вместо значения.
- Для перебора элементов:
forEach(func)
– вызываетfunc
для каждого элемента. Ничего не возвращает.
- Для преобразования массива:
map(func)
– создаёт новый массив из результатов вызоваfunc
для каждого элемента.sort(func)
– сортирует массив «на месте», а потом возвращает его.reverse()
– «на месте» меняет порядок следования элементов на противоположный и возвращает изменённый массив.split/join
– преобразует строку в массив и обратно.reduce(func, initial)
– вычисляет одно значение на основе всего массива, вызываяfunc
для каждого элемента и передавая промежуточный результат между вызовами.
- Дополнительно:
Array.isArray(arr)
проверяет, является лиarr
массивом.
Обратите внимание, что методы sort
, reverse
и splice
изменяют исходный массив.
Изученных нами методов достаточно в 99% случаев, но существуют и другие.
- arr.some(fn)/arr.every(fn) проверяет массив.Функция
fn
вызывается для каждого элемента массива аналогичноmap
. Если какие-либо/все результаты вызовов являютсяtrue
, то метод возвращаетtrue
, иначеfalse
. - arr.fill(value, start, end) – заполняет массив повторяющимися
value
, начиная с индексаstart
доend
. - arr.copyWithin(target, start, end) – копирует свои элементы, начиная со
start
и заканчиваяend
, в собственную позициюtarget
(перезаписывает существующие).
Полный список есть в справочнике MDN.
На первый взгляд может показаться, что существует очень много разных методов, которые довольно сложно запомнить. Но это гораздо проще, чем кажется.
Внимательно изучите шпаргалку, представленную выше, а затем, чтобы попрактиковаться, решите задачи, предложенные в данной главе. Так вы получите необходимый опыт в правильном использовании методов массива.
Всякий раз, когда вам будет необходимо что-то сделать с массивом, а вы не знаете, как это сделать – приходите сюда, смотрите на таблицу и ищите правильный метод. Примеры помогут вам всё сделать правильно, и вскоре вы быстро запомните методы без особых усилий.
Практика
Перемешайте массив
важность: 3
Напишите функцию shuffle(array)
, которая перемешивает (переупорядочивает случайным образом) элементы массива.
Многократные прогоны через shuffle
могут привести к разным последовательностям элементов. Например:
let arr = [1, 2, 3];
shuffle(arr);
// arr = [3, 2, 1]
shuffle(arr);
// arr = [2, 1, 3]
shuffle(arr);
// arr = [3, 1, 2]
// ...
Все последовательности элементов должны иметь одинаковую вероятность. Например, [1,2,3]
может быть переупорядочено как [1,2,3]
или [1,3,2]
, или [3,1,2]
и т.д., с равной вероятностью каждого случая.
Переведите текст вида border-left-width в borderLeftWidth
важность: 5
Напишите функцию camelize(str)
, которая преобразует строки вида «my-short-string» в «myShortString».
То есть дефисы удаляются, а все слова после них получают заглавную букву.
Примеры:
camelize("background-color") == 'backgroundColor';
camelize("list-style-image") == 'listStyleImage';
camelize("-webkit-transition") == 'WebkitTransition';
P.S. Подсказка: используйте split
, чтобы разбить строку на массив символов, потом переделайте всё как нужно и методом join
соедините обратно.
Фильтрация по диапазону “на месте”
важность: 4
Напишите функцию filterRangeInPlace(arr, a, b)
, которая принимает массив arr
и удаляет из него все значения кроме тех, которые находятся между a
и b
. То есть, проверка имеет вид a ≤ arr[i] ≤ b
.
Функция должна изменять принимаемый массив и ничего не возвращать.
Например:
let arr = [5, 3, 8, 1];
filterRangeInPlace(arr, 1, 4); // удалены числа вне диапазона 1..4
alert( arr ); // [3, 1]