Vue Front-end Инженер

Vue Front-end Инженер

Роадмап навыков для прокачки

Свойства __proto__ и prototype

Язык JavaScript (ES5)Прототипы и наследованиеОсновное

Основная идея

__proto__ и prototype — два разных свойства, которые часто путают. __proto__ — ссылка на прототип объекта (откуда он наследует). prototype — свойство функций, определяющее прототип для объектов, созданных через new.

Ключевые аспекты

  • proto — есть у каждого объекта, указывает на его прототип
  • prototype — есть только у функций, используется при вызове с new
  • [[Prototype]] — внутреннее свойство, к которому __proto__ даёт доступ
  • new F() — создаёт объект с __proto__ === F.prototype

Плюсы и минусы

СвойствоЕсть уНазначение
protoВсех объектовСсылка на прототип объекта
prototypeТолько функцийБудущий прототип для new

Частые ошибки на собеседованиях

  • Путают __proto__ (у всех объектов) и prototype (только у функций)
  • Не понимают связь: (new F()).__proto__ === F.prototype
  • Думают, что prototype — это прототип самой функции (нет, это Function.prototype)
  • Не знают, что стрелочные функции не имеют prototype (ES6)

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

Одна из самых запутанных тем в JavaScript — разница между __proto__ и prototype. Оба связаны с прототипами, но выполняют разные роли.

Запомните: __proto__ есть у каждого объекта. prototype есть только у функций.


Базовая теория

proto — ссылка на прототип

Каждый объект имеет внутреннее свойство [[Prototype]] — ссылку на его прототип. __proto__ — это геттер/сеттер для доступа к этому свойству.

Code Example 1: Что выведут rabbit.eats и rabbit.__proto__ === animal?

js
var animal = { eats: true };
var rabbit = { jumps: true };
 
rabbit.__proto__ = animal;
 
// rabbit наследует от animal
console.log(rabbit.eats); // true
console.log(rabbit.__proto__ === animal); // true

prototype — свойство функций

Свойство prototype есть только у функций. Оно определяет, каким будет __proto__ у объектов, созданных через new.

Code Example 2: Что выведет bunny.__proto__ === Rabbit.prototype? Почему?

js
function Rabbit(name) {
  this.name = name;
}
 
Rabbit.prototype.jump = function() {
  console.log(this.name + ' прыгает');
};
 
var bunny = new Rabbit('Кролик');
 
// bunny.__proto__ === Rabbit.prototype
console.log(bunny.__proto__ === Rabbit.prototype); // true
bunny.jump(); // "Кролик прыгает"

Ключевая связь

graph LR A[new Rabbit] -->|создаёт| B[bunny] C[Rabbit.prototype] -->|становится| D[bunny.__proto__]

Code Example 3: Какова связь между bunny.__proto__, Rabbit.prototype и Rabbit.prototype.constructor?

js
function Rabbit() {}
 
var bunny = new Rabbit();
 
// Главная формула!
console.log(bunny.__proto__ === Rabbit.prototype); // true
 
// Дополнительно
console.log(Rabbit.prototype.constructor === Rabbit); // true
console.log(bunny.constructor === Rabbit); // true (унаследовано)

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

Разница на практике

Code Example 4: Что выведет cat.prototype? В чём разница между cat.__proto__ и Animal.prototype?

js
function Animal() {}
Animal.prototype.eats = true;
 
var cat = new Animal();
 
// __proto__ — прототип объекта cat
console.log(cat.__proto__ === Animal.prototype); // true
 
// prototype — свойство функции Animal
console.log(Animal.prototype); // { eats: true, constructor: Animal }
 
// У объекта cat НЕТ свойства prototype
console.log(cat.prototype); // undefined

Что является прототипом самой функции?

Code Example 5: Чему равен Example.__proto__? Почему Example.prototype !== Example.__proto__?

js
function Example() {}
 
// Прототип функции Example — это Function.prototype
console.log(Example.__proto__ === Function.prototype); // true
 
// НЕ путать с Example.prototype!
console.log(Example.prototype !== Example.__proto__); // true
 
// Example.prototype — для объектов, созданных new Example()
// Example.__proto__ — прототип самой функции Example

Визуализация всех связей

js
function User(name) {
  this.name = name;
}
 
User.prototype.greet = function() {
  console.log('Привет, ' + this.name);
};
 
var ivan = new User('Иван');
graph TD A[ivan] -->|__proto__| B[User.prototype] B -->|__proto__| C[Object.prototype] C -->|__proto__| D[null] E[User function] -->|prototype| B E -->|__proto__| F[Function.prototype] F -->|__proto__| C

Сравнительная таблица

Характеристикаprotoprototype
Есть уВсех объектовТолько функций
Указывает наПрототип объектаБудущий прототип для new
Стандарт ES5Нет (но поддерживается)Да
ЭквивалентObject.getPrototypeOf()

Пограничные кейсы

Функция — тоже объект

js
function myFunc() {}
 
// У функции есть оба свойства!
 
// prototype — для объектов, созданных new myFunc()
console.log(myFunc.prototype); // { constructor: myFunc }
 
// __proto__ — прототип самой функции
console.log(myFunc.__proto__ === Function.prototype); // true

Object и Function

Code Example 6: Что выведут все console.log? Почему Function.__proto__ === Function.prototype?

js
// Object — функция-конструктор
console.log(typeof Object); // "function"
console.log(Object.prototype); // { toString, hasOwnProperty, ... }
 
// Object.__proto__ — это Function.prototype
console.log(Object.__proto__ === Function.prototype); // true
 
// Function.__proto__ — тоже Function.prototype!
console.log(Function.__proto__ === Function.prototype); // true
 
// Круговая ссылка
console.log(Function.prototype.__proto__ === Object.prototype); // true
⚠️

Function.prototype — уникальный объект, который является прототипом всех функций, включая саму функцию Function.

constructor

Code Example 7: Как свойство constructor связано с prototype? Можно ли создать новый объект через user.constructor?

js
function User() {}
 
// prototype имеет свойство constructor
console.log(User.prototype.constructor === User); // true
 
var user = new User();
 
// Объект наследует constructor
console.log(user.constructor === User); // true
 
// Можно создать новый объект того же типа
var user2 = new user.constructor();
console.log(user2 instanceof User); // true

Как изменения в prototype влияют на объекты

Code Example 8: Почему cat.speak() работает, хотя метод speak был добавлен после создания cat?

js
function Animal() {}
 
var cat = new Animal();
 
// Добавляем метод в prototype
Animal.prototype.speak = function() {
  console.log('Мяу');
};
 
// Существующий объект получает метод!
cat.speak(); // "Мяу"
 
// Потому что cat.__proto__ === Animal.prototype

Типичные ошибки

Ошибка 1: путать prototype и proto

Code Example 9: Что выведут dog.prototype и dog.__proto__? В чём ошибка при обращении к dog.prototype?

js
function Dog() {}
var dog = new Dog();
 
// ❌ Неправильное понимание
// "prototype объекта dog"
console.log(dog.prototype); // undefined — у объекта нет prototype!
 
// ✅ Правильно
// "прототип объекта dog"
console.log(dog.__proto__); // Dog.prototype

Ошибка 2: думать, что prototype — прототип функции

Code Example 10: Что выведет Cat.__proto__ === Cat.prototype? Объясните разницу между этими двумя свойствами.

js
function Cat() {}
 
// ❌ Неправильно: prototype НЕ прототип самой функции Cat
console.log(Cat.__proto__ === Cat.prototype); // false
 
// ✅ Правильно:
// Cat.__proto__ — прототип функции Cat (Function.prototype)
// Cat.prototype — прототип для объектов new Cat()

Вопросы интервьюера

Q: В чём разница между proto и prototype?

__proto__ есть у каждого объекта и указывает на его прототип. prototype есть только у функций и определяет прототип для объектов, создаваемых через new.

Q: Чему равен (new F()).proto?

F.prototype. При вызове new F() создаётся объект, у которого __proto__ устанавливается равным F.prototype.

Q: Есть ли prototype у обычных объектов?

Нет. prototype — свойство только функций. У объектов есть __proto__.

Q: Что такое constructor?

Свойство prototype.constructor указывает на саму функцию-конструктор. Объекты наследуют его и могут использовать для создания новых экземпляров.


Источники

Code Example 1: __proto__ — link to prototype

❓ Что выведут rabbit.eats и rabbit.__proto__ === animal?

js
var animal = { eats: true };
var rabbit = { jumps: true };
 
rabbit.__proto__ = animal;
 
console.log(rabbit.eats);
console.log(rabbit.__proto__ === animal);

Code Example 2: prototype — property of functions

❓ Что выведет bunny.__proto__ === Rabbit.prototype? Почему?

js
function Rabbit(name) {
  this.name = name;
}
 
Rabbit.prototype.jump = function() {
  console.log(this.name + ' прыгает');
};
 
var bunny = new Rabbit('Кролик');
 
console.log(bunny.__proto__ === Rabbit.prototype);
bunny.jump();

Code Example 3: Key connection

❓ Какова связь между bunny.__proto__, Rabbit.prototype и Rabbit.prototype.constructor?

js
function Rabbit() {}
 
var bunny = new Rabbit();
 
console.log(bunny.__proto__ === Rabbit.prototype);
 
console.log(Rabbit.prototype.constructor === Rabbit);
console.log(bunny.constructor === Rabbit);

Code Example 4: Difference in practice

❓ Что выведет cat.prototype? В чём разница между cat.__proto__ и Animal.prototype?

js
function Animal() {}
Animal.prototype.eats = true;
 
var cat = new Animal();
 
console.log(cat.__proto__ === Animal.prototype);
 
console.log(Animal.prototype);
 
console.log(cat.prototype);

Code Example 5: Prototype of function itself

❓ Чему равен Example.__proto__? Почему Example.prototype !== Example.__proto__?

js
function Example() {}
 
console.log(Example.__proto__ === Function.prototype);
 
console.log(Example.prototype !== Example.__proto__);

Code Example 6: Object and Function

❓ Что выведут все console.log? Почему Function.__proto__ === Function.prototype?

js
console.log(typeof Object);
console.log(Object.prototype);
 
console.log(Object.__proto__ === Function.prototype);
 
console.log(Function.__proto__ === Function.prototype);
 
console.log(Function.prototype.__proto__ === Object.prototype);

Code Example 7: constructor

❓ Как свойство constructor связано с prototype? Можно ли создать новый объект через user.constructor?

js
function User() {}
 
console.log(User.prototype.constructor === User);
 
var user = new User();
 
console.log(user.constructor === User);
 
var user2 = new user.constructor();
console.log(user2 instanceof User);

Code Example 8: Changes in prototype affect objects

❓ Почему cat.speak() работает, хотя метод speak был добавлен после создания cat?

js
function Animal() {}
 
var cat = new Animal();
 
Animal.prototype.speak = function() {
  console.log('Мяу');
};
 
cat.speak();

Code Example 9: Confusing prototype and __proto__

❓ Что выведут dog.prototype и dog.__proto__? В чём ошибка при обращении к dog.prototype?

js
function Dog() {}
var dog = new Dog();
 
console.log(dog.prototype);
 
console.log(dog.__proto__);

Code Example 10: prototype is NOT function's own prototype

❓ Что выведет Cat.__proto__ === Cat.prototype? Объясните разницу между этими двумя свойствами.

js
function Cat() {}
 
console.log(Cat.__proto__ === Cat.prototype);