Відійдемо від окремих структур даних і поговоримо про ітерації над ними.
У минулому розділі ми бачили методи map.keys()
, map.values()
, map.entries()
.
Ці методи є загальними, існує спільна згода використовувати їх для структур даних. Якщо ми створюватимемо власну структуру даних, нам слід їх також реалізувати.
Вони підтримуються для:
Map
Set
Array
Звичайні об’єкти також підтримують подібні методи, але синтаксис дещо інший.
Object.keys, values, entries
Для простих об’єктів доступні наступні методи:
- Object.keys(obj) – повертає масив ключів.
- Object.values(obj) – повертає масив значень.
- Object.entries(obj) – повертає масив пар
[ключ, значення]
.
Зверніть увагу на відмінності (порівняно з map, наприклад):
Map | Object | |
---|---|---|
Синтаксис виклику | map.keys() |
Object.keys(obj) , а не obj.keys() |
Повертає | ітерабельний | “реальний” масив |
Перша відмінність полягає в тому, що ми повинні викликати Object.keys(obj)
, а не obj.keys()
.
Чому так? Основною причиною цього є гнучкість. Пам’ятайте, об’єкти є базою всіх складних структур у JavaScript. Ми можемо мати власний об’єкт, такий як data
, який реалізує власний метод data.values()
. І ми все ще можемо застосовувати до нього Object.values(data)
.
Друга відмінність полягає в тому, що Object.*
методи повертають “реальний” масив об’єктів, а не просто ітерабельний. Це переважно з історичних причин.
Наприклад:
let user = {
name: "Іван",
age: 30
};
Object.keys(user) = ["name", "age"]
Object.values(user) = ["Іван", 30]
Object.entries(user) = [ ["name","Іван"], ["age",30] ]
Це приклад використання Object.values
для перебору значень властивостей у циклі:
let user = {
name: "Іван",
age: 30
};
// Перебираємо значення
for (let value of Object.values(user)) {
alert(value); // Іван, тоді 30
}
Як і цикл for..in
, ці методи ігнорують властивості, що використовують Symbol(...)
як ключі.
Зазвичай це зручно. Якщо ми хочемо враховувати символьні ключі також, то для цього існує окремий метод Object.getOwnPropertySymbols, що повертає масив лише символьних ключів. Також існує метод Reflect.ownKeys(obj) , що повертає усі ключі.
Трансформація об’єктів
У об’єктів немає багатьох методів, які є у масивів, наприклад map
, filter
та інші.
Якщо б ми хотіли їх застосувати, тоді б ми використовували Object.entries
з подальшим викликом Object.fromEntries
:
- Викликаємо
Object.entries(obj)
, щоб отримати масив пар ключ/значення зobj
. - На ньому використовуємо методи масиву, наприклад
map
, щоб перетворити ці пари ключів/значень. - Використаємо
Object.fromEntries(array)
на отриманому масиві, щоб перетворити його знову на об’єкт.
Наприклад, у нас є об’єкт з цінами, і ми б хотіли їх подвоїти:
let prices = {
banana: 1,
orange: 2,
meat: 4,
};
let doublePrices = Object.fromEntries(
// перетворити ціни на масив, потім застосувати map, щоб перетворити на пари ключ/значення
// а потім fromEntries повертає об’єкт
Object.entries(prices).map(entry => [entry[0], entry[1] * 2])
);
alert(doublePrices.meat); // 8
З першого погляду це може здатися важким, але стане зрозумілим після того, як ви використаєте це декілька разів. Таким чином ми можемо створювати потужні ланцюги перетворень.