Когда применяется ключевое слово Extends?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Применение ключевого слова extends в JavaScript/TypeScript
Ключевое слово extends является фундаментальной частью объектно-ориентированного программирования в JavaScript/TypeScript и применяется в нескольких ключевых контекстах для реализации механизма наследования.
Основные случаи применения
1. Наследование классов в JavaScript/TypeScript
extends используется для создания дочернего класса, который наследует свойства и методы родительского класса:
// Базовый (родительский) класс
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} издает звук`);
}
}
// Дочерний класс, наследуемый от Animal
class Dog extends Animal {
constructor(name, breed) {
super(name); // Вызов конструктора родительского класса
this.breed = breed;
}
speak() {
console.log(`${this.name} лает: Гав-гав!`);
}
fetch() {
console.log(`${this.name} приносит мяч`);
}
}
const myDog = new Dog('Бобик', 'Овчарка');
myDog.speak(); // "Бобик лает: Гав-гав!"
myDog.fetch(); // "Бобик приносит мяч"
2. Наследование встроенных классов
extends позволяет создавать кастомные классы на основе встроенных:
class CustomArray extends Array {
// Добавляем пользовательский метод
last() {
return this.length > 0 ? this[this.length - 1] : undefined;
}
// Переопределяем существующий метод
push(...items) {
console.log(`Добавлено ${items.length} элементов`);
return super.push(...items);
}
}
const arr = new CustomArray(1, 2, 3);
console.log(arr.last()); // 3
arr.push(4, 5); // "Добавлено 2 элементов"
3. TypeScript: расширение интерфейсов и типов
В TypeScript extends используется для создания производных интерфейсов:
// Базовый интерфейс
interface Vehicle {
brand: string;
startEngine(): void;
}
// Расширенный интерфейс
interface Car extends Vehicle {
doors: number;
drive(): void;
}
// Реализация расширенного интерфейса
class Sedan implements Car {
brand: string;
doors: number;
constructor(brand: string, doors: number) {
this.brand = brand;
this.doors = doors;
}
startEngine() {
console.log('Двигатель запущен');
}
drive() {
console.log('Машина едет');
}
}
4. TypeScript: Generic Constraints (ограничения дженериков)
extends устанавливает ограничения для универсальных типов:
// Ограничение: T должен иметь свойство length
function logLength<T extends { length: number }>(item: T): void {
console.log(`Длина: ${item.length}`);
}
logLength([1, 2, 3]); // Работает
logLength('строка'); // Работает
logLength({ length: 5 }); // Работает
// logLength(42); // Ошибка: number не имеет свойства length
5. TypeScript: Conditional Types (условные типы)
В продвинутых типах TypeScript extends используется для условной логики типов:
// Условный тип
type IsString<T> = T extends string ? true : false;
type A = IsString<'hello'>; // true
type B = IsString<number>; // false
// Использование в утилитарных типах
type ExtractString<T> = T extends string ? T : never;
type Result = ExtractString<string | number | boolean>; // string
Ключевые принципы и особенности
Принцип подстановки Барбары Лисков: Объекты дочернего класса должны быть заменяемы объектами родительского класса без нарушения работы программы.
Цепочка прототипов: При использовании extends создается иерархия прототипов:
class A {}
class B extends A {}
class C extends B {}
console.log(C.prototype.__proto__ === B.prototype); // true
console.log(B.prototype.__proto__ === A.prototype); // true
console.log(A.prototype.__proto__ === Object.prototype); // true
Модификаторы доступа: В TypeScript extends взаимодействует с модификаторами:
public- наследуются вездеprotected- наследуются в иерархииprivate- не наследуются
Практические рекомендации
- Используйте наследование осторожно: Предпочитайте композицию над наследованием там, где это уместно
- Следуйте принципу единой ответственности: Класс должен иметь только одну причину для изменения
- Избегайте глубоких иерархий: Глубокие цепочки наследования усложняют понимание кода
- Используйте абстрактные классы (TypeScript) для определения общего поведения:
abstract class Shape {
abstract getArea(): number;
display() {
console.log(`Площадь: ${this.getArea()}`);
}
}
class Circle extends Shape {
constructor(private radius: number) {
super();
}
getArea(): number {
return Math.PI * this.radius ** 2;
}
}
Ключевое слово extends является мощным инструментом для создания иерархий типов и классов, но требует осмысленного применения с учетом принципов SOLID и конкретных требований проекта.