Наследование классов — механизм, позволяющий создавать классы (говорят подклассы) на основе других классов (называемых базовыми или суперклассами). Подклассы в таком случае «наследуют» структуру базовых классов, то есть получают возможность использовать все, что определено в базовом классе.
Механизм наследования — сложная система. Поэтому изучаться он будет в несколько приемов, на протяжении всего курса. Кроме того, не забываем что говоря про классы в JavaScript, мы на самом деле говорим про прототипы.
Рассмотрим наследование на примере структуры HTML. Каждый тег в HTML по-своему уникален. С другой стороны, все они имеют общие атрибуты и некоторые другие характеристики. Попробуем отобразить это с помощью иерархии классов.
// Базовый класс для всех тегов. Умеет работать с атрибутами.
class HTMLElement {
constructor(attributes = {}) {
this.attributes = attributes
}
setAttribute(key, value) {
this.attributes[key] = value
}
getAttribute(key) {
return this.attributes[key]
}
getTextContent() {
return this.body
}
setTextContent(body) {
this.body = body
}
stringifyAttributes() {
// build: key="value" key2="value2"
}
}
Конкретные элементы, представленные тегами в HTML, наследуют этот класс:
// Anchor — это ссылка. Класс HTMLAnchorElement описывает тег «a».
// Наследование выполняется через ключевое слово extends
class HTMLAnchorElement extends HTMLElement {
toString() {
// Родительский метод
const attrLine = this.stringifyAttributes()
// Родительский метод
const body = this.getTextContent()
return `<a${attrLine}>${body}</a>`
}
}
Наследование записывается так: A extends B
. Эта запись означает, что класс A наследует класс B. Теперь посмотрим, как работает наследование:
// Конструктор родителя
const anchor = new HTMLAnchorElement({ href: 'https://ru.hexlet.io' })
anchor.setTextContent('Hexlet')
console.log(`Anchor: ${anchor}`) // toString() вызывается автоматически
// => Anchor: <a href="https://ru.hexlet.io">Hexlet</a>
Внутри HTMLAnchorElement нет определения конструктора, но благодаря наследованию, этот класс имеет доступ ко всем свойствам суперкласса. JavaScript вызывает их автоматически при обращении к ним. В свою очередь, внутри toString()
вызываются методы, которых нет в текущих классах, поэтому они также берутся из родительского класса.
Цепочка наследования
Наследование классов в JavaScript — одиночное. Другими словами, наследоваться можно только от одного класса. Точно так же как и в Java. Множественное наследование в этих языках было убрано специально, из-за его высокой сложности и проблем, которые оно добавляет (например, коллизии методов и свойств). С другой стороны, сама по себе цепочка наследования может быть сколь угодно глубокой:
class D {}
class C extends D {}
class B extends C {}
class A extends B {}
Оператор проверки типа
Оператор instanceof
учитывает классы из цепочки наследования прототипов:
const anchor = new HTMLAnchorElement()
if (anchor instanceof HTMLElement) {
console.log('!!!')
}
// => !!!
Не забывайте, что подобные проверки закрывают возможность использовать полиморфизм. Иногда без них не обойтись, но в подавляющем большинстве случаев лучше завязываться на интерфейс объекта.
Дополнительные материалы
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.