Как проверить, есть ли у объекта определенное свойство в JavaScript?
Рассмотрим следующий пример:
x = {'key': 1};
if ( x.hasOwnProperty('key') ) {
//Do this
}
Существуют ли альтернативные способы проверки наличия определенного свойства у объекта в JavaScript?
Проверка наличия свойства в объекте JavaScript
Чтобы проверить, содержит ли объект определенное свойство в JavaScript, можно использовать несколько методов, включая метод hasOwnProperty(), оператор in, более новый метод Object.hasOwn() или сравнение значений свойств с undefined. Каждый подход имеет разные характеристики поведения при обходе цепочки прототипов и производительности.
Содержание
- Методы проверки свойств
- Метод hasOwnProperty()
- Оператор in
- Object.hasOwn() - Современная альтернатива
- Альтернативные подходы
- Сравнение производительности
- Особые случаи и лучшие практики
Методы проверки свойств
JavaScript предоставляет несколько способов проверить, содержит ли объект определенное свойство, но они ведут себя по-разному при обходе цепочки прототипов и имеют различные производственные характеристики. Выбор метода зависит от того, нужно ли проверять только собственные свойства или также унаследованные, а также от требований к производительности и совместимости с браузерами.
Давайте рассмотрим основные методы, доступные для проверки свойств в JavaScript:
hasOwnProperty()- Проверяет только собственные свойства (не унаследованные от прототипа)inоператор - Проверяет как собственные, так и унаследованные свойстваObject.hasOwn()- Современная альтернативаhasOwnProperty()с улучшенной безопасностью- Сравнение с
undefined- Быстрая проверка, но с ограничениями Object.keys()сincludes()- Менее производительный, но простой
Метод hasOwnProperty()
Метод hasOwnProperty() - это традиционный способ проверить, содержит ли объект определенное свойство. Этот метод возвращает true, только если свойство существует непосредственно в самом объекте, а не в его цепочке прототипов.
const example = { key: 1 };
console.log(example.hasOwnProperty('key')); // true
console.log(example.hasOwnProperty('toString')); // false (унаследованное свойство)
Однако у hasOwnProperty() есть важные ограничения:
- Может быть переопределен: Если объект имеет собственное свойство
hasOwnProperty, это может помешать работе метода. - Недоступен во всех объектах: Объекты, созданные с помощью
Object.create(null), не наследуются отObject.prototype, поэтому у них нет методаhasOwnProperty().
Проблема переопределения:
const hedgehog = {
name: "shadow",
color: "black",
hasOwnProperty() { return false; } // Переопределяем метод
};
console.log(hedgehog.hasOwnProperty('color')); // false (неверно!)
Чтобы безопасно использовать hasOwnProperty() на объектах, которые могут его переопределить, можно использовать:
// Безопасный способ использования hasOwnProperty
Object.prototype.hasOwnProperty.call(obj, 'key');
Оператор in
Оператор in проверяет, существует ли указанное свойство в объекте или его цепочке прототипов. Это отличается от hasOwnProperty(), потому что он включает унаследованные свойства.
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():
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() в браузерах, которые его поддерживают.
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():
- Работает с Object.create(null): В отличие от
hasOwnProperty(), он работает с объектами, которые не наследуются отObject.prototype. - Не может быть переопределен: Это статический метод, поэтому он не может быть переопределен свойствами объекта.
- Чистый синтаксис: Более лаконичен, чем
Object.prototype.hasOwnProperty.call()
Пример с Object.create(null):
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.
const example = { key: undefined };
console.log(example.key !== undefined); // false (но свойство существует!)
Более надежная версия, которая проверяет существование и не-undefined значение:
function hasProperty(obj, prop) {
return obj[prop] !== undefined;
}
// Но это все равно не работает, если свойство существует со значением undefined
Object.keys() с includes()
Вы можете получить все собственные свойства и проверить, есть ли имя свойства в массиве:
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, но предоставляет функциональный интерфейс:
const example = { key: 1 };
console.log(Reflect.has(example, 'key')); // true
console.log(Reflect.has(example, 'toString')); // true
Сравнение производительности
Производительность значительно различается между методами, и эти различия становятся важными при частой проверке свойств или в коде, критичном к производительности.
Согласно тестам производительности, вот общая рейтинг производительности:
- Прямой доступ к свойству (
obj[key] !== undefined) - Самый быстрый - Оператор
in- Умеренная производительность hasOwnProperty()- Медленнее прямого доступаObject.hasOwn()- Похож наhasOwnProperty()или немного медленнееObject.keys().includes()- Самый медленный для одиночных проверок
Важные соображения по производительности:
-
Подход с Object.keys(): Создание массива всех ключей дорого для больших объектов. Как отмечено в ответе на Stack Overflow, проверка истинности значений с помощью
[]намного быстрее, чем использованиеinилиhasOwnProperty. -
Обход цепочки прототипов: Оператор
inобходит цепочку прототипов, что может быть медленнее для глубоко вложенных цепочек наследования. -
Поиск метода: Вызов
hasOwnProperty()для объекта означает сначала поиск метода, определение его источника, а затем привязку к объекту. Как объясняется в этом анализе,Object.hasOwn()избегает этого дополнительного шага поиска.
Особые случаи и лучшие практики
Объекты с переопределенным hasOwnProperty()
При работе с объектами, которые могут переопределить метод hasOwnProperty(), всегда предпочитайте Object.hasOwn() или безопасный подход Object.prototype.hasOwnProperty.call():
// Безопасные подходы, которые работают даже при переопределении hasOwnProperty
Object.hasOwn(obj, 'key'); // Лучший вариант, если поддерживается
Object.prototype.hasOwnProperty.call(obj, 'key'); // Резерв для старых браузеров
Объекты, созданные с Object.create(null)
Объекты, созданные с помощью Object.create(null), не наследуются от Object.prototype, поэтому у них полностью отсутствует метод hasOwnProperty():
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. Проверка строгого равенства не работает в этом случае:
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оператор: Универсальная поддержка
Для максимальной совместимости можно использовать полифилл или определение возможностей:
function safeHasOwn(obj, prop) {
return typeof Object.hasOwn === 'function'
? Object.hasOwn(obj, prop)
: Object.prototype.hasOwnProperty.call(obj, prop);
}
Сводка рекомендаций
- Современный код: Используйте
Object.hasOwn()для проверки собственных свойств - Старые браузеры: Используйте
Object.prototype.hasOwnProperty.call()как запасной вариант - Проверка прототипа: Используйте оператор
in, когда нужно включить унаследованные свойства - Критичный к производительности код: Рассмотрите прямой доступ к свойству (
obj[key] !== undefined), но будьте aware о ограничениях - Проверка нескольких свойств: Используйте
Object.keys(), когда проверяете несколько свойств
Вот справочная таблица:
| Метод | Проверяет только собственные свойства | Цепочка прототипов | Производительность | Безопасность |
|---|---|---|---|---|
Object.hasOwn() |
✓ | ✗ | Хорошая | ✓ |
hasOwnProperty() |
✓ | ✗ | Умеренная | ✗ |
in оператор |
✗ | ✓ | Умеренная | ✓ |
obj[key] !== undefined |
✓ | ✗ | Лучшая | ✗ |
Object.keys().includes() |
✓ | ✗ | Плохая | ✓ |
Источники
- Object.prototype.hasOwnProperty() - JavaScript | MDN
- Object.hasOwn() - JavaScript | MDN
- 3 Ways to Check If an Object Has a Property/Key in JavaScript
- The Uses of ‘in’ vs ‘hasOwnProperty’ - A Drip of JavaScript
- The Difference Between in and hasOwnProperty in JavaScript - Mastering JS
- How to Check If an Object Has a Property in JavaScript | Built In
- Speed test: === vs in vs hasOwnProperty
- Object.hasOwn() versus Object.prototype.hasOwnProperty() - Kieran Barker
- Which is faster: obj.hasOwnProperty(prop) vs Object.keys(obj).includes(prop) - DEV Community
- 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() как запасной вариант.