hellojs.ru
Главная - Дополнительные основы JavaScript - Итерируемые конструкции

Итерируемые конструкции

Размещено в категории "Дополнительные основы JavaScript"
06.10.2024 / просмотров: 53 / комментариев: 0
Ресурсы:

The Essential Guide to JavaScript Iterators
hasOwnProperty()
for..in versus for..of Loops
Документация for of
How to iterate over a JavaScript object?




for...in при использовании на массиве, объекте или строке будет работать с каждой сущностью по порядку.

Для примера возьмём такой объект:

Код

const user = {
  name: 'Alex',
  surname: 'Smith',
  birthday: '20/04/1993',
  showMyPublicData: function() {
  console.log(`${this.name} ${this.surname}`);
  }
};

И с помощью for...in переберём его свойства:

Код

for (const key in user) {
  console.log(user[key]);
}

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

Цитата

Alex
Smith
20/04/1993
[Function: showMyPublicData]

Так как массив - это частный случай объекта, мы можем также перебрать и его:

Код

const arr = ['b', 'a', 'c'];

for (const key in arr) {
  console.log(arr[key]);
}

В key теперь будет попадать индекс каждого элемента (0, 1, 2), соответственно, в консоли мы получим элементы нашего массива, то есть b, a, c

Строка также является итерируемой:

Код

const str = 'string';

for (const key in str) {
  console.log(str[key]);
}

Цитата

s
t
r
i
n
g

Цитата

for...in не обязательно проводит перебор по порядку, именно поэтому его не рекомендуется применять на массивах и строках.

for...of проходит по значениям перебираемого объекта и производит над ними необходимые нам действия.

Таким образом, код выше с помощью for...of будет выглядеть так:

Код

const str = 'string';

for (const key of str) {
  console.log(key);
}  

В key в данном случае попадет уже не индекс каждого элемента, как это было в for...in, а сразу его значение

Но если мы эту конструкцию попробуем применить на объекте, то получим ошибку

Цитата

TypeError: user is not iterable

Если по-простому, то объект является итерируемым, если мы можем применить к нему for...of (как мы это делали выше для массива и строки).

Объект(сам, как отдельный тип данных) не является итерируемым.

Всё зависит от того, есть ли у данной сущности так называемый Symbol.iterator, встроенный технический символ, отвечающий на вопрос, будет ли данный объект перебираемым.

Мы можем вывести в качестве объекта в консоль браузера, к примеру, массив и увидеть этот Symbol.iterator

Цитата

console.dir(arr);
Symbol(Symbol.iterator): ƒ values()
length: 0
name: "values"
arguments: (...)
caller: (...)

Цитата

К перебираемым объектам относятся массивы, строки, типизированные массивы, set, map и DOM-коллекции.

Главное, что мы получаем при этом два преимущества:

- строгое соответствие порядка в переборе

- производится исключение всех лишних свойств, которые могут быть унаследованы

Разберём на примере, если мы к нашему массиву прототипно добавим какой-то метод:

Код

const arr = ['b', 'a', 'c'];

Array.prototype.someMethod = function() { };

for (const key in arr) {
  console.log(key);
}

То при переборе с помощью for...in от также будет выведен в консоль.

Цитата

0
1
2
someMethod

Если же мы делаем перебор с помощью for...of, то этот метод исчезнет.

Дословно, итератор - это метод, который возвращает объект с методом next()

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

Создадим какой-то объект:

Код

const salaries = {
  john: 500,
  ivan: 1000,
  ann: 5000,
  sayHello: function () {
  console.log('Hello');
  }
};

Напишем функционал для перебора всех зарплат. Для этого нам нужно сначала сделать этот объект перебираемым, то есть позволить ему работать с for...of

Для этого в объект нужно добавить метод Symbol.iterator

Код

salaries[Symbol.iterator] = function () {
  return {
  current: this.john,
  last: this.ann,

  next() {
  if (this.current < this.last) {
  this.current = this.current + 500;
  return { done: false, value: this.current };
  } else {
  return { done: true };
  }
  }
  };
};

Теперь мы можем протестировать перебор объекта через for..of

Код

for (let res of salaries) {
  console.log(res);
}

Мы научились делать перебираемым любой объект, но итератор можно вызывать и вручную. Вместо конструкции for...of мы создадим отдельную переменную и в неё сохраним Symbol.iterator

Код

const iterator = salaries[Symbol.iterator];

А так как это метод нашего объекта, то мы можем его вызвать:

Код

const iterator = salaries[Symbol.iterator]();

В результате в переменную iterator мы получим объект с привязкой к объекту salaries и содержащим метод next()

Ну и дальше мы можем вызывать на этом объекте метод next()

Код

console.log(iterator.next());

получаем в консоли объект

Цитата

{done: false, value: 1000}
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
Сайт управляется системой uCoz