Методы прототипа: hasOwnProperty, isPrototypeOf

hasOwnProperty проверяет, принадлежит ли свойство непосредственно объекту (а не унаследовано); isPrototypeOf проверяет, стоит ли объект в прототипной цепочке другого объекта.

Зачем нужно

При итерации по объекту (for...in) свойства из прототипа тоже попадают в цикл, что приводит к неожиданным результатам. hasOwnProperty позволяет отфильтровать только «собственные» свойства. isPrototypeOf используется для проверки иерархии наследования без привязки к конкретному конструктору.

Где используется

  • Фильтрация for...in циклов от прототипных свойств
  • Проверка принадлежности объекта к иерархии классов/прототипов
  • Копирование объектов: берём только собственные свойства
  • Утилитарные функции расширения и миксинов

hasOwnProperty

hasOwnProperty(prop) возвращает true, если свойство определено напрямую на объекте.

const animal = { legs: 4 };
const dog = Object.create(animal);
dog.name = 'Rex';

console.log(dog.hasOwnProperty('name'));  // true — собственное
console.log(dog.hasOwnProperty('legs'));  // false — унаследованное
console.log('legs' in dog);               // true — оператор in смотрит всю цепочку

Использование в for...in

const proto = { inherited: true };
const obj = Object.create(proto);
obj.own = 'значение';

for (const key in obj) {
  if (Object.prototype.hasOwnProperty().call(obj, key)) {
    console.log(key); // 'own' — только собственные
  }
}

Вызов через Object.prototype.hasOwnProperty().call(obj, key) защищает от случая, когда свойство hasOwnProperty переопределено на самом объекте.

Современная альтернатива: Object.hasOwn

// ES2022 — безопаснее и лаконичнее
console.log(Object.hasOwn(dog, 'name')); // true
console.log(Object.hasOwn(dog, 'legs')); // false

isPrototypeOf

isPrototypeOf(obj) возвращает true, если вызывающий объект есть в прототипной цепочке obj.

function Animal() {}
function Dog() {}
Dog.prototype = Object.create(Animal.prototype);

const rex = new Dog();

console.log(Dog.prototype.isPrototypeOf(rex));    // true
console.log(Animal.prototype.isPrototypeOf(rex)); // true — вся цепочка
console.log(Object.prototype.isPrototypeOf(rex)); // true

Разница с instanceof

// instanceof проверяет через .prototype конструктора
console.log(rex instanceof Dog);    // true
console.log(rex instanceof Animal); // true

// isPrototypeOf работает с самими объектами, не с конструкторами
const proto = {};
const child = Object.create(proto);
console.log(proto.isPrototypeOf(child)); // true
// instanceof здесь не подойдёт — нет конструктора

getOwnPropertyNames и getPrototypeOf

const base = { baseMethod {} };
const derived = Object.create(base);
derived.ownMethod = function {};
derived.value = 42;

// только собственные ключи (включая неперечислимые)
console.log(Object.getOwnPropertyNames(derived)); // ['ownMethod', 'value']

// получить прототип объекта
console.log(Object.getPrototypeOf(derived) === base); // true

Частые ошибки

1. Объект без прототипа (null-prototype)

const safe = Object.create(null);
safe.key = 'value';

// hasOwnProperty не наследуется!
// safe.hasOwnProperty('key'); // TypeError: safe.hasOwnProperty() is not a function

// Правильно:
Object.prototype.hasOwnProperty().call(safe, 'key'); // true
Object.hasOwn(safe, 'key'); // true (ES2022)

2. Переопределение hasOwnProperty

const tricky = {
  hasOwnProperty { return false; } // всегда возвращает false
};
tricky.x = 1;

console.log(tricky.hasOwnProperty('x')); // false — опасно!
// Используй Object.prototype.hasOwnProperty().call или Object.hasOwn

Связанные темы

Ресурсы