НейроАгент

Руководство по методам проверки свойств в JavaScript

Узнайте несколько методов проверки наличия конкретного свойства в объекте JavaScript. Сравните hasOwnProperty(), оператор in, Object.hasOwn() и альтернативные методы с учетом производительности.

Вопрос

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

Рассмотрим следующий пример:

javascript
x = {'key': 1};
if ( x.hasOwnProperty('key') ) {
    //Do this
}

Существуют ли альтернативные способы проверки наличия определенного свойства у объекта в JavaScript?

НейроАгент

Проверка наличия свойства в объекте JavaScript

Чтобы проверить, содержит ли объект определенное свойство в JavaScript, можно использовать несколько методов, включая метод hasOwnProperty(), оператор in, более новый метод Object.hasOwn() или сравнение значений свойств с undefined. Каждый подход имеет разные характеристики поведения при обходе цепочки прототипов и производительности.

Содержание

Методы проверки свойств

JavaScript предоставляет несколько способов проверить, содержит ли объект определенное свойство, но они ведут себя по-разному при обходе цепочки прототипов и имеют различные производственные характеристики. Выбор метода зависит от того, нужно ли проверять только собственные свойства или также унаследованные, а также от требований к производительности и совместимости с браузерами.

Давайте рассмотрим основные методы, доступные для проверки свойств в JavaScript:

  • hasOwnProperty() - Проверяет только собственные свойства (не унаследованные от прототипа)
  • in оператор - Проверяет как собственные, так и унаследованные свойства
  • Object.hasOwn() - Современная альтернатива hasOwnProperty() с улучшенной безопасностью
  • Сравнение с undefined - Быстрая проверка, но с ограничениями
  • Object.keys() с includes() - Менее производительный, но простой

Метод hasOwnProperty()

Метод hasOwnProperty() - это традиционный способ проверить, содержит ли объект определенное свойство. Этот метод возвращает true, только если свойство существует непосредственно в самом объекте, а не в его цепочке прототипов.

javascript
const example = { key: 1 };
console.log(example.hasOwnProperty('key')); // true
console.log(example.hasOwnProperty('toString')); // false (унаследованное свойство)

Однако у hasOwnProperty() есть важные ограничения:

  • Может быть переопределен: Если объект имеет собственное свойство hasOwnProperty, это может помешать работе метода.
  • Недоступен во всех объектах: Объекты, созданные с помощью Object.create(null), не наследуются от Object.prototype, поэтому у них нет метода hasOwnProperty().

Проблема переопределения:

javascript
const hedgehog = { 
    name: "shadow", 
    color: "black", 
    hasOwnProperty() { return false; } // Переопределяем метод
};
console.log(hedgehog.hasOwnProperty('color')); // false (неверно!)

Чтобы безопасно использовать hasOwnProperty() на объектах, которые могут его переопределить, можно использовать:

javascript
// Безопасный способ использования hasOwnProperty
Object.prototype.hasOwnProperty.call(obj, 'key');

Оператор in

Оператор in проверяет, существует ли указанное свойство в объекте или его цепочке прототипов. Это отличается от hasOwnProperty(), потому что он включает унаследованные свойства.

javascript
const example = { key: 1 };
console.log('key' in example); // true (собственное свойство)
console.log('toString' in example); // true (унаследованное свойство)
console.log('nonExistent' in example); // false

Оператор in полезен, когда вы хотите проверять свойства независимо от того, где они определены в цепочке прототипов. Однако иногда это может привести к неожиданным результатам, если вас интересуют только свойства, определенные непосредственно в объекте.

Пример, показывающий разницу между in и hasOwnProperty():

javascript
const example = {};
example.prop = "существует";

// hasOwnProperty проверяет только собственные свойства
console.log(example.hasOwnProperty('prop')); // true
console.log(example.hasOwnProperty('toString')); // false

// оператор in проверяет и собственные, и унаследованные свойства
console.log('prop' in example); // true
console.log('toString' in example); // true
console.log('hasOwnProperty' in example); // true

Object.hasOwn() - Современная альтернатива

Object.hasOwn() - это более новый метод, представленный в ECMAScript 2022 в качестве более безопасной альтернативы Object.prototype.hasOwnProperty(). Он решает многие ограничения традиционного метода.

Согласно документации MDN, Object.hasOwn() рекомендуется вместо hasOwnProperty() в браузерах, которые его поддерживают.

javascript
const example = {};
example.prop = "существует";

// Object.hasOwn возвращает true только для прямых свойств
console.log(Object.hasOwn(example, 'prop')); // true
console.log(Object.hasOwn(example, 'toString')); // false
console.log(Object.hasOwn(example, 'hasOwnProperty')); // false

Ключевые преимущества Object.hasOwn():

  1. Работает с Object.create(null): В отличие от hasOwnProperty(), он работает с объектами, которые не наследуются от Object.prototype.
  2. Не может быть переопределен: Это статический метод, поэтому он не может быть переопределен свойствами объекта.
  3. Чистый синтаксис: Более лаконичен, чем Object.prototype.hasOwnProperty.call()

Пример с Object.create(null):

javascript
const x = Object.create(null);
x.prop = 'значение';

console.log(Object.hasOwn(x, 'prop')); // true
console.log(x.hasOwnProperty('prop')); // TypeError: x.hasOwnProperty is not a function

Альтернативные подходы

Сравнение с undefined

Одна из быстрых альтернатив - проверить, что свойство не равно undefined. Однако этот подход имеет ограничения, потому что свойство может иметь легитимное значение undefined.

javascript
const example = { key: undefined };
console.log(example.key !== undefined); // false (но свойство существует!)

Более надежная версия, которая проверяет существование и не-undefined значение:

javascript
function hasProperty(obj, prop) {
    return obj[prop] !== undefined;
}

// Но это все равно не работает, если свойство существует со значением undefined

Object.keys() с includes()

Вы можете получить все собственные свойства и проверить, есть ли имя свойства в массиве:

javascript
const example = { key: 1 };
console.log(Object.keys(example).includes('key')); // true
console.log(Object.keys(example).includes('toString')); // false

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

Reflect.has()

Метод Reflect.has() похож на оператор in, но предоставляет функциональный интерфейс:

javascript
const example = { key: 1 };
console.log(Reflect.has(example, 'key')); // true
console.log(Reflect.has(example, 'toString')); // true

Сравнение производительности

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

Согласно тестам производительности, вот общая рейтинг производительности:

  1. Прямой доступ к свойству (obj[key] !== undefined) - Самый быстрый
  2. Оператор in - Умеренная производительность
  3. hasOwnProperty() - Медленнее прямого доступа
  4. Object.hasOwn() - Похож на hasOwnProperty() или немного медленнее
  5. Object.keys().includes() - Самый медленный для одиночных проверок

Важные соображения по производительности:

  • Подход с Object.keys(): Создание массива всех ключей дорого для больших объектов. Как отмечено в ответе на Stack Overflow, проверка истинности значений с помощью [] намного быстрее, чем использование in или hasOwnProperty.

  • Обход цепочки прототипов: Оператор in обходит цепочку прототипов, что может быть медленнее для глубоко вложенных цепочек наследования.

  • Поиск метода: Вызов hasOwnProperty() для объекта означает сначала поиск метода, определение его источника, а затем привязку к объекту. Как объясняется в этом анализе, Object.hasOwn() избегает этого дополнительного шага поиска.

Особые случаи и лучшие практики

Объекты с переопределенным hasOwnProperty()

При работе с объектами, которые могут переопределить метод hasOwnProperty(), всегда предпочитайте Object.hasOwn() или безопасный подход Object.prototype.hasOwnProperty.call():

javascript
// Безопасные подходы, которые работают даже при переопределении hasOwnProperty
Object.hasOwn(obj, 'key'); // Лучший вариант, если поддерживается
Object.prototype.hasOwnProperty.call(obj, 'key'); // Резерв для старых браузеров

Объекты, созданные с Object.create(null)

Объекты, созданные с помощью Object.create(null), не наследуются от Object.prototype, поэтому у них полностью отсутствует метод hasOwnProperty():

javascript
const x = Object.create(null);
x.prop = 'значение';

// Эти варианты работают:
console.log('prop' in x); // true
console.log(Object.hasOwn(x, 'prop')); // true

// Этот вариант не работает:
console.log(x.hasOwnProperty('prop')); // TypeError: x.hasOwnProperty is not a function

Свойства со значением undefined

Будьте осторожны при проверке свойств, которые могут легитимно иметь значение undefined. Проверка строгого равенства не работает в этом случае:

javascript
const obj = { key: undefined };

// Эти корректно идентифицируют существование свойства:
console.log('key' in obj); // true
console.log(Object.hasOwn(obj, 'key')); // true
console.log(obj.hasOwnProperty('key')); // true

// Этот неверно указывает, что свойства не существует:
console.log(obj.key !== undefined); // false

Совместимость с браузерами

Хотя Object.hasOwn() является современным рекомендуемым подходом, учитывайте совместимость с браузерами:

  • Object.hasOwn(): Поддерживается в современных браузерах (Chrome 93+, Firefox 92+, Safari 15.4+, Edge 93+)
  • hasOwnProperty(): Универсальная поддержка
  • in оператор: Универсальная поддержка

Для максимальной совместимости можно использовать полифилл или определение возможностей:

javascript
function safeHasOwn(obj, prop) {
    return typeof Object.hasOwn === 'function' 
        ? Object.hasOwn(obj, prop) 
        : Object.prototype.hasOwnProperty.call(obj, prop);
}

Сводка рекомендаций

  1. Современный код: Используйте Object.hasOwn() для проверки собственных свойств
  2. Старые браузеры: Используйте Object.prototype.hasOwnProperty.call() как запасной вариант
  3. Проверка прототипа: Используйте оператор in, когда нужно включить унаследованные свойства
  4. Критичный к производительности код: Рассмотрите прямой доступ к свойству (obj[key] !== undefined), но будьте aware о ограничениях
  5. Проверка нескольких свойств: Используйте Object.keys(), когда проверяете несколько свойств

Вот справочная таблица:

Метод Проверяет только собственные свойства Цепочка прототипов Производительность Безопасность
Object.hasOwn() Хорошая
hasOwnProperty() Умеренная
in оператор Умеренная
obj[key] !== undefined Лучшая
Object.keys().includes() Плохая

Источники

  1. Object.prototype.hasOwnProperty() - JavaScript | MDN
  2. Object.hasOwn() - JavaScript | MDN
  3. 3 Ways to Check If an Object Has a Property/Key in JavaScript
  4. The Uses of ‘in’ vs ‘hasOwnProperty’ - A Drip of JavaScript
  5. The Difference Between in and hasOwnProperty in JavaScript - Mastering JS
  6. How to Check If an Object Has a Property in JavaScript | Built In
  7. Speed test: === vs in vs hasOwnProperty
  8. Object.hasOwn() versus Object.prototype.hasOwnProperty() - Kieran Barker
  9. Which is faster: obj.hasOwnProperty(prop) vs Object.keys(obj).includes(prop) - DEV Community
  10. What is the hasOwnProperty() method in JavaScript?

Заключение

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

  • Используйте Object.hasOwn() для современного JavaScript, когда нужно проверять только собственные свойства - это самый безопасный и надежный метод
  • Используйте оператор in, когда нужно включить унаследованные свойства в проверку
  • Избегайте прямого сравнения свойства с undefined, когда свойство может легитимно иметь undefined в качестве значения
  • Учитывайте производительность - прямой доступ к свойству самый быстрый, но имеет ограничения, в то время как Object.keys().includes() самый медленный, но наиболее надежный для сложных случаев
  • Обрабатывайте особые случаи, такие как объекты с переопределенными методами hasOwnProperty() или объекты, созданные с помощью Object.create(null)

Лучший метод зависит от вашего конкретного случая использования, но Object.hasOwn() обычно рекомендуется для современного JavaScript-разработки при проверке только собственных свойств. Для максимальной совместимости используйте определение возможностей или Object.prototype.hasOwnProperty.call() как запасной вариант.