Avatar ·

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

Привет! Я только начал изучать JavaScript и столкнулся с задачей: мне нужно проверить, является ли объект пустым (то есть не содержит ни одного собственного свойства). На первый взгляд кажется просто, но на деле всё оказалось сложнее. Вот пример: у меня есть объект `userSettings`, который может быть пустым, если пользователь ничего не настроил: ```javascript let userSettings = {}; ``` Я хочу написать условие вроде: ```javascript if (userSettings === {}) { console.log("Настроек нет"); } ``` Но это не работает. Я понял, что оператор `===` сравнивает ссылки, а не содержимое объектов. Потом я попробовал `Object.keys(userSettings).length === 0`, но слышал, что у этого метода могут быть проблемы. Ещё я видел, как кто-то использует `JSON.stringify(userSettings) === '{}'`, но это кажется каким-то костылём. Подскажите, пожалуйста, какой способ самый правильный и надёжный? Важно, чтобы решение работало во всех современных браузерах и не ломалось на хитрых случаях (например, если у объекта есть прототипные свойства или если мы используем ES6 классы). Буду благодарен за объяснение! <<>>

Правильный способ: комбинация Object.keys() и проверки типа

Лучший и наиболее надёжный способ проверить, пустой ли объект в JavaScript — использовать метод Object.keys() в сочетании с проверкой, что переменная действительно является объектом. Вот универсальное решение:

function isEmptyObject(obj) {
  return obj && typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0;
}

// Примеры использования:
console.log(isEmptyObject({}));           // true
console.log(isEmptyObject({a: 1}));       // false
console.log(isEmptyObject([]));           // false (массив — не объект в нашем понимании)
console.log(isEmptyObject(null));         // false
console.log(isEmptyObject(undefined));    // false
console.log(isEmptyObject("строка"));     // false

Почему это работает?

  • Проверка на существование и тип — obj && typeof obj === 'object' отсекает null (который тоже считается объектом в typeof), примитивы и undefined.
  • Проверка на массив — !Array.isArray(obj) исключает массивы, так как пустой массив [] тоже имеет Object.keys().length === 0, но это не объект в классическом смысле.
  • Object.keys() возвращает массив только собственных перечисляемых свойств объекта, игнорируя свойства из прототипа (например, методы из Object.prototype).

Почему не подходят другие популярные способы?

1. JSON.stringify(obj) === '{}'
Хотя этот способ работает для простых объектов, у него есть серьёзные недостатки:

  • Он ломается, если объект содержит undefined, функции или символы (они будут удалены при сериализации).
  • Он медленнее, так как преобразует весь объект в строку.
  • Пример поломки: JSON.stringify({a: undefined}) === '{}' — вернёт true, хотя объект не пустой.

2. Цикл for...in с hasOwnProperty

function isEmpty(obj) {
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      return false;
    }
  }
  return true;
}

Этот способ рабочий, но более громоздкий и менее читаемый. Object.keys() — современная и лаконичная альтернатива.

3. Object.entries(obj).length === 0
Работает аналогично Object.keys(), но возвращает массив пар [ключ, значение], что избыточно для простой проверки на пустоту.

Современная альтернатива (ES2020+)

Если вы используете Node.js 16+ или современные браузеры, можно применить опциональную цепочку и null-оператор:

const isEmpty = (obj) => obj?.constructor === Object && Object.keys(obj).length === 0;

Этот вариант проверяет, что объект является простым объектом (не массивом, не Date, не Map и т.д.) и не содержит свойств.

Итог

Для 99% случаев используйте:

Object.keys(obj).length === 0 && obj.constructor === Object

Это коротко, быстро и надёжно. Главное — не забывайте проверять, что переменная вообще является объектом, иначе получите ошибку.

<<>>

Альтернативный подход: использование for...in с защитой от прототипа

Если вы работаете в среде, где Object.keys() недоступен (например, очень старые браузеры вроде IE8), можно использовать классический цикл for...in с проверкой hasOwnProperty:

function isObjectEmpty(obj) {
  // Сначала проверяем, что это объект и не null
  if (obj === null || typeof obj !== 'object' || Array.isArray(obj)) {
    return false;
  }
  
  // Перебираем все ключи (включая унаследованные)
  for (let key in obj) {
    // Проверяем, что свойство принадлежит самому объекту
    if (obj.hasOwnProperty(key)) {
      return false; // Нашли хотя бы одно собственное свойство
    }
  }
  return true; // Собственных свойств нет
}

Когда это может быть полезно?

  • В легаси-проектах, где нет полифилов для Object.keys().
  • Если вы хотите избежать создания промежуточного массива (хотя разница в производительности микроскопическая).
  • Для образовательных целей — этот код наглядно показывает, как работает проверка "вручную".

Важное замечание

Оба метода (с Object.keys() и с for...in) проверяют только перечисляемые свойства. Если объект создан через Object.defineProperty() с флагом enumerable: false, такой объект будет считаться пустым, хотя содержит свойство. Для полной проверки используйте Object.getOwnPropertyNames():

function isTrulyEmpty(obj) {
  return Object.getOwnPropertyNames(obj).length === 0;
}

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