← Назад к вопросам

Как понять что цепочка прототипов дошла до конца?

2.3 Middle🔥 151 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Цепочка прототипов в JavaScript

Цепочка прототипов - это механизм наследования в JavaScript. Расскажу как она работает и как определить конец.

Что такое цепочка прототипов

Каждый объект в JavaScript имеет скрытое свойство [[Prototype]], которое указывает на его прототип:

// Создать объект
const person = {
  name: 'John',
  age: 30
};

// Цепочка выглядит так:
// person -> Object.prototype -> null
//
// Когда мы ищем свойство:
// 1. Сначала ищем в самом объекте (person.name)
// 2. Если не найдено, ищем в прототипе (Object.prototype)
// 3. Если не найдено, ищем в прототипе прототипа
// 4. До конца цепочки - null

console.log(person.toString); // Найдётся в Object.prototype
console.log(person.hasOwnProperty); // Тоже из Object.prototype

Как понять что цепочка закончилась

Способ 1: Проверка на null

const obj = { a: 1 };

// Получить прототип
let proto = Object.getPrototypeOf(obj);

while (proto !== null) {
  console.log('Прототип:', proto);
  proto = Object.getPrototypeOf(proto);
  // Цикл заканчивается когда proto === null
}

// Вывод:
// Прототип: { }
// Прототип: null (КОНЕЦ ЦЕПОЧКИ)

Способ 2: Проверка с Object.prototype

const obj = { name: 'John' };

// Конец цепочки - это Object.prototype
console.log(Object.getPrototypeOf(Object.prototype)); // null

// Проверить, дошли ли мы до конца
let current = obj;
while (current !== null) {
  console.log('Уровень:', current);
  current = Object.getPrototypeOf(current);
}

// Результат:
// Уровень: { name: 'John' }
// Уровень: Object {}  <- это Object.prototype
// Уровень: null      <- КОНЕЦ

Визуализация цепочки

function visualizePrototypeChain(obj) {
  let chain = [];
  let current = obj;
  
  while (current !== null) {
    chain.push(current.constructor.name);
    current = Object.getPrototypeOf(current);
  }
  
  return chain.join(' -> ') + ' -> null';
}

// Примеры
console.log(visualizePrototypeChain({}));
// Объект -> Object -> null

console.log(visualizePrototypeChain([]));
// Array -> Object -> null

console.log(visualizePrototypeChain('hello'));
// String -> Object -> null

Проверка принадлежности к цепочке

const animal = { eats: true };
const dog = Object.create(animal);
dog.barks = true;

// Проверить есть ли свойство в объекте или в цепочке
console.log('eats' in dog); // true (из цепочки)
console.log('barks' in dog); // true (собственное)
console.log('meows' in dog); // false (нет в цепочке)

// Проверить, собственное ли свойство
console.log(dog.hasOwnProperty('barks')); // true
console.log(dog.hasOwnProperty('eats')); // false (это в цепочке)

// Современный способ
console.log(Object.hasOwn(dog, 'barks')); // true
console.log(Object.hasOwn(dog, 'eats')); // false

Практические примеры

С функциями-конструкторами

function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  console.log(this.name + ' makes a sound');
};

function Dog(name) {
  Animal.call(this, name);
}

// Установить прототип
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

const dog = new Dog('Rex');

// Цепочка: dog -> Dog.prototype -> Animal.prototype -> Object.prototype -> null

console.log(Object.getPrototypeOf(dog)); // Dog.prototype
console.log(Object.getPrototypeOf(Object.getPrototypeOf(dog))); // Animal.prototype
console.log(Object.getPrototypeOf(
  Object.getPrototypeOf(
    Object.getPrototypeOf(dog)
  )
)); // Object.prototype

console.log(
  Object.getPrototypeOf(
    Object.getPrototypeOf(
      Object.getPrototypeOf(
        Object.getPrototypeOf(dog)
      )
    )
  )
); // null <- КОНЕЦ ЦЕПОЧКИ

С классами (ES6)

class Animal {
  speak() {
    return 'sound';
  }
}

class Dog extends Animal {
  bark() {
    return 'woof';
  }
}

const dog = new Dog();

// Обход цепочки
let level = 0;
let current = dog;
while (current !== null) {
  console.log(`Уровень ${level}:`, current.constructor.name);
  current = Object.getPrototypeOf(current);
  level++;
}

// Уровень 0: Dog
// Уровень 1: Animal
// Уровень 2: Object
// Уровень 3: null

Инструменты для исследования

// 1. Получить всю цепочку в массив
function getPrototypeChain(obj) {
  const chain = [obj];
  let proto = Object.getPrototypeOf(obj);
  
  while (proto !== null) {
    chain.push(proto);
    proto = Object.getPrototypeOf(proto);
  }
  
  return chain;
}

const arr = [1, 2, 3];
const chain = getPrototypeChain(arr);
console.log('Длина цепочки:', chain.length); // 3
console.log('Последний элемент это null?', chain[chain.length - 1] === Object.prototype);

// 2. Вывести все свойства из цепочки
function getAllProperties(obj) {
  const props = new Set();
  let current = obj;
  
  while (current !== null) {
    Object.getOwnPropertyNames(current).forEach(prop => props.add(prop));
    current = Object.getPrototypeOf(current);
  }
  
  return Array.from(props);
}

Проверка: дошли ли до конца

const isEndOfChain = (proto) => proto === null;
const isObjectPrototype = (proto) => proto === Object.prototype;
const isLastBeforeNull = (proto) => Object.getPrototypeOf(proto) === null;

// Примеры
let current = { x: 1 };
while (current !== null) { // Проверка на null
  console.log(current);
  current = Object.getPrototypeOf(current);
}

Выводы

  1. Цепочка прототипов заканчивается когда Object.getPrototypeOf() возвращает null
  2. Перед null всегда находится Object.prototype
  3. Используй Object.getPrototypeOf() для навигации по цепочке
  4. Проверяй proto !== null в цикле
  5. Используй hasOwnProperty() или Object.hasOwn() чтобы различить собственные свойства от унаследованных
  6. Инспектируй цепочку в DevTools через Object tab в консоли
Как понять что цепочка прототипов дошла до конца? | PrepBro