Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Для чего нужен Proto ([[Prototype]])
Краткий ответ
[[Prototype]] (или __proto__ в браузерах) — это механизм прототипного наследования в JavaScript. Каждый объект имеет скрытую ссылку на другой объект (его прототип), из которого он наследует свойства и методы. Это основа всей объектно-ориентированной модели в JavaScript.
Цель Proto: наследование и переиспользование кода
// Без прототипов пришлось бы копировать методы каждому объекту
const dog1 = {
name: 'Rex',
bark: function() { console.log(this.name + ' barks'); }
};
const dog2 = {
name: 'Max',
bark: function() { console.log(this.name + ' barks'); } // Дублирование!
};
// С прототипами — методы общие
const dogPrototype = {
bark() { console.log(this.name + ' barks'); }
};
const dog1 = Object.create(dogPrototype);
dog1.name = 'Rex';
const dog2 = Object.create(dogPrototype);
dog2.name = 'Max';
dog1.bark(); // Rex barks
dog2.bark(); // Max barks
Как работает цепочка прототипов (Prototype Chain)
Когда вы обращаетесь к свойству объекта, JavaScript ищет его так:
- В самом объекте
- В его прототипе ([[Prototype]])
- В прототипе прототипа
- И так далее, пока не найдёт или не достигнет null
const animal = {
eat() { console.log('Eating'); }
};
const dog = Object.create(animal);
dog.bark = function() { console.log('Barking'); };
dog.bark(); // "Barking" — найдено в самом dog
dog.eat(); // "Eating" — найдено в прототипе (animal)
dog.toString(); // [object Object] — найдено выше в цепочке (Object.prototype)
Цепочка прототипов
dog --[[Prototype]]--> animal --[[Prototype]]--> Object.prototype --[[Prototype]]--> null
Это и есть цепочка прототипов.
Способы создания объектов с прототипами
1. Object.create() — явное установление прототипа
const parent = {
greet() { console.log('Hello'); }
};
const child = Object.create(parent);
child.greet(); // "Hello"
console.log(child.hasOwnProperty('greet')); // false
console.log('greet' in child); // true — унаследовано
2. Конструкторские функции (старый способ)
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(this.name + ' makes a sound');
};
const dog = new Animal('Dog');
dog.speak(); // "Dog makes a sound"
// dog.[[Prototype]] === Animal.prototype
3. ES6 классы (синтаксический сахар над прототипами)
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a sound');
}
}
class Dog extends Animal {
speak() {
console.log(this.name + ' barks');
}
}
const dog = new Dog('Rex');
dog.speak(); // "Rex barks"
// Под капотом это всё ещё прототипное наследование
Доступ к прототипу
const parent = { x: 1 };
const child = Object.create(parent);
child.y = 2;
// Способы доступа к прототипу
console.log(Object.getPrototypeOf(child)); // { x: 1 }
console.log(child.__proto__); // { x: 1 } (не стандартно, но работает)
// Изменение прототипа (редко)
Object.setPrototypeOf(child, { x: 10 });
Практический пример: наследование
// Прототип для животных
const AnimalProto = {
eat() { console.log(this.name + ' is eating'); },
sleep() { console.log(this.name + ' is sleeping'); }
};
// Прототип для собак (наследует от животных)
const DogProto = Object.create(AnimalProto);
DogProto.bark = function() { console.log(this.name + ' is barking'); };
// Создание конкретной собаки
const myDog = Object.create(DogProto);
myDog.name = 'Buddy';
myDog.eat(); // "Buddy is eating" (от AnimalProto)
myDog.bark(); // "Buddy is barking" (от DogProto)
myDog.sleep(); // "Buddy is sleeping" (от AnimalProto)
Цепочка прототипов при ES6 классах
class Vehicle {
move() { console.log('Moving'); }
}
class Car extends Vehicle {
drive() { console.log('Driving'); }
}
const myCar = new Car();
// Цепочка:
// myCar --[[Prototype]]--> Car.prototype
// --[[Prototype]]--> Vehicle.prototype
// --[[Prototype]]--> Object.prototype
// --[[Prototype]]--> null
myCar.drive(); // "Driving" (в Car.prototype)
myCar.move(); // "Moving" (в Vehicle.prototype)
myCar.toString(); // "[object Object]" (в Object.prototype)
Важная разница: свойства vs методы
const proto = { x: 1 };
const obj = Object.create(proto);
obj.y = 2;
// Собственные свойства объекта
console.log(obj.hasOwnProperty('y')); // true
console.log(obj.hasOwnProperty('x')); // false
// Но доступны оба
console.log(obj.y); // 2
console.log(obj.x); // 1
// Когда меняем унаследованное свойство
obj.x = 10; // Создаёт своё свойство x, не меняет прототип
console.log(obj.x); // 10 (своё)
console.log(proto.x); // 1 (прототип не изменился)
console.log(obj.hasOwnProperty('x')); // true (теперь своё)
Часто встречающиеся ошибки
1. Путаница между прототипом и прототипом функции
function Dog() {}
// Dog.prototype — это объект, от которого наследуют экземпляры
Dog.prototype.bark = function() { console.log('Woof'); };
const dog = new Dog();
// dog.[[Prototype]] === Dog.prototype
// Dog.[[Prototype]] === Function.prototype (это другое!)
2. Изменение прототипа после создания объекта
const parent = { x: 1 };
const child = Object.create(parent);
parent.x = 2; // Меняем прототип
console.log(child.x); // 2 — изменилось! (смотрит на прототип)
child.x = 10; // Создаём своё свойство
parent.x = 20;
console.log(child.x); // 10 — своё свойство затеняет прототип
3. Performance: глубокие цепочки прототипов медленнее
// Плохо — очень глубокая цепочка
const a = { x: 1 };
const b = Object.create(a);
const c = Object.create(b);
const d = Object.create(c);
const e = Object.create(d);
const f = Object.create(e);
console.log(f.x); // JavaScript ищет x через 5 уровней прототипов
// Хорошо — используйте композицию или копирование для часто используемых методов
Вывод
- [[Prototype]] — механизм наследования в JavaScript
- Цепочка прототипов позволяет переиспользовать методы
- Object.create() — явное создание объекта с прототипом
- ES6 классы — удобный синтаксис поверх прототипов
- hasOwnProperty() помогает различить собственные свойства от унаследованных
- Не используйте
__proto__напрямую в production коде - Помните о цепочке прототипов при отладке