Чем собственные свойства отличаются от унаследованных в JavaScript
Что проверяют
Понимаете ли вы устройство цепочки прототипов и чем перебор собственных свойств отличается от перебора вместе с унаследованными. По ответу судят, будете ли вы ловить сюрпризы при копировании, сериализации и обходе объектов.
Как отвечать
Собственное свойство лежит в самом объекте, унаследованное движок нашёл дальше по цепочке [[Prototype]]. Чтение идёт по цепочке вверх, а запись всегда создаёт собственное свойство в самом объекте и затеняет прототипное.
Инструменты удобно называть парами:
Object.hasOwn(obj, k)иobj.hasOwnProperty(k)смотрят только собственные, операторinпроверяет всю цепочку;Object.keys,Object.entriesиJSON.stringifyберут собственные перечислимые, аfor...inидёт и по прототипам;Object.getOwnPropertyNamesдобавит неперечислимые,Object.getOwnPropertySymbolsсимвольные ключи.
const proto = { shared: 1 };
const obj = Object.create(proto);
obj.own = 2;
Object.keys(obj); // ["own"]
"shared" in obj; // true
Object.hasOwn(obj, "shared"); // falseПолезно связать это с классами: методы класса лежат в prototype, то есть унаследованы и неперечислимы, а поля и всё присвоенное через this в конструкторе собственные. Поэтому спред и JSON.stringify теряют методы, и объект после такой копии перестаёт быть экземпляром.
Скажите и почему Object.hasOwn надёжнее метода: у объекта из Object.create(null) метода hasOwnProperty нет, а своё свойство с таким именем ломает вызов.
Где спотыкаются
Обходят объект через for...in и получают чужие ключи из прототипа. Особенно неприятно на массивах и на объектах, чей прототип кто-то расширил. Безопаснее for...of по Object.keys или фильтр через Object.hasOwn.
Второе: считают, что копия переносит наследование. Спред и Object.assign копируют только собственные перечислимые свойства, прототип теряется, а геттеры при копировании вычисляются и превращаются в обычные значения.
Третье: путают затенение с изменением прототипа. Присваивание создаёт собственное свойство и на соседних объектах не сказывается, а вот мутация объекта или массива, лежащего в прототипе, видна сразу всем наследникам.