Возможно ли отобразить Web страницу внутри Web страницы?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое прототип и прототипальное наследование
Прототип — это механизм, на котором основана вся объектная система JavaScript. Это может быть сложным концептом, но он критически важен для понимания языка.
Что такое прототип
Определение
Каждый объект в JavaScript имеет скрытое свойство [[Prototype]] (внутреннее свойство), которое указывает на другой объект — его прототип. Когда ты ищешь свойство на объекте, JavaScript сначала ищет на самом объекте, потом на его прототипе, потом на прототипе прототипа, и так до конца цепи.
// У каждого объекта есть [[Prototype]]
const obj = {};
console.log(Object.getPrototypeOf(obj)); // Object {} - это базовый прототип
// Или через __proto__ (не рекомендуется в продакшене)
console.log(obj.__proto__); // То же самое
Цепь прототипов (Prototype Chain)
const animal = {
sound: 'generic sound',
makeSound() {
console.log(this.sound);
}
};
const dog = Object.create(animal);
dog.sound = 'woof';
dog.makeSound(); // 'woof'
console.log(dog.hasOwnProperty('sound')); // true
console.log(dog.hasOwnProperty('makeSound')); // false (на прототипе)
// Цепь: dog -> animal -> Object.prototype -> null
Как работает поиск свойства
Поиск идет по цепи
const grandParent = { level: 'grand' };
const parent = Object.create(grandParent);
parent.level = 'parent';
const child = Object.create(parent);
// child.level не определен
console.log(child.level); // 'parent' (найдено на parent)
console.log(child.age); // undefined (не найдено нигде)
// Процесс:
// 1. Есть ли child.level? Нет
// 2. Есть ли Object.getPrototypeOf(child).level? Да! 'parent'
// 3. Возвращаем 'parent'
hasOwnProperty vs in
const parent = { name: 'Parent' };
const child = Object.create(parent);
child.age = 5;
console.log(child.hasOwnProperty('age')); // true (прямое свойство)
console.log(child.hasOwnProperty('name')); // false (на прототипе)
console.log('age' in child); // true (прямое свойство)
console.log('name' in child); // true (включая прототип!)
Функции-конструкторы и новый способ (классы)
Старый способ: функции-конструкторы
function Animal(name) {
this.name = name;
}
// Свойства добавляются конструктору
Animal.prototype.sound = 'generic';
Animal.prototype.makeSound = function() {
console.log(`${this.name} makes ${this.sound}`);
};
const dog = new Animal('Шарик');
dog.sound = 'woof';
dog.makeSound(); // 'Шарик makes woof'
// Цепь: dog -> Animal.prototype -> Object.prototype -> null
Как работает new
// new делает вот что:
function Person(name) {
// 1. Создает новый объект
// const obj = {};
// 2. Устанавливает [[Prototype]] на Person.prototype
// Object.setPrototypeOf(obj, Person.prototype);
// 3. Вызывает функцию с this = obj
this.name = name; // obj.name = 'Иван'
// 4. Возвращает obj (если не вернул другой объект)
// return obj;
}
const person = new Person('Иван');
console.log(person.name); // 'Иван'
console.log(Object.getPrototypeOf(person) === Person.prototype); // true
Современный способ: классы (синтаксический сахар)
// Классы — это просто синтаксис для функций-конструкторов
class Animal {
constructor(name) {
this.name = name;
}
makeSound() {
console.log(`${this.name} makes sound`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
makeSound() {
console.log(`${this.name} barks`);
}
}
const dog = new Dog('Шарик', 'Овчарка');
dog.makeSound(); // 'Шарик barks'
// Под капотом это то же самое что функции-конструкторы!
// Только удобнее и понятнее
Наследование через прототипы
Способ 1: Object.create (рекомендуется)
const parent = {
greet() {
return `Hello, I'm ${this.name}`;
}
};
const child = Object.create(parent);
child.name = 'Child';
console.log(child.greet()); // 'Hello, I'm Child'
Способ 2: Классы (современный)
class Parent {
greet() {
return `Hello, I'm ${this.name}`;
}
}
class Child extends Parent {
constructor(name) {
super();
this.name = name;
}
}
const child = new Child('Иван');
console.log(child.greet()); // 'Hello, I'm Иван'
Способ 3: Старый способ (не используй)
function Parent() {}
Parent.prototype.greet = function() {
return `Hello, I'm ${this.name}`;
};
function Child(name) {
this.name = name;
}
// Неправильно!
// Child.prototype = Parent.prototype; // Они будут одно и то же!
// Правильно:
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child; // Восстанавливаем constructor
const child = new Child('Иван');
console.log(child.greet()); // 'Hello, I'm Иван'
Переопределение методов (Override)
class Animal {
sound() {
return 'generic sound';
}
}
class Dog extends Animal {
sound() {
return 'woof'; // Переопределяем
}
}
class Cat extends Animal {
sound() {
return 'meow';
}
}
const dog = new Dog();
const cat = new Cat();
const animal = new Animal();
console.log(dog.sound()); // 'woof'
console.log(cat.sound()); // 'meow'
console.log(animal.sound()); // 'generic sound'
instanceof работает через прототипы
class Animal {}
class Dog extends Animal {}
const dog = new Dog();
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true (через цепь!)
console.log(dog instanceof Object); // true
// instanceof проверяет:
// Dog.prototype в цепи dog
// Animal.prototype в цепи dog
// Object.prototype в цепи dog
Свойства vs методы
class Counter {
constructor(start = 0) {
this.value = start; // Свойство
}
increment() { // Метод
this.value++;
}
}
const c = new Counter(5);
console.log(c.hasOwnProperty('value')); // true (свойство объекта)
console.log(c.hasOwnProperty('increment')); // false (на прототипе)
console.log('increment' in c); // true (найдено в цепи)
Производительность
Доступ к свойствам медленнее, чем методам
// Быстро: метод на прототипе (одно поднятие)
class Foo {
method() { return 42; }
}
// Медленнее: каждый объект имеет свою функцию
function Bar() {
this.method = () => 42;
}
// Что дольше ищется:
obj.method(); // 1 шаг (на прототипе)
obj.property; // 1 шаг (на объекте) или несколько (в цепи)
Практический пример
class Vehicle {
constructor(brand) {
this.brand = brand;
}
describe() {
return `Марка: ${this.brand}`;
}
}
class Car extends Vehicle {
constructor(brand, model) {
super(brand);
this.model = model;
}
describe() {
return super.describe() + `, Модель: ${this.model}`;
}
}
class Tesla extends Car {
constructor(model) {
super('Tesla', model);
}
describe() {
return super.describe() + ' (Электро)';
}
}
const myTesla = new Tesla('Model 3');
console.log(myTesla.describe());
// 'Марка: Tesla, Модель: Model 3 (Электро)'
// Цепь: myTesla -> Tesla -> Car -> Vehicle -> Object
Заключение
Прототипы — это фундамент JavaScript:
- Каждый объект имеет [[Prototype]]
- Поиск свойства идет по цепи прототипов
- Классы — это синтаксис для прототипального наследования
- Используй классы в современном коде, они понятнее
- Понимание прототипов помогает избежать ошибок с
this,newи наследованием