Синтаксис метода keys()
Array.prototype.keys ( )
Логика работы метода keys()
Выполняются следующие шаги:
1. Пусть O будет ? ToObject(значение this). 2. Вернуть CreateArrayIterator(O, key).
Как работает итератор массивов в случае метода keys()?
Есть массив:
var massiv = ["efim", "360", ".", "ru"]
Мы создаём итератор массива и кладём его в переменную iterator
var iterator = massiv.keys()
У итератора массива есть свой собственный метод next() при помощи которого он обходит массив.
Каждый вызов next() делает шаг вперёд по массиву. Самостоятельное «шагание» вне других методов и функций бесполезно. Итератор должен вызываться «параллельно» вместе с остальными методами.
Давайте посмотрим, что возвращает шаг итератора массива.
Делаем первый шаг — первый раз вызываем next()
iterator.next()
Нам вернулся объект с двумя свойствами.
Ключ value хранит значение индекса первого элемента массива. На первом шаге «value: 0«. Ключ done хранит состояние выполнения итераций над массивом. На первом шаге «done: false«
Делаем второй шаг
Делаем третий шаг
Делаем четвёртый шаг — это шаг на последний элемент массива
Делаем пятый шаг
На пятом шаге итератор массива возвращает объект с «value: undefined» и «done: true«. Это значит, что итератор массива дошёл до конца массива и элементов больше нет.
Когда мы делаем шаги по массиву, то в этот момент мы можем извлекать номера индексов и использовать их в решениях своих задач.
Как использовать метод keys() у массивов?
Задача — Сравнение массивов
Есть 2 массива:
var a = [1, 2, 3, 4] var b = [1, 2, 3, "4"]
Нам нужно сравнить 2 массива на равенство. Длины массивов совпадают, поэтому первое условие равенства массивов выполняется. Для сравнения будем использовать метод filter() и метод keys().
Метод filter() может принимать 2 параметра:
- Функцию, которая возвращает true или false
- Объект this для каждого вызова (тут будет наш итератор массива)
Вариант 1
Если массивы равны, то длина отфильтрованного массива должна равняться длине оригинального массива
a.filter( i => i === b[x.next().value], x=b.keys() ) [1, 2, 3]
В этом условии длина фильтрованного меньше длины оригинального массива. Значит массивы не равны.
Вариант 2
Если массивы не равны, то длина отфильтрованного массива будет больше нуля. То есть фильтрованный массив найдёт элемент, который не будет похож.
a.filter( i => i !== b[x.next().value], x=b.keys() ) [4]
В этом условии длина фильтрованного массива равна «1». В нём хранится элемент, который не совпал значением.
Задача — Получение индексов элементов с одинаковыми значениями
Есть массив с одинаковыми значениями «11»:
var massiv = [11, 22, 33, 11, 44, 11, 55, 66]
Как получить индексы элементов с одинаковыми значениями «11»?
massiv.map(i => i==11 ? x.next().value : x.next().done, x=massiv.keys()).filter(i => i !== false) [0, 3, 5]
Сначала мы обошли элементы массива методом map(). В качестве this для функции обратного вызова мы использовали итератор массива по переменной massiv.
На каждом шаге метода map() мы проверяли условие равенства текущего элемента со значением «11«. Вместе с map() шагал и наш итератор массива. Если условие было верным, тогда мы возвращали индекс элемента, который доставали из ключа value объекта, возвращаемого шагом next(). Если условие было неверным, то мы возвращали значение ключа done.
Мы применили тернарный оператор (условие ? возвращаем если условие верное : возвращаем если условие неверное), чтобы упростить вид записи.
Метод map() вернул нам такой вариант массива:
[0, false, false, 3, false, 5, false, false]
Удобно то, что в нашем случае мы никогда не увидим true в качестве значения элемента преобразованного массива. Только индексы и false.
Информационные ссылки
JavaScript | Как получить индексы элементов с одинаковыми значениями в массиве?
Стандарт ECMAScript — Раздел «23.1.3.16 Array.prototype.keys ( )» — https://tc39.es/ecma262/#sec-array.prototype.keys