`__proto__` vs `prototype`
prototype— свойство функции-конструктора, задающее прототип будущих объектов;__proto__— внутренняя ссылка каждого объекта на его прототип в цепочке наследования.
Зачем нужно
Понимание разницы между prototype и __proto__ необходимо для понимания прототипного наследования — основного механизма ООП в JavaScript. Без этого невозможно осознанно использовать классы, Object.create, instanceof и отлаживать цепочки прототипов.
Где используется
- Определение методов на прототипе функции-конструктора
- Проверка цепочки прототипов через
instanceofиisPrototypeOf Object.create(proto)— создание объекта с заданным прототипом- Расширение встроенных классов (с осторожностью)
Концепция
Каждая функция имеет свойство prototype — объект, который станет [[Prototype Pattern]] (внутренний слот) всех экземпляров, созданных через new.
__proto__ — устаревший accessor, открывающий доступ к [[Prototype Pattern]] конкретного объекта. Современная альтернатива — Object.getPrototypeOf / Object.setPrototypeOf.
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function {
return `${this.name} говорит`;
};
const dog = new Animal('Шарик');
// prototype — свойство функции
console.log(Animal.prototype); // { speak: f, constructor: Animal }
// __proto__ — ссылка экземпляра на прототип
console.log(dog.__proto__ === Animal.prototype); // true
// Современный способ
console.log(Object.getPrototypeOf(dog) === Animal.prototype); // true
Цепочка прототипов (prototype chain)
function Vehicle(type) {
this.type = type;
}
Vehicle.prototype.describe = function {
return `Транспорт: ${this.type}`;
};
function Car(brand) {
Vehicle.call(this, 'car');
this.brand = brand;
}
// Настраиваем наследование
Car.prototype = Object.create(Vehicle.prototype);
Car.prototype.constructor = Car;
Car.prototype.honk = function {
return `${this.brand}: бип!`;
};
const bmw = new Car('BMW');
console.log(bmw.describe); // "Транспорт: car" — из Vehicle.prototype
console.log(bmw.honk); // "BMW: бип!" — из Car.prototype
// Цепочка: bmw.__proto__ → Car.prototype → Vehicle.prototype → Object.prototype → null
Object.create vs new
const animalProto = {
speak {
return `${this.name} говорит`;
}
};
// Object.create явно задаёт прототип
const cat = Object.create(animalProto);
cat.name = 'Мурка';
console.log(cat.speak); // "Мурка говорит"
console.log(Object.getPrototypeOf(cat) === animalProto); // true
Проверка принадлежности прототипу
console.log(bmw instanceof Car); // true
console.log(bmw instanceof Vehicle); // true
console.log(Car.prototype.isPrototypeOf(bmw)); // true
Частые ошибки
- Мутация
prototypeпосле создания объектов — замена всего объектаConstructor.prototype = {...}обрывает связь с уже созданными экземплярами; нужно добавлять свойства, а не перезаписывать объект, или восстанавливатьconstructor. - Прямое изменение
__proto__— очень медленная операция, разрушает оптимизации движка; используйтеObject.createилиObject.setPrototypeOfпри инициализации. - Путаница
prototypeу обычного объекта — обычные объекты не имеютprototype(только функции); у них есть__proto__.