Ключи объекта: получение, проверка и особенности в JavaScript

Раздел: JavaScript -> Операции с объектами и массивами

Ключи в JavaScript: способы получения и проверки

Самый прямой способ получить список собственных перечисляемых ключей объекта - метод Object.keys(). Он возвращает массив строк, соответствующих именам свойств, которые принадлежат самому объекту (не унаследованы) и имеют флаг enumerable: true.


  const obj = {
    name: 'Alice',
    age: 30,
    city: 'Moscow'
  };
  const keys = Object.keys(obj);
  console.log(keys); // ['name', 'age', 'city']
  

ключи js (ключи в javascript)

Проблема: Object.keys() не включает символьные ключи и неперечисляемые свойства. Порядок ключей соответствует правилам современного JavaScript (целочисленные индексы по возрастанию, затем строковые в порядке добавления), но для старых движков может отличаться.

Цель использования: Получение всех перечисляемых ключей собственных свойств для итерации или анализа объекта.

Как перебрать все перечисляемые ключи, включая унаследованные от прототипа?

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


  const parent = { inherited: true };
  const child = Object.create(parent);
  child.own = 1;
  for (let key in child) {
    console.log(key); // 'own', затем 'inherited'
  }
  

Ошибка: Цикл захватывает унаследованные ключи, что часто нежелательно. Решение - использовать hasOwnProperty() внутри цикла:


  for (let key in child) {
    if (child.hasOwnProperty(key)) {
      console.log(key); // только 'own'
    }
  }
    

Случаи использования: Когда нужно проверить или перебрать все ключи, включая унаследованные (например, при прототипном наследовании или копировании свойств).

Как получить все собственные ключи, даже неперечисляемые?

Метод Object.getOwnPropertyNames() возвращает массив всех собственных ключей (включая неперечисляемые), но не включает символы.


  const obj = {};
  Object.defineProperty(obj, 'hidden', {
    value: 42,
    enumerable: false
  });
  console.log(Object.keys(obj));          // []
  console.log(Object.getOwnPropertyNames(obj)); // ['hidden']
  

Проблема: Символьные ключи не попадают в результат. Для их получения нужен отдельный метод.

Когда применять: Когда важны неперечисляемые свойства (например, встроенные методы объекта или свойства, созданные через Object.defineProperty).

Как получить только символьные ключи объекта?

Метод Object.getOwnPropertySymbols() возвращает массив символьных ключей (их нельзя получить через Object.keys или getOwnPropertyNames).


  const sym = Symbol('secret');
  const obj = { [sym]: 'hidden data', visible: 1 };
  console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(secret)]
  

Использование: для доступа к свойствам, чьи ключи являются символами (например, внутренние метаданные или итераторы).

Как одним вызовом получить все собственные ключи любого типа, включая символы?

Метод Reflect.ownKeys() объединяет результаты Object.getOwnPropertyNames и Object.getOwnPropertySymbols, возвращая полный список собственных ключей (строковых и символьных).


  const sym = Symbol('id');
  const obj = { [sym]: 1, name: 'test' };
  Object.defineProperty(obj, 'hidden', { value: 2 });
  console.log(Reflect.ownKeys(obj)); // ['name', 'hidden', Symbol(id)]
  

Поддержка: Reflect.ownKeys доступен в современном JavaScript (ES6+). Для старых окружений требуется полифилл.

Выбор: Если нужно гарантированно получить все собственные ключи объекта (строковые и символьные, включая неперечисляемые), Reflect.ownKeys - наиболее полное решение.

Как проверить, существует ли ключ в объекте (собственный или унаследованный)?

Оператор in проверяет наличие ключа во всей цепочке прототипов. Метод hasOwnProperty() (или Object.hasOwn() в ES2022) проверяет только собственные свойства.


  const proto = { inherited: 1 };
  const obj = Object.create(proto);
  obj.own = 2;
  console.log('inherited' in obj); // true
  console.log(obj.hasOwnProperty('inherited')); // false
  console.log(Object.hasOwn(obj, 'own')); // true (статический метод)
  

Типичная ошибка: Использование obj.hasOwnProperty('key') может привести к ошибке, если объект переопределил hasOwnProperty. Безопаснее вызывать через Object.prototype.hasOwnProperty.call(obj, 'key') или использовать Object.hasOwn.

Случаи: in - для проверки доступности свойства в цепочке; hasOwnProperty - для фильтрации унаследованных ключей.

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

Для динамического доступа к ключам используется синтаксис квадратных скобок obj[key]. Это позволяет использовать любые строки и символы.


  const key = 'name';
  const obj = { name: 'Alice', age: 30 };
  console.log(obj[key]); // 'Alice'
  
  // Динамическое создание ключа
  const sym = Symbol('id');
  const obj2 = { [sym]: 100 };
  console.log(obj2[sym]); // 100
  

Применение: Когда имя ключа формируется в процессе выполнения (например, из данных формы или API).

Расширенные примеры работы с ключами

Пример 1. Фильтрация ключей по условию (например, длина ключа больше 3).

Пример

const data = {
  a: 1,
  ab: 2,
  abc: 3,
  abcd: 4,
  abcde: 5
};
const filtered = Object.keys(data).filter(key => key.length > 3);
console.log(filtered); // ['abcd', 'abcde']
Результат: ['abcd', 'abcde']

Пример 2. Сортировка ключей объекта по алфавиту и создание нового упорядоченного объекта.

Пример

const unsorted = { banana: 1, apple: 2, cherry: 3 };
const sortedKeys = Object.keys(unsorted).sort();
const sortedObj = {};
sortedKeys.forEach(key => {
  sortedObj[key] = unsorted[key];
});
console.log(sortedObj); // { apple: 2, banana: 1, cherry: 3 }
Результат: { apple: 2, banana: 1, cherry: 3 }

Пример 3. Рекурсивное получение всех ключей вложенных объектов (глубокий обход).

Пример

function getAllKeys(obj) {
  let keys = [];
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      keys.push(key);
      if (typeof obj[key] === 'object' && obj[key] !== null) {
        keys = keys.concat(getAllKeys(obj[key]));
      }
    }
  }
  return keys;
}

const nested = {
  level1: {
    level2: {
      leaf: 1
    },
    another: 2
  },
  top: 3
};
console.log(getAllKeys(nested));
Результат: ['level1', 'top', 'level2', 'another', 'leaf']

Пример 4. Комбинирование Object.keys и Object.values для создания массива пар ключ-значение (аналог Object.entries вручную).

Пример

const obj = { x: 10, y: 20 };
const keys = Object.keys(obj);
const entries = keys.map(key => [key, obj[key]]);
console.log(entries); // [['x', 10], ['y', 20]]
Результат: [['x', 10], ['y', 20]]

Пример 5. Работа с символьными ключами и Reflect.ownKeys для копирования всех собственных свойств.

Пример

const sym = Symbol('secret');
const source = { visible: 1, [sym]: 2 };
Object.defineProperty(source, 'hidden', { value: 3, enumerable: false });

const target = {};
const allKeys = Reflect.ownKeys(source);
allKeys.forEach(key => {
  target[key] = source[key];
});
console.log(target); // { visible: 1, Symbol(secret): 2, hidden: 3 }
console.log(Object.keys(target)); // ['visible'] (только перечисляемые)
Результат: 
{ visible: 1, Symbol(secret): 2, hidden: 3 }
['visible']

Ключи в JavaScript - comments

En
ключи js (javascript)