Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Proto у функции-конструктора
Да, функция-конструктор имеет два важных прототипа, и это может быть источником путаницы. Разберёмся в деталях.
Два вида Proto
Каждая функция в JavaScript имеет два свойства, связанные с прототипами:
- Свойство
prototype— объект, который становится прототипом для новых экземпляров - Внутреннее свойство
[[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(); // "Рекс лает"
// За кулисами это всё та же работа с прототипами
Итог
Да, функция-конструктор имеет прототипы:
Constructor.prototype— прототип для экземпляров, создаваемых черезnewConstructor.__proto__(илиObject.getPrototypeOf(Constructor)) — прототип самой функции, обычно этоFunction.prototype
Это критически важно понимать для работы с наследованием и цепочками прототипов в JavaScript. В современном коде часто используют классы, но под капотом это всё ещё работает с прототипами.