JavaScript изначально является прототипно-ориентированным языком, что
означает, что наследование объектов реализуется через прототипы, а не
через классы в традиционном смысле. Однако с появлением стандарта ES6
был введён синтаксис class, который упрощает работу с
объектами и делает код более читаемым, сохраняя при этом прототипную
природу языка.
Класс — это шаблон для создания объектов с общими свойствами и методами. Синтаксис класса выглядит следующим образом:
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
return `Привет, меня зовут ${this.name}`;
}
}
Создание экземпляра класса:
const user = new Person('Алексей', 30);
console.log(user.greet()); // Привет, меня зовут Алексей
В JavaScript каждый объект имеет скрытую ссылку на прототип
([[Prototype]]), который позволяет делегировать поиск
свойств. Прототипы формируют цепочку наследования (prototype chain).
Пример прототипного наследования без использования синтаксиса
class:
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
return `${this.name} издаёт звук`;
};
function Dog(name) {
Animal.call(this, name); // вызов конструктора родителя
}
Dog.prototype = Object.create(Animal.prototype); // создание цепочки прототипов
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
return `${this.name} лает`;
};
const dog = new Dog('Шарик');
console.log(dog.speak()); // Шарик издаёт звук
console.log(dog.bark()); // Шарик лает
Object.create создаёт новый объект с указанным
прототипом.constructor необходимо, чтобы
сохранить корректное указание на конструктор.Синтаксис class позволяет упростить создание подклассов
с использованием ключевого слова extends:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} издаёт звук`;
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // вызов конструктора родителя
this.breed = breed;
}
bark() {
return `${this.name} лает`;
}
}
const dog = new Dog('Бобик', 'Бульдог');
console.log(dog.speak()); // Бобик издаёт звук
console.log(dog.bark()); // Бобик лает
Классы могут содержать статические методы, которые вызываются на самом классе, а не на экземпляре:
class MathUtils {
static sum(a, b) {
return a + b;
}
}
console.log(MathUtils.sum(5, 7)); // 12
Классы позволяют создавать свойства с управляемым доступом:
class Rectangle {
constructor(width, height) {
this.width = width;
this.height = height;
}
get area() {
return this.width * this.height;
}
set dimensions({ width, height }) {
this.width = width;
this.height = height;
}
}
const rect = new Rectangle(10, 5);
console.log(rect.area); // 50
rect.dimensions = { width: 20, height: 10 };
console.log(rect.area); // 200
Во Vue.js прототипное наследование используется для расширения
функциональности компонентов и глобальных объектов. Например, при
добавлении методов в Vue.prototype они становятся
доступными во всех экземплярах Vue:
Vue.prototype.$log = function(message) {
console.log(`[Лог Vue]: ${message}`);
};
new Vue({
created() {
this.$log('Компонент создан');
}
});
provide/inject, что частично заменяет прямое использование
прототипа для расширения функциональности.