NodeJS Back-end Инженер

NodeJS Back-end Инженер

Роадмап навыков для прокачки

Методы keys, values, entries и fromEntries

JavaScript (ES6 и новее)Общие возможности ES6По умолчанию

Основная идея

Методы Object.keys(), Object.values(), Object.entries() и Object.fromEntries() — это инструменты ES6+ для работы с объектами как с коллекциями. Они позволяют преобразовывать объекты в массивы и обратно, делая доступными методы массивов для обработки данных объекта.

Ключевые аспекты

  • Object.keys(obj) — возвращает массив ключей (свойств) объекта
  • Object.values(obj) — возвращает массив значений объекта
  • Object.entries(obj) — возвращает массив пар [ключ, значение]
  • Object.fromEntries(arr) — создаёт объект из массива пар (ES2019)
  • Только собственные свойства — методы игнорируют унаследованные свойства

Плюсы

  • Простое преобразование объекта в массив для итерации
  • Работает с for...of, map(), filter(), reduce()
  • Позволяет трансформировать объекты функционально
  • fromEntries() удобен для создания объектов из Map

Минусы

  • Возвращают только enumerable свойства
  • Порядок ключей не всегда гарантирован (числовые ключи сортируются)
  • fromEntries() требует ES2019+

Частые ошибки на собеседованиях

  • Путают с методами Map — у Map это методы экземпляра, у Object — статические
  • Забывают, что entries() возвращает массив массивов, а не объект
  • Не учитывают, что методы не возвращают Symbol-ключи

Введение и проблематика

В JavaScript объекты — основная структура данных, но у них нет встроенных методов для итерации, как у массивов. До ES6 приходилось использовать for...in с проверкой hasOwnProperty().

Методы Object.keys(), Object.values() и Object.entries() появились в ES6/ES2017, а Object.fromEntries() — в ES2019, решив проблему удобной работы с объектами как с коллекциями.

Какую проблему решают?

Code Example 1: Чем отличаются два подхода к перебору свойств объекта? Какой предпочтительнее и почему?

js
const user = { name: 'Иван', age: 30, city: 'Москва' };
 
// ❌ Старый подход с for...in
for (const key in user) {
  if (user.hasOwnProperty(key)) {
    console.log(key, user[key]);
  }
}
 
// ✅ Современный подход с entries()
for (const [key, value] of Object.entries(user)) {
  console.log(key, value);
}

Базовая теория

Object.keys()

Возвращает массив ключей (имён свойств) объекта.

Code Example 2: Что вернёт каждый из методов Object.keys(), Object.values() и Object.entries()?

js
const user = { name: 'Анна', age: 25, role: 'admin' };
 
const keys = Object.keys(user);
console.log(keys); // ['name', 'age', 'role']

Object.values()

Возвращает массив значений свойств объекта.

js
const user = { name: 'Анна', age: 25, role: 'admin' };
 
const values = Object.values(user);
console.log(values); // ['Анна', 25, 'admin']

Object.entries()

Возвращает массив пар [ключ, значение].

js
const user = { name: 'Анна', age: 25 };
 
const entries = Object.entries(user);
console.log(entries);
// [['name', 'Анна'], ['age', 25]]

Object.fromEntries()

Создаёт объект из массива пар [ключ, значение]обратная операция к entries().

Code Example 3: Что будет в переменной user? Какую обратную операцию выполняет Object.fromEntries()?

js
const entries = [['name', 'Борис'], ['age', 30]];
 
const user = Object.fromEntries(entries);
console.log(user); // { name: 'Борис', age: 30 }

Сводная таблица

МетодВходные данныеРезультатВерсия
Object.keys()ОбъектМассив ключейES6
Object.values()ОбъектМассив значенийES2017
Object.entries()ОбъектМассив [key, value]ES2017
Object.fromEntries()Массив/MapОбъектES2019

Практические примеры

Подсчёт свойств объекта

js
const config = { debug: true, version: '1.0', env: 'production' };
 
const count = Object.keys(config).length;
console.log(`Количество настроек: ${count}`); // 3

Фильтрация свойств объекта

Code Example 4: Что будет в переменной affordable? Как работает комбинация entries + filter + fromEntries?

js
const prices = { apple: 100, banana: 50, orange: 75, grape: 200 };
 
// Оставляем только товары дешевле 100
const affordable = Object.fromEntries(
  Object.entries(prices).filter(([_, price]) => price < 100)
);
 
console.log(affordable); // { banana: 50, orange: 75 }

Трансформация значений

Code Example 5: Что будет в переменной newPrices? Что делает этот код?

js
const prices = { apple: 100, banana: 50, orange: 75 };
 
// Увеличиваем все цены на 10%
const newPrices = Object.fromEntries(
  Object.entries(prices).map(([key, value]) => [key, value * 1.1])
);
 
console.log(newPrices);
// { apple: 110, banana: 55, orange: 82.5 }

Поиск максимального значения

Code Example 6: Что выведет console.log? Как reduce используется для поиска максимума?

js
const scores = { Анна: 95, Борис: 87, Виктор: 92 };
 
const [topStudent, topScore] = Object.entries(scores)
  .reduce((max, current) => current[1] > max[1] ? current : max);
 
console.log(`Лучший: ${topStudent} (${topScore} баллов)`);
// Лучший: Анна (95 баллов)

Использование с for...of

Code Example 7: Что выведет каждый из трёх вариантов цикла for...of?

js
const user = { name: 'Иван', age: 30 };
 
for (const key of Object.keys(user)) {
  console.log(key);
}
// name
// age

Преобразование Map в Object и обратно

Code Example 8: Как работает преобразование между Map и Object? Что выведут console.log?

js
// Map → Object
const map = new Map([
  ['name', 'Алексей'],
  ['age', 28]
]);
 
const obj = Object.fromEntries(map);
console.log(obj); // { name: 'Алексей', age: 28 }
 
// Object → Map
const newMap = new Map(Object.entries(obj));
console.log(newMap.get('name')); // 'Алексей'

Пограничные кейсы

Порядок ключей

⚠️

Числовые ключи сортируются по возрастанию, строковые — в порядке добавления.

Code Example 9: Что вернёт Object.keys(mixed)? В каком порядке будут ключи и почему?

js
const mixed = { b: 1, 2: 'two', a: 3, 1: 'one' };
 
console.log(Object.keys(mixed));
// ['1', '2', 'b', 'a'] — числа первыми и отсортированы!

Только enumerable свойства

Code Example 10: Что вернёт Object.keys(obj)? Почему не все свойства включены?

js
const obj = {};
Object.defineProperty(obj, 'hidden', {
  value: 'secret',
  enumerable: false
});
obj.visible = 'shown';
 
console.log(Object.keys(obj)); // ['visible']
// 'hidden' не включён, т.к. enumerable: false

Symbol-ключи игнорируются

Code Example 11: Что вернут Object.keys() и Object.values()? Почему Symbol-ключ не включён?

js
const sym = Symbol('id');
const obj = {
  [sym]: 123,
  name: 'Тест'
};
 
console.log(Object.keys(obj));   // ['name']
console.log(Object.values(obj)); // ['Тест']
// Symbol-ключи не возвращаются!

Для получения Symbol-ключей используйте Object.getOwnPropertySymbols().


Работа с вложенными объектами

js
const data = {
  user: { name: 'Мария', age: 25 },
  settings: { theme: 'dark' }
};
 
// Поверхностное преобразование
const entries = Object.entries(data);
console.log(entries);
// [['user', { name: 'Мария', age: 25 }], ['settings', { theme: 'dark' }]]
 
// Глубокое клонирование с трансформацией требует рекурсии

Плюсы и минусы

ПлюсыМинусы
Простое преобразование в массивНе включают Symbol-ключи
Совместимость с методами массивовПорядок числовых ключей меняется
Функциональный стиль обработкиfromEntries() требует ES2019
Работают с for...ofТолько enumerable свойства

Вопросы интервьюера

Q: В чём разница между Object.keys() и for...in?

Object.keys() возвращает только собственные enumerable свойства. for...in также перебирает унаследованные свойства из прототипа.

Q: Как отфильтровать свойства объекта?

Используйте комбинацию Object.entries(), filter() и Object.fromEntries().

Q: Почему Object.entries() возвращает массив, а не итератор?

Для совместимости и простоты использования. Массив можно многократно перебирать и применять методы массивов.

Q: Как преобразовать Map в обычный объект?

Object.fromEntries(map) — Map реализует протокол итератора и возвращает пары [key, value].


Источники

Code Example 1: for...in vs Object.entries()

❓ Чем отличаются два подхода к перебору свойств объекта? Какой предпочтительнее и почему?

Подход A:

js
const user = { name: 'Иван', age: 30, city: 'Москва' };
 
for (const key in user) {
  if (user.hasOwnProperty(key)) {
    console.log(key, user[key]);
  }
}

Подход B:

js
const user = { name: 'Иван', age: 30, city: 'Москва' };
 
for (const [key, value] of Object.entries(user)) {
  console.log(key, value);
}

Code Example 2: Object.keys(), Object.values(), Object.entries()

❓ Что вернёт каждый из трёх вызовов — Object.keys(), Object.values() и Object.entries()?

js
const user = { name: 'Анна', age: 25, role: 'admin' };
 
console.log(Object.keys(user));
console.log(Object.values(user));
console.log(Object.entries(user));

Code Example 3: Object.fromEntries()

❓ Что будет в переменной user? Какую обратную операцию выполняет Object.fromEntries()?

js
const entries = [['name', 'Борис'], ['age', 30]];
 
const user = Object.fromEntries(entries);
console.log(user);

Code Example 4: Фильтрация свойств объекта

❓ Что будет в переменной affordable? Как работает комбинация entries + filter + fromEntries?

js
const prices = { apple: 100, banana: 50, orange: 75, grape: 200 };
 
const affordable = Object.fromEntries(
  Object.entries(prices).filter(([_, price]) => price < 100)
);
 
console.log(affordable);

Code Example 5: Трансформация значений

❓ Что будет в переменной newPrices? Что делает этот код?

js
const prices = { apple: 100, banana: 50, orange: 75 };
 
const newPrices = Object.fromEntries(
  Object.entries(prices).map(([key, value]) => [key, value * 1.1])
);
 
console.log(newPrices);

Code Example 6: Поиск максимального значения

❓ Что выведет console.log? Как reduce используется для поиска максимума?

js
const scores = { Анна: 95, Борис: 87, Виктор: 92 };
 
const [topStudent, topScore] = Object.entries(scores)
  .reduce((max, current) => current[1] > max[1] ? current : max);
 
console.log(`Лучший: ${topStudent} (${topScore} баллов)`);

Code Example 7: for...of с keys(), values(), entries()

❓ Что выведет каждый из трёх вариантов цикла for...of?

keys():

js
const user = { name: 'Иван', age: 30 };
 
for (const key of Object.keys(user)) {
  console.log(key);
}

values():

js
const user = { name: 'Иван', age: 30 };
 
for (const value of Object.values(user)) {
  console.log(value);
}

entries():

js
const user = { name: 'Иван', age: 30 };
 
for (const [key, value] of Object.entries(user)) {
  console.log(`${key}: ${value}`);
}

Code Example 8: Map ↔ Object

❓ Как работает преобразование между Map и Object? Что выведут console.log?

js
const map = new Map([
  ['name', 'Алексей'],
  ['age', 28]
]);
 
const obj = Object.fromEntries(map);
console.log(obj);
 
const newMap = new Map(Object.entries(obj));
console.log(newMap.get('name'));

Code Example 9: Порядок ключей

❓ Что вернёт Object.keys(mixed)? В каком порядке будут ключи и почему?

js
const mixed = { b: 1, 2: 'two', a: 3, 1: 'one' };
 
console.log(Object.keys(mixed));

Code Example 10: Enumerable свойства

❓ Что вернёт Object.keys(obj)? Почему не все свойства включены?

js
const obj = {};
Object.defineProperty(obj, 'hidden', {
  value: 'secret',
  enumerable: false
});
obj.visible = 'shown';
 
console.log(Object.keys(obj));

Code Example 11: Symbol-ключи

❓ Что вернут Object.keys() и Object.values()? Почему Symbol-ключ не включён?

js
const sym = Symbol('id');
const obj = {
  [sym]: 123,
  name: 'Тест'
};
 
console.log(Object.keys(obj));
console.log(Object.values(obj));