Reduce() js
Содержание:
- Что изучать?
- Работа с массивами JS — метод slice
- Добавление или удаление элементов массива в любой позиции
- Работа с массивами JS — удаление из массива
- Метод Object.keys()
- JavaScript
- Работа с массивами в JS:
- JavaScript
- Добавление/удаление элементов
- reduce
- forEach
- Коллекция Map
- Объект как ассоциативный массив
- Пишем свой метод reduce на JavaScript
- Эффективность
- Symbol.iterator
Что изучать?
Java — это такой промышленный язык. На нём работают терминалы оплаты, умные устройства, огромные серверные системы. Мир потных инженеров, серверных комнат и финансовых рынков. Если хотите, чтобы у вас была работа по поддержке и совершенствованию всего этого хозяйства на много лет вперёд — вам сюда.
JavaScript — это в первую очередь язык для веба. На нём можно очень быстро написать простое веб-приложение, быстро его распространить, быстро заработать денег. Если вам нужно много небольшой работы прямо сейчас или вы хотите запускать собственные веб-приложения как предприниматель, начинайте с JavaScript.
И не забывайте, что можно переходить с одного языка на другой. Не сказать, что переход с JavaScript на Java будет простым, но это выполнимо.
История Java и JavaScript в общих чертах выглядит так.
Начало девяностых. В компании Sun Microsystems пилят язык программирования, который можно будет использовать для умных устройств — телеприставок, холодильников и всякого такого. Задача была придумать такую систему, чтобы код писался один раз, а исполнять его можно было бы на разном железе. В 1995 году выходят первые версии этого языка, он называется Java.
Параллельно с этим в другой области идёт война браузеров. Технологии веба ещё очень слабые, плохо стандартизированные, HTML ещё мало что умеет, дизайна мало. В ходу несколько браузеров, каждый из которых рисует веб-страницы по-своему. Один из этих браузеров — Netscape Navigator.
Создатели Netscape Navigator мечтают, чтобы браузеры умели красиво себя вести; чтобы там был интерактив и анимации; чтобы в браузере можно было запускать программы и делать хотя бы простые вещи (а не только читать). И они разрабатывают технологию Mocha — язык скриптования, который умел работать напрямую с веб-страницей. В те времена это было ново и интересно.
Слово за слово, Netscape входит в состав Sun Microsystems, и в порыве маркетингового креатива язык Mocha переименовывают в JavaScript, чтобы попиарить одно на другом. Якобы JavaScript — это компаньон Java для веба (хотя разрабатывали JavaScript совсем другие люди и с другими задачами).
Пиар не зашёл. Лет пять разработчики плевались из-за кажущейся кривизны JavaScript и общего разлада в веб-технологиях. Уже позднее, в двухтысячных, началась бескомпромиссная стандартизация веб-технологий (огнём и мечом), и всё постепенно наладилось. Но осадочек остался.
А похожие названия языков — это то, что бывает, когда маркетологов пускают в программирование. Не надо так.
Работа с массивами JS — метод slice
Можно извлечь часть массива с помощью метода slice(begin): var arr = ; var arr2 = arr.slice(0,2) // принимает 2 элемента, начиная с 0 alert(arr2.join(', ')) // "Why, learn"
Обратите внимание, что этот метод не изменяет в JavaScript количество элементов в массиве, а копирует его часть. Можно опустить второй аргумент, чтобы получить все элементы, начиная с определенного индекса:
Можно опустить второй аргумент, чтобы получить все элементы, начиная с определенного индекса:
var arr = ; var arr2 = arr.slice(1) // принимает все элементы, начиная с 1 alert(arr2.join(', ')) // "learn, JavaScript"
Метод поддерживает отрицательные индексы, так же, как String#slice.
Добавление или удаление элементов массива в любой позиции
Метод splice() — это очень универсальный метод массива, который позволяет добавлять или удалять элементы любого индекса, используя синтаксис arr.splice(startIndex, deleteCount, elem1, …, elemN).
Этот метод принимает три параметра: первый параметр — это индекс, с которого начинается объединение массива (обязателен); второй параметр — количество удаляемых элементов (используйте 0, если вы не хотите удалять какие-либо элементы) (параметр необязательный), и третий параметр представляет собой набор заменяющих элементов, он также является необязательным. В следующем примере показано, как это работает:
var colors = ; var removed = colors.splice(0,1); // Удалить первый элемент document.write(colors); // Результат: Green,Blue document.write(removed); // Результат: Red (массив из одного элемента) document.write(removed.length); // Результат: 1 removed = colors.splice(1, 0, "Pink", "Yellow"); // Вставить два элемента начиная с позиции 1 document.write(colors); // Результат: Green,Pink,Yellow,Blue document.write(removed); // Пустой массив document.write(removed.length); // Результат: 0 removed = colors.splice(1, 1, "Purple", "Voilet"); // Вставить два элемента, удалить один document.write(colors); // Результат: Green,Purple,Voilet,Yellow,Blue document.write(removed); // Результат: Pink (массив из одного элемента) document.write(removed.length); // Результат: 1
Метод splice() возвращает массив удаленных элементов или пустой массив, если элементы не были удалены, как вы можете видеть в приведенном выше примере. Если второй аргумент опущен, все элементы от начала до конца массива удаляются. В отличие от методов slice() и concat(), метод splice() модифицирует массив, для которого он вызывается.
Работа с массивами JS — удаление из массива
Как мы знаем, массивы — это объекты, поэтому мы могли бы использовать delete, чтобы удалить значение:
var arr = delete arr // теперь arr = alert(arr) // не задано
Вы видите, что значение удаляется, но не так, как мы хотели бы, потому что массив содержит незаданный элемент.
Оператор delete удаляет пару ключ-значение, и это все. Естественно, так как массив — это только хэш, позиция удаленного элемента становится undefined.
Чаще всего нам нужно удалить элемент, не оставляя «дыр» между индексами. Существует еще один метод, который поможет нам в этом.
Метод splice
Метод splice может удалять элементы и заменять их в JavaScript многомерных массивах. Его синтаксис:
arr.splice(index, deleteCount)
Удаляет элемент deleteCount, начиная с index, а затем вставляет на его место elem1, …, elemN.
Давайте рассмотрим несколько примеров:
var arr = arr.splice(1, 1) // удалить 1 элемент, начиная с индекса 1 alert( arr.join(',') ) // (1 элемент удален)
Таким образом, вы можете использовать splice, чтобы удалить один элемент из массива. Номера элементов массива сдвигаются, чтобы заполнить пробел:
var arr = arr.splice(0, 1) // удаляем 1 элемент, начиная с индекса 0 alert( arr ) // "to" стал первым элементом
В следующем примере показано, как заменять элементы:
var arr = ; // remove 3 first elements and add two arr.splice(0, 3, "Come", "here") alert( arr ) //
Метод splice возвращает массив удаленных элементов:
var arr = ; // удаляем 2 первых элемента var removed = arr.splice(0, 2) alert( removed ) // "Go", "to" <-- массив удаленных элементов splice может вставлять элементы, задайте 0 для deleteCount. var arr = ; // со второй позиции // удаляем 0 // и вставляем "my", "sweet" arr.splice(2, 0, "my", "sweet") alert( arr) // "Go", "to", "my", "sweet", "home"
Данный метод также может использовать отрицательный индекс, который отсчитывается с конца массива:
var arr = // для элемента -1 (предпоследнего) // удаляем 0 элементов, // и вставляем 3 и 4 arr.splice(-1, 0, 3, 4) alert(arr) // 1,2,3,4,5
Задание для самостоятельного выполнения
Объект содержит свойство className, в котором содержатся имена классов, разделенные пробелами:
var obj = { className: 'open menu' }
Напишите функцию removeClass(obj, cls), которая удаляет класс cls, если он задан:
removeClass(obj, 'open') // obj.className='menu' removeClass(obj, 'blabla') // без изменений (класса для удаления не существует)
Решение
Нужно разделить className на части и перебрать эти части через цикл. Если найдено совпадение, оно удаляется из JavaScript массива объектов, а затем добавляется обратно в конец.
Немного оптимизируем это:
function removeClass(elem, cls) { for(var c = elem.className.split(' '), i=c.length-1; i>=0; i--) { if (c == cls) c.splice(i,1) } elem.className = c.join(' ') } var obj = { className: 'open menu' } removeClass(obj, 'open') removeClass(obj, 'blabla') alert(obj.className) // menu
В приведенном выше примере переменная c задана в начале цикла, и для i задан ее последний индекс.
Сам цикл выполняется в обратном направлении, заканчиваясь условием i>=0. Это сделано потому, что i>=0 проверяется быстрее, чем i. Что ускоряет поиск свойства в c.
Метод Object.keys()
Очень часто требуется произвести итерацию по свойствам объекта.
Здесь нам приходит на помощь метод , который позволяет создать новый массив из ключей нашего объекта.
1const car ={ 2 name'bmw', 3 model'x2', 4 year2020, 5 engine'2.0T', 6 color'red', 7 country'Germany', 8}; 9const carData =Object.keys(car); 10console.log(carData); 11
Если нам нужно создать массив не из ключей, а значений, то можно использовать метод .
1const car ={ 2 name'bmw', 3 model'x2', 4 year2020, 5 engine'2.0T', 6 color'red', 7 country'Germany', 8}; 9const carData =Object.values(car); 10console.log(carData); 11
JavaScript
JS Массивы
concat()
constructor
copyWithin()
entries()
every()
fill()
filter()
find()
findIndex()
forEach()
from()
includes()
indexOf()
isArray()
join()
keys()
length
lastIndexOf()
map()
pop()
prototype
push()
reduce()
reduceRight()
reverse()
shift()
slice()
some()
sort()
splice()
toString()
unshift()
valueOf()
JS Булевы
constructor
prototype
toString()
valueOf()
JS Классы
constructor()
extends
static
super
JS Даты
constructor
getDate()
getDay()
getFullYear()
getHours()
getMilliseconds()
getMinutes()
getMonth()
getSeconds()
getTime()
getTimezoneOffset()
getUTCDate()
getUTCDay()
getUTCFullYear()
getUTCHours()
getUTCMilliseconds()
getUTCMinutes()
getUTCMonth()
getUTCSeconds()
now()
parse()
prototype
setDate()
setFullYear()
setHours()
setMilliseconds()
setMinutes()
setMonth()
setSeconds()
setTime()
setUTCDate()
setUTCFullYear()
setUTCHours()
setUTCMilliseconds()
setUTCMinutes()
setUTCMonth()
setUTCSeconds()
toDateString()
toISOString()
toJSON()
toLocaleDateString()
toLocaleTimeString()
toLocaleString()
toString()
toTimeString()
toUTCString()
UTC()
valueOf()
JS Ошибка
name
message
JS Булевы
decodeURI()
decodeURIComponent()
encodeURI()
encodeURIComponent()
escape()
eval()
Infinity
isFinite()
isNaN()
NaN
Number()
parseFloat()
parseInt()
String()
undefined
unescape()
JS JSON
parse()
stringify()
JS Математика
abs()
acos()
acosh()
asin()
asinh()
atan()
atan2()
atanh()
cbrt()
ceil()
cos()
cosh()
E
exp()
floor()
LN2
LN10
log()
LOG2E
LOG10E
max()
min()
PI
pow()
random()
round()
sin()
sqrt()
SQRT1_2
SQRT2
tan()
tanh()
trunc()
JS Числа
constructor
isFinite()
isInteger()
isNaN()
isSafeInteger()
MAX_VALUE
MIN_VALUE
NEGATIVE_INFINITY
NaN
POSITIVE_INFINITY
prototype
toExponential()
toFixed()
toLocaleString()
toPrecision()
toString()
valueOf()
JS ОператорыJS Рег.Выражения
constructor
compile()
exec()
g
global
i
ignoreCase
lastIndex
m
multiline
n+
n*
n?
n{X}
n{X,Y}
n{X,}
n$
^n
?=n
?!n
source
test()
toString()
(x|y)
.
\w
\W
\d
\D
\s
\S
\b
\B
\0
\n
\f
\r
\t
\v
\xxx
\xdd
\uxxxx
JS Заявления
break
class
continue
debugger
do…while
for
for…in
for…of
function
if…else
return
switch
throw
try…catch
var
while
JS Строки
charAt()
charCodeAt()
concat()
constructor
endsWith()
fromCharCode()
includes()
indexOf()
lastIndexOf()
length
localeCompare()
match()
prototype
repeat()
replace()
search()
slice()
split()
startsWith()
substr()
substring()
toLocaleLowerCase()
toLocaleUpperCase()
toLowerCase()
toString()
toUpperCase()
trim()
valueOf()
Работа с массивами в JS:
Теперь перейдём к работе с массивом, для начала посмотрим как получить элемент массива, его можно взять ро индексу.
Важно:
В JavaScript индексация начинается с нуля.
JavaScript
1 2 3 4 5 |
// Создаём массив let arr=»Яблоко»,»Персик»,»Банан»; console.log(arr1); |
Как видите, у нас вывелся второй элемент, хоть и использовали индекс один, это всё потому что, индексация начинается с нуля.
Также мы можете вывести все элементы массива, для этого нужно использовать цикл.
JavaScript
1 2 3 4 5 6 7 |
// Создаём массив let arr=»Яблоко»,»Персик»,»Банан»; for(leti=;i<arr.length;i++){ console.log(arri);// Выводим элемент в консоль } |
Здесь всё крайне просто, в цикле мы выводим каждый элемент, самое интересное, это условие, при котором он должен работать, там мы используем метод , который возвращает количество данных.
То есть цикл будет работать, пока строга меньше трёх, в нашем случае.
Также вы можете изменять элемент массива как вам надо, для этого просто используете нужный индекс и присваиваете ему значение на которое нужно изменить.
Default
1 2 3 4 5 6 7 8 9 |
// Создаём массив let arr=»Яблоко»,»Персик»,»Банан»; arr1=»Киви»; for(leti=;i<arr.length;i++){ console.log(arri);// Выводим элемент в консоль } |
Вот что выведется:
Методы работы с массивами в JS:
Также кроме есть другие методы для работы с массивами в JavaScript, здесь покажу только самые основные, их четыре.
- push() — Добавляет элемент в конец массива;
- pop() — Удаляет элемент в конце массива;
- unshift() — Добавляем элемент в начала массива;
- shift() — Удаляем из массива первый элемент;
- splice() — Заменяет или удаляет элементы
- concat() — Объединяет массивы;
- farEach() — Перебор массива;
Это те методы которые вы будите пользоваться чаще всего, вот пару примеров работы с ними.
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 |
// Создаём массив let arr=»Яблоко»,»Персик»,»Банан»; arr.push(«Киви») // Удаляем элемент в начале массива arr.shift() for(leti=;i<arr.length;i++){ console.log(arri);// Выводим элемент в консоль } |
Здесь мы просто не много изменяем массив, сначала добавляем в конец слово «Киви», а потом удаляем элемент из начала, вот что должно получится.
Как видите вывод массива изменился, в конец добавилось слово, а в начала удалилось.
Вот этот пример покажет как происходит в JavaScript удаление элемента массива или его замена.
JavaScript
1 2 3 4 5 6 7 8 9 10 |
// Создаём массив let arr=»Яблоко»,»Персик»,»Банан»; arr.splice(1,1); for(leti=;i<arr.length;i++){ console.log(arri);// Выводим элемент в консоль } |
Здесь мы уже используем метод , первый параметр, это с какого индекса удалять элемент, второй, количество удаляемых элементов.
Ещё благодаря этому методу, можете заменять элементы.
JavaScript
1 2 3 4 5 6 7 8 9 10 |
// Создаём массив let arr=»Яблоко»,»Персик»,»Банан»; arr.splice(1,2,»Груша»,»Киви»); for(leti=;i<arr.length;i++){ console.log(arri);// Выводим элемент в консоль } |
Тут после параметра который отвечает за количество заменяемых элементов, просто перечисляем все элементы которые мы хотим добавить, и даже не важно какого типа
Последнее что мы рассмотрим, это как в JavaScript перебрать массив и объединить его с другим массивом.
JavaScript
1 2 3 4 5 6 7 8 9 10 11 |
// Создаём массив let arr=»Яблоко»,»Персик»,»Банан»; arr=arr.concat(«Груша»,»Киви») arr.forEach(function(item,key){ // Вывод элемента и его индекса в консоль console.log(`${item}имеетиндекс${key}`); }) |
В начале мы как всегда создаём новый массив, потом с помощью метода , который приминается к массиву, внутри в качестве параметра принимает ещё один массив, возвращает уже объединённый массив данных, мы же присваиваем это значение уже созданному.
Дальше с помощью метода мы перебираем, внутри в качестве параметра используем функцию, которая принимает в себя ещё два параметра, это , значение элемента и , его индекс.
Выводим весь массив в консоль, вот что получилось.
Как видите, у нас вывелся объединённый массив, то есть, всё правильно работает.
JavaScript
JS Array
concat()
constructor
copyWithin()
entries()
every()
fill()
filter()
find()
findIndex()
forEach()
from()
includes()
indexOf()
isArray()
join()
keys()
length
lastIndexOf()
map()
pop()
prototype
push()
reduce()
reduceRight()
reverse()
shift()
slice()
some()
sort()
splice()
toString()
unshift()
valueOf()
JS Boolean
constructor
prototype
toString()
valueOf()
JS Classes
constructor()
extends
static
super
JS Date
constructor
getDate()
getDay()
getFullYear()
getHours()
getMilliseconds()
getMinutes()
getMonth()
getSeconds()
getTime()
getTimezoneOffset()
getUTCDate()
getUTCDay()
getUTCFullYear()
getUTCHours()
getUTCMilliseconds()
getUTCMinutes()
getUTCMonth()
getUTCSeconds()
now()
parse()
prototype
setDate()
setFullYear()
setHours()
setMilliseconds()
setMinutes()
setMonth()
setSeconds()
setTime()
setUTCDate()
setUTCFullYear()
setUTCHours()
setUTCMilliseconds()
setUTCMinutes()
setUTCMonth()
setUTCSeconds()
toDateString()
toISOString()
toJSON()
toLocaleDateString()
toLocaleTimeString()
toLocaleString()
toString()
toTimeString()
toUTCString()
UTC()
valueOf()
JS Error
name
message
JS Global
decodeURI()
decodeURIComponent()
encodeURI()
encodeURIComponent()
escape()
eval()
Infinity
isFinite()
isNaN()
NaN
Number()
parseFloat()
parseInt()
String()
undefined
unescape()
JS JSON
parse()
stringify()
JS Math
abs()
acos()
acosh()
asin()
asinh()
atan()
atan2()
atanh()
cbrt()
ceil()
clz32()
cos()
cosh()
E
exp()
expm1()
floor()
fround()
LN2
LN10
log()
log10()
log1p()
log2()
LOG2E
LOG10E
max()
min()
PI
pow()
random()
round()
sign()
sin()
sinh()
sqrt()
SQRT1_2
SQRT2
tan()
tanh()
trunc()
JS Number
constructor
isFinite()
isInteger()
isNaN()
isSafeInteger()
MAX_VALUE
MIN_VALUE
NEGATIVE_INFINITY
NaN
POSITIVE_INFINITY
prototype
toExponential()
toFixed()
toLocaleString()
toPrecision()
toString()
valueOf()
JS OperatorsJS RegExp
Modifiers:
g
i
m
Groups:
(x|y)
Metacharacters:
.
\w
\W
\d
\D
\s
\S
\b
\B
\0
\n
\f
\r
\t
\v
\xxx
\xdd
\uxxxx
Quantifiers:
+
*
?
{X}
{X,Y}
{X,}
$
^
?=
?!
Properties:
constructor
global
ignoreCase
lastIndex
multiline
source
Methods:
compile()
exec()
test()
toString()
JS Statements
break
class
continue
debugger
do…while
for
for…in
for…of
function
if…else
return
switch
throw
try…catch
var
while
JS String
charAt()
charCodeAt()
concat()
constructor
endsWith()
fromCharCode()
includes()
indexOf()
lastIndexOf()
length
localeCompare()
match()
prototype
repeat()
replace()
search()
slice()
split()
startsWith()
substr()
substring()
toLocaleLowerCase()
toLocaleUpperCase()
toLowerCase()
toString()
toUpperCase()
trim()
valueOf()
Добавление/удаление элементов
Мы уже знаем методы, которые добавляют и удаляют элементы из начала или конца:
- – добавляет элементы в конец,
- – извлекает элемент из конца,
- – извлекает элемент из начала,
- – добавляет элементы в начало.
Есть и другие.
Как удалить элемент из массива?
Так как массивы – это объекты, то можно попробовать :
Вроде бы, элемент и был удалён, но при проверке оказывается, что массив всё ещё имеет 3 элемента .
Это нормально, потому что всё, что делает – это удаляет значение с данным ключом . Это нормально для объектов, но для массивов мы обычно хотим, чтобы оставшиеся элементы сдвинулись и заняли освободившееся место. Мы ждём, что массив станет короче.
Поэтому для этого нужно использовать специальные методы.
Метод arr.splice(str) – это универсальный «швейцарский нож» для работы с массивами. Умеет всё: добавлять, удалять и заменять элементы.
Его синтаксис:
Он начинает с позиции , удаляет элементов и вставляет на их место. Возвращает массив из удалённых элементов.
Этот метод проще всего понять, рассмотрев примеры.
Начнём с удаления:
Легко, правда? Начиная с позиции , он убрал элемент.
В следующем примере мы удалим 3 элемента и заменим их двумя другими.
Здесь видно, что возвращает массив из удалённых элементов:
Метод также может вставлять элементы без удаления, для этого достаточно установить в :
Отрицательные индексы разрешены
В этом и в других методах массива допускается использование отрицательного индекса. Он позволяет начать отсчёт элементов с конца, как тут:
Метод arr.slice намного проще, чем похожий на него .
Его синтаксис:
Он возвращает новый массив, в который копирует элементы, начиная с индекса и до (не включая ). Оба индекса и могут быть отрицательными. В таком случае отсчёт будет осуществляться с конца массива.
Это похоже на строковый метод , но вместо подстрок возвращает подмассивы.
Например:
Можно вызвать и вообще без аргументов: создаёт копию массива . Это часто используют, чтобы создать копию массива для дальнейших преобразований, которые не должны менять исходный массив.
Метод arr.concat создаёт новый массив, в который копирует данные из других массивов и дополнительные значения.
Его синтаксис:
Он принимает любое количество аргументов, которые могут быть как массивами, так и простыми значениями.
В результате мы получаем новый массив, включающий в себя элементы из , а также , и так далее…
Если аргумент – массив, то все его элементы копируются. Иначе скопируется сам аргумент.
Например:
Обычно он просто копирует элементы из массивов. Другие объекты, даже если они выглядят как массивы, добавляются как есть:
…Но если объект имеет специальное свойство , то он обрабатывается как массив: вместо него добавляются его числовые свойства.
Для корректной обработки в объекте должны быть числовые свойства и :
reduce
Метод – также использует исходный массив для последовательной обработки каждого элемента.
С помощью данного метода можно сохранять промежуточный результат и возвращать новые объекты, массивы или, например, числа.
Пример .reduce #1
Чаще всего я использую , чтобы подсчитать общее количество или сумму чего-либо.
1const invoices =22,8,16,120; 2const totalInvoices = invoices.reduce((total, current)=>{ 3return total + current; 4}); 5console.log(totalInvoices); 6
Пример .reduce() #2
Еще один пример – учет количества экземпляров каждой единицы товара.
Давайте определим общее количество бананов, яблок и т.д. в нашем массиве:
1const fruits ='apples','bananas','oranges','apples','kiwi','apples'; 2const fruitsCount = fruits.reduce((accum, curVal)=>{ 3if(!accumcurVal){ 4 accumcurVal=1; 5return accum; 6} 7 accumcurVal+=1; 8return accum; 9},{}); 10 11console.log(fruitsCount); 12
forEach
Данный метод
перебирает элементы массива и при этом позволяет с ними выполнить какие-либо
действия. Имеет следующий синтаксис:
ar.forEach(function(item,
index, array) {
// … делать
что-то с item
});
Например, здесь
выводятся элементы массива в консоль:
let ar = "Я", "смотрю", "этот", "обучающий", "урок"; ar.forEach(function(item) { console.log(item); });
Обратите
внимание, что нам нет необходимости указывать все аргументы функции, достаточно
лишь те, что необходимы. В реализацию метода forEach очень хорошо
вписываются стрелочные функции, о которых мы говорили ранее, например так:
let dig = 1, 2, 3, 4, 5, 6, 7; dig.forEach( (item) => console.log(item) );
или так для
вывода только четных значений:
dig.forEach( (item, index) => { if(item % 2 == ) console.log(`${item} с индексом ${index}`); });
А вот так все
нечетные элементы можно заменить на 1:
dig.forEach( (item, index, array) => { if(item % 2 != ) arrayindex = 1; });
Далее мы
рассмотрим группу методов для поиска элементов в массиве.
Коллекция Map
– это коллекция «ключ-значение», которую можно использовать для создания ассоциативных массивов.
в отличие от объекта позволяет использовать в качестве ключей значения любых типов как примитивные, так и ссылочные.
Создание пустой коллекции:
Создании коллекции с инициализацией начальных значений:
В этом примере строки «key1», «key2» и «key3» являются ключами, а «value1», «value2» и «value3» соответственно их значениями.
Узнать количество элементов в массиве можно осуществить с помощью свойства :
arr.size; // 3
Добавление элемента в массив (в экземпляр объекта Map) осуществляется с помощью метода :
// добавить в массив одну пару "ключ-значение" arr.set('key4','value4'); // добавить в массив несколько пар "ключ-значение" arr.set('key5','value5'); arr.set('key6','value6'); // или так arr .set('key5','value5') .set('key6','value6');
Если в массиве есть уже такой ключ, то произойдёт установка нового значения, которое будет связано с ним:
arr.set('key1','new value');
Получить значение по ключу выполняется с помощью метода :
// получить значение, ассоциированное с ключом 'key4' arr.get('key4'); // 'value4'
Проверить есть ли ключ в массиве можно посредством метода :
// есть ли в массиве arr ключ key2 arr.has('key2'); // true
Удалить из ассоциативного массива (экземпляра объекта Map) элемент по имени ключа можно с помощью метода :
arr.delete('key1'); // true
Данный метод возвращает , если данный ключ существовал в массиве, в противном случае он возвращает .
if (arr.delete('key1')) { console.log('Запись с ключом "key1" удалена из массива!'); } else { console.log('Запись с ключом "key1" не найдена в массиве!'); }
Очистить массив (удалить все элементы) можно выполнить с помощью метода .
arr.clear(); // очистим массив arr arr.size; // 0 (количество элементов)
Перебор ассоциативного массива (объекта Map) обычно осуществляется с помощью цикла . При этом итерацию можно организовать по ключам, значениям и записям ().
Перебор ключей можно осуществить посредством итерируемого объекта , возвращаемым методом :
for (let key of arr.keys()) { console.log(key); }
Для перебора значений можно воспользоваться итерируемым объектом , возвращаемым посредством методом :
for (let value of arr.values()) { console.log(value); }
Перебор записей ассоциативного массива с использованием метода :
for (let pair of arr.entries()) { // pair - это массив console.log(pair); // ключ console.log(pair); // значение console.log(`Ключ = ${pair}, значение = ${pair}`); }
Данный метод используется по умолчанию в for…of, поэтому его можно опустить:
for (let pair of arr) { console.log(`Ключ = ${pair}, значение = ${pair}`); }
Кроме этого перебрать ассоциативный массив можно с помощью метода forEach.
arr.forEach(function(value,key) { console.log('key = ' + key +', value = ' + value); });
Преобразовать ассоциативный массив (объект Map) в JSON и обратно можно так:
let arr = new Map(, , , ]); // в JSON jsonStr = JSON.stringify(); // из JSON в Map mapArr = new Map(JSON.parse(jsonStr));
Объект как ассоциативный массив
В качестве ассоциативного массива можно использовать обычный объект.
Создание пустого ассоциативного массива через объект:
Заполнение ассоциативный массив значениями на этапе его создания:
Добавление нового элемента (пары «ключ-значение»):
Добавление нового элемента будет выполняться только в том случае, если данного ключа в нём нет. Если данный ключ уже существует, то указанное значение просто изменит существующее.
В качестве значения можно использовать не только примитивные типы данных, но и ссылочные.
В JavaScript для обращения к ключу можно использовать не только квадратные скобки, но и выполнять это через точку. Но это доступно только для ключей, имена которых отвечают правилам именования переменных.
Получение значения ключа:
Получить количество ключей (длину) можно так:
Удаление ключа выполняется с помощью оператора :
Выполнить проверку (наличия) ключа можно так:
Перебор ключей с помощью цикла :
Преобразовать объект, используем в качестве ассоциативного массива, в JSON и обратно можно так:
Пишем свой метод reduce на JavaScript
Мы разберем два примера: простой и более сложный, в котором будут обрабатываться ошибки и проверяться условия.
Первый пример:
Array.prototype.customReduce = function(callback, result) { let i = 0; // Проверяем если кол-во аргументов меньше 2, значит не передано дефолтное значение if (arguments.length < 2) { i = 1; // В данном случае this указывает на итерируемый массив result = this } for (; i < this.length; i++) { result = callback(result, this, i, this); } return result; }
Мы сразу добавили данный метод к прототипу массива, чтобы его можно было легко вызвать. Теперь проверим выдаст ли он нам такой же результат, как был в самом первом примере этого поста:
const salary = ; const sum = salary.customReduce((total, currentItem) => { total += currentItem; return total; }, 0); console.log('sum', sum); // 4900
Теперь давайте рассмотрим более сложный вариант с дополнительными проверками:
Array.prototype.customReduce = function(callBack, initialValue) { // Проверяем не пустой ли массив и задано ли дефолтное значение if (!this.length && initialValue === undefined) throw new TypeError('Массив пустой. Невозможно к нему применить данный метод'); // Если дефолтное значение задано, то присваиваем его к accumulator, который в итоге будем возвращать let accumulator = initialValue; let index = 0; if (initialValue === undefined) { // Если нет дефолтного значения, тогда accumulator будет присваиваться значение первого элемента массива accumulator = this; index = 1; } // В цикле проходимся по нашему массиву и передаем наш callback, который нужно выполнить для каждого элемента массива for (; index < this.length; index++) { // Как мы помним метод reduce принимает 4 параметра (см начало поста) // Поэтому мы в наш callback передаем такие же 4 параметра accumulator = callBack(accumulator, this, index, this); } return accumulator; }
Если остались вопросы — пишите в комментарии.
Эффективность
Методы выполняются быстро, а методы – медленно.
Почему работать с концом массива быстрее, чем с его началом? Давайте посмотрим, что происходит во время выполнения:
Просто взять и удалить элемент с номером недостаточно. Нужно также заново пронумеровать остальные элементы.
Операция должна выполнить 3 действия:
- Удалить элемент с индексом .
- Сдвинуть все элементы влево, заново пронумеровать их, заменив на , на и т.д.
- Обновить свойство .
Чем больше элементов содержит массив, тем больше времени потребуется для того, чтобы их переместить, больше операций с памятью.
То же самое происходит с : чтобы добавить элемент в начало массива, нам нужно сначала сдвинуть существующие элементы вправо, увеличивая их индексы.
А что же с ? Им не нужно ничего перемещать. Чтобы удалить элемент в конце массива, метод очищает индекс и уменьшает значение .
Действия при операции :
Метод не требует перемещения, потому что остальные элементы остаются с теми же индексами. Именно поэтому он выполняется очень быстро.
Аналогично работает метод .
Symbol.iterator
Мы легко поймём принцип устройства перебираемых объектов, создав один из них.
Например, у нас есть объект. Это не массив, но он выглядит подходящим для .
Например, объект , который представляет собой диапазон чисел:
Чтобы сделать итерируемым (и позволить работать с ним), нам нужно добавить в объект метод с именем (специальный встроенный , созданный как раз для этого).
- Когда цикл запускается, он вызывает этот метод один раз (или выдаёт ошибку, если метод не найден). Этот метод должен вернуть итератор – объект с методом .
- Дальше работает только с этим возвращённым объектом.
- Когда хочет получить следующее значение, он вызывает метод этого объекта.
- Результат вызова должен иметь вид , где означает, что итерация закончена, в противном случае содержит очередное значение.
Вот полная реализация с пояснениями:
Обратите внимание на ключевую особенность итераторов: разделение ответственности
- У самого нет метода .
- Вместо этого другой объект, так называемый «итератор», создаётся вызовом , и именно его генерирует значения.
Таким образом, итератор отделён от самого итерируемого объекта.
Технически мы можем объединить их и использовать сам как итератор, чтобы упростить код.
Например, вот так:
Теперь возвращает сам объект : у него есть необходимый метод , и он запоминает текущее состояние итерации в . Короче? Да. И иногда такой способ тоже хорош.
Недостаток такого подхода в том, что теперь мы не можем использовать этот объект в двух параллельных циклах : у них будет общее текущее состояние итерации, потому что теперь существует лишь один итератор – сам объект. Но необходимость в двух циклах , выполняемых одновременно, возникает редко, даже при наличии асинхронных операций.
Бесконечные итераторы
Можно сделать бесконечный итератор. Например, будет бесконечным при . Или мы можем создать итерируемый объект, который генерирует бесконечную последовательность псевдослучайных чисел. Это бывает полезно.
Метод не имеет ограничений, он может возвращать всё новые и новые значения, это нормально.
Конечно же, цикл с таким итерируемым объектом будет бесконечным. Но мы всегда можем прервать его, используя .