Есть ли случаи, когда я должен использовать оператор in вместо hasOwnProperty()?

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

Допустим, по какой-то причине у нас есть объект 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 метод в цепи прототипа, поэтому 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

3 ответа

Решение

Обнаружение функций для загрузки полифилов, условия тестирования для использования современных DOM API и т. Д.

С использованием in Оператор идеально подходит для оценки того, следует ли загружать / выполнять полифилл JavaScript именно потому, что он проверяет цепочку прототипов.

Например:

// this works wonderfully
if (!('addEventListener' in window)) {
  // polyfill addEventListener
}

по сравнению с:

// this doesn't work at all
if (!window.hasOwnProperty('addEventListener')) {
  // polyfill addEventListener
}

Следовательно, почему сервис Polyfill.io использует его для своих тестов обнаружения функций.

in это оператор, поэтому его нельзя угнать. Вам не нужно полагаться на то, что ни один сценарий не изменен или скрыт Object, Object.prototype, Object.prototype.hasOwnProperty, Object.prototype.hasOwnProperty.call,

И это быстрый способ узнать, есть ли у объекта какое-либо свойство. Я имею в виду, если obj.foo может вернуться, например, "bar" даже если foo свойство наследуется, имеет смысл знать, obj имеет это foo собственностью или не заблаговременно, либо собственной, либо наследственной.

Конечно, если бы у нас был только HasOwnProperty, мы могли бы (обычно) продолжать вызывать [[GetPrototypeOf]] до конца цепочки и проверять каждый объект. Но это было бы утомительно для кода, вероятно, медленнее, чем родной in и не возможно до ES5.

Более того, есть принципиальная разница. in оператор использует внутренний метод [[HasProperty]], а HasOwnProperty использует [[GetOwnProperty]]. Повторение [[GetOwnProperty]] и [[GetPrototypeOf]] может привести к отличному результату, чем [[HasProperty]] для неординарных объектов.

Так что да: in Оператор полезен, когда вы хотите вызвать внутренний метод [[HasProperty]] объекта. На самом деле, кроме Reflect.has Это единственный правильный способ сделать это.

var p = new Proxy({}, {has: function() {
  console.log('Hooray!');
  return true;
}});
p.hasOwnProperty('foo'); // :(
'foo' in p; // Hooray! :)

Вы отвечаете на свой вопрос.in хорошо, когда вы хотите искать в цепочке прототипов.

Другие вопросы по тегам