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

Есть ли Proto у функци-конструктора?

1.3 Junior🔥 122 комментариев
#JavaScript Core

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

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

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

Proto у функции-конструктора

Да, функция-конструктор имеет два важных прототипа, и это может быть источником путаницы. Разберёмся в деталях.

Два вида Proto

Каждая функция в JavaScript имеет два свойства, связанные с прототипами:

  1. Свойство prototype — объект, который становится прототипом для новых экземпляров
  2. Внутреннее свойство [[Prototype]] (доступно как __proto__ или через Object.getPrototypeOf()) — сам прототип функции
// Функция-конструктор
function Animal(name) {
  this.name = name;
}

// 1. Свойство prototype
console.log(Animal.prototype);
// {
//   constructor: Animal,
//   __proto__: Object.prototype
// }

// 2. Внутренний [[Prototype]] функции
console.log(Object.getPrototypeOf(Animal));
// [Function: Function]

// 3. Доступ через __proto__
console.log(Animal.__proto__);
// [Function: Function]

Чему служит каждый proto

Свойство prototype Это source of truth для экземпляров объектов. Когда вы создаёте новый экземпляр с помощью new, его [[Prototype]] указывает на prototype конструктора.

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

Dog.prototype.bark = function() {
  return this.name + " говорит гав-гав!";
};

const dog = new Dog("Шарик");

// dog имеет свой [[Prototype]], который указывает на Dog.prototype
console.log(Object.getPrototypeOf(dog) === Dog.prototype);  // true

// Методы достаются через цепочку прототипов
console.log(dog.bark());  // "Шарик говорит гав-гав!"

Внутренний [[Prototype]] функции Это прототип самой функции. Функции в JavaScript — это объекты, поэтому они тоже имеют прототип. Обычно это Function.prototype.

function sayHello() {
  console.log("Hello");
}

// Функция наследует методы из Function.prototype
console.log(Object.getPrototypeOf(sayHello) === Function.prototype);  // true

// sayHello имеет методы Function.prototype
console.log(typeof sayHello.call);      // "function"
console.log(typeof sayHello.apply);     // "function"
console.log(typeof sayHello.bind);      // "function"

// Эти методы приходят из Function.prototype, не из sayHello.prototype

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

Это изображает полную картину:

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

const dog = new Animal("Дружок");

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

console.log(Object.getPrototypeOf(dog) === Animal.prototype);          // true
console.log(Object.getPrototypeOf(Animal.prototype) === Object.prototype);  // true
console.log(Object.getPrototypeOf(Object.prototype) === null);         // true

// Цепочка для самой функции:
// Animal -> Function.prototype -> Object.prototype -> null

console.log(Object.getPrototypeOf(Animal) === Function.prototype);     // true
console.log(Object.getPrototypeOf(Function.prototype) === Object.prototype);  // true

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

Добавление методов к прототипу

function Person(name, age) {
  this.name = name;
  this.age = age;
}

// Добавляем методы в Person.prototype
// Эти методы будут доступны для ВСЕ экземпляров
Person.prototype.greet = function() {
  return `Привет, я ${this.name}`;
};

Person.prototype.isAdult = function() {
  return this.age >= 18;
};

const alice = new Person("Алиса", 25);
const bob = new Person("Боб", 16);

console.log(alice.greet());     // "Привет, я Алиса"
console.log(bob.isAdult());     // false

// Оба объекта используют один и тот же метод из Person.prototype
console.log(alice.greet === bob.greet);  // true (один объект функции)

Наследование через прототипы

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

Animal.prototype.move = function() {
  console.log(this.name + " движется");
};

function Dog(name, breed) {
  Animal.call(this, name);  // Вызываем конструктор родителя
  this.breed = breed;
}

// Наследование: Dog.prototype должен указывать на Animal.prototype
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;  // Восстанавливаем правильный constructor

Dog.prototype.bark = function() {
  console.log(this.name + " лает");
};

const dog = new Dog("Рекс", "Овчарка");

dog.move();  // "Рекс движется" (из Animal.prototype)
dog.bark();  // "Рекс лает" (из Dog.prototype)

Проверка прототипов

function Vehicle(make) {
  this.make = make;
}

function Car(make, model) {
  Vehicle.call(this, make);
  this.model = model;
}

Car.prototype = Object.create(Vehicle.prototype);
Car.prototype.constructor = Car;

const car = new Car("Toyota", "Camry");

// Проверка через instanceof
console.log(car instanceof Car);      // true
console.log(car instanceof Vehicle);  // true
console.log(car instanceof Object);   // true

// Проверка через Object.getPrototypeOf
console.log(Object.getPrototypeOf(car) === Car.prototype);        // true
console.log(Object.getPrototypeOf(car) === Vehicle.prototype);    // false

// Проверка через Object.getOwnPropertyNames
console.log(Object.getOwnPropertyNames(Car.prototype));  // ["constructor", "bark", ...]

Важные отличия

function MyFunction() {}

// ❌ Неправильная путаница
// MyFunction.__proto__ — это прототип ФУНКЦИИ (Function.prototype)
// MyFunction.prototype — это прототип ЭКЗЕМПЛЯРОВ

// ✅ Правильно
console.log(MyFunction.__proto__ === Function.prototype);  // true
console.log(MyFunction.prototype !== Function.prototype);   // true (обычно)

const instance = new MyFunction();
console.log(Object.getPrototypeOf(instance) === MyFunction.prototype);  // true
console.log(Object.getPrototypeOf(instance) === Function.prototype);    // false

Modern JavaScript подход (class)

В современном JavaScript используют классы, которые скрывают сложность прототипов:

// Класс — это синтаксический сахар над прототипами
class Animal {
  constructor(name) {
    this.name = name;
  }

  move() {
    console.log(this.name + " движется");
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }

  bark() {
    console.log(this.name + " лает");
  }
}

const dog = new Dog("Рекс", "Овчарка");
dog.move();  // "Рекс движется"
dog.bark();  // "Рекс лает"

// За кулисами это всё та же работа с прототипами

Итог

Да, функция-конструктор имеет прототипы:

  1. Constructor.prototype — прототип для экземпляров, создаваемых через new
  2. Constructor.__proto__ (или Object.getPrototypeOf(Constructor)) — прототип самой функции, обычно это Function.prototype

Это критически важно понимать для работы с наследованием и цепочками прототипов в JavaScript. В современном коде часто используют классы, но под капотом это всё ещё работает с прототипами.