3

В 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 
+0

В большинстве случаев, если функция принимает что-то с каким-то свойством - оно не должно быть его бизнес, где в цепочке прототипов определяется свойство, но это только доступно. Таким образом вы отделяете форму данных от деталей реализации. – zerkms

ответ

2

обнаружение Функции для загрузки polyfills, тестирование условий для использования современного API, DOM и т.д.

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

Например:

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

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

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

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

4

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

+1

Я ищу конкретные варианты использования, например, в ответе Амдугласа. –

4

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! :)