Есть ли вероятность, что количество ключей, полученных через for-in и Object.keys, будет разным для одного объекта и при каком условии
Что проверяют
Знаете ли вы, как устроено наследование через прототипы и что такое перечисляемость свойства. Следом обычно просят показать, как такое расхождение возникает на практике и как защититься от него в цикле.
Как отвечать
Да, может. Оба способа берут только перечисляемые свойства со строковыми ключами, но с разной областью:
Object.keys(obj): только собственные перечисляемые свойства;for...in: собственные плюс перечисляемые свойства всей цепочки прототипов.
Значит, количество расходится ровно тогда, когда в цепочке прототипов есть перечисляемое свойство, которого нет среди собственных. Реальные сценарии:
Object.create(proto): уprotoобычные свойства, заданные присваиванием;- функция-конструктор: методы, повешенные как
Foo.prototype.bar = function () {}, перечисляемые и попадут вfor...inу каждого экземпляра. Методы, объявленные в синтаксисеclass, наоборот, неперечисляемые; - расширенный
Object.prototype: старая библиотека или самодельный полифил добавили метод присваиванием, и лишний ключ появляется вfor...inу любого объекта приложения.
Одинаково оба способа ведут себя с символьными ключами (их не видит ни один, нужны Object.getOwnPropertySymbols или Reflect.ownKeys) и с неперечисляемыми свойствами (их покажет только Object.getOwnPropertyNames). У объекта из Object.create(null) прототипа нет, и результаты совпадут.
Если for...in всё же нужен, фильтруйте собственные ключи через Object.hasOwn(obj, key) из ES2022. В остальных случаях проще Object.keys или Object.entries и обход через for...of.
Где спотыкаются
Говорят, что for...in перебирает вообще все свойства. Неперечисляемые, в том числе встроенные методы вроде toString, он не видит, иначе в любом цикле было бы по десятку лишних ключей.
Фильтруют через obj.hasOwnProperty(key). У объекта без прототипа такого метода нет, а у обычного его можно перекрыть собственным свойством, поэтому надёжнее Object.hasOwn.
Перебирают массивы через for...in. Индексы приходят строками, в перебор попадают лишние свойства массива и прототипа, а для элементов есть for...of и методы массива.