Ресурсы: 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]);
}
Цитата
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 от также будет выведен в консоль.
Если же мы делаем перебор с помощью
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}
Добавлять комментарии могут только зарегистрированные пользователи.