В JavaScript оператор in
проверяет, имеет ли объект указанное свойство. Однако он не проверяет только собственные свойства объекта, а также цепочку прототипов. Поэтому в некоторых ситуациях он может вести себя не так, как ожидалось.Есть ли случаи, когда я должен использовать оператор in вместо hasOwnProperty()?
Допустим, что по какой-то причине у нас есть объект someArrayMethods
, содержащий (очевидно) некоторые методы массива, ключи:
const someArrayMethods = {
indexOf: true,
map: true,
};
Мы можем проверить, что этот объект имеет определенный метод в качестве ключа с помощью оператора in
:
console.log('indexOf' in someArrayMethods); // true
console.log('every' in someArrayMethods); // false
Что делать, если мы попытались проверить наличие toString
?
console.log('toString' in someArrayMethods); // true
Сюрприз! Оказывается, этот объект имеет toString
method в цепочке прототипов, поэтому оператор in
возвращает true
, хотя объект не имеет собственного свойства toString
.
И вот тут hasOwnProperty()
приходит на помощь! Это почти то же самое, что и оператор in
, с одним отличием: он не проверяет цепочку прототипов. Мы можем переписать наш предыдущий пример:
console.log(someArrayMethods.hasOwnProperty('toString')); // false
Теперь он работает должным образом. К сожалению, hasOwnProperty()
также может выйти из строя в одном случае. Что делать, если бы у нас был объект с собственным имуществом hasOwnProperty
? Смотрите этот пример:
const someObject = {
hasOwnProperty() {
return false;
},
theAnswer: 42,
};
// Does `someObject` has own property `theAnswer`?
console.log(someObject.hasOwnProperty('theAnswer')); // false
// Well, it seems it doesn't...
Чтобы решить эту проблему, вместо того, чтобы использовать someObject.hasOwnProperty
, мы можем обратиться к этому методу непосредственно из Object.prototype
:
const hasOwn = Object.prototype.hasOwnProperty;
console.log(hasOwn.call(someObject, 'theAnswer')); // true
Это, как представляется, наиболее разумный подход для проверки, если объект имеет некоторое свойство. Несмотря на это, были ли в этом случае операторы с кодом in
? Я знаю, что его можно использовать для проверки того, имеет ли экземпляр некоторого класса какой-либо метод, но в этом случае лучше не просто проверить, является ли этот объект экземпляром этого класса?
Как примечание стороны, еще один вариант заключается в использовании Object.keys()
с ECMAScript 2016 Array.prototype.includes()
:
console.log(Object.keys(someObject).includes('theAnswer')); // true
В большинстве случаев, если функция принимает что-то с каким-то свойством - оно не должно быть его бизнес, где в цепочке прототипов определяется свойство, но это только доступно. Таким образом вы отделяете форму данных от деталей реализации. – zerkms