Herança - JavaScript
Classes podem herdar de outras classes. A herança permite reduzir a quantidade de código nos classes derivadas. Por exemplo, considere as seguintes classes:
class Person {
name;
age;
print() {
console.log(`Name: ${this.name} Age: ${this.age}`);
}
}
class Employee {
name;
age;
company;
print() {
console.log(`Name: ${this.name} Age: ${this.age}`);
}
work() {
console.log(`${this.name} works in ${this.company}`);
}
}
const tom = new Person();
tom.name = "Tom";
tom.age = 34;
const bob = new Employee();
bob.name = "Bob";
bob.age = 36;
bob.company = "Google";
tom.print(); // Name: Tom Age: 34
bob.print(); // Name: Bob Age: 36
bob.work(); // Bob works in Google
Aqui, temos duas classes: Person
Employee
Employee
Person
name
age
print
A herança permite que uma classe obtenha automaticamente funcionalidades de outras classes, reduzindo assim a quantidade de código. Para herdar de uma classe, usamos a palavra-chave extends
class Base {}
class Derived extends Base {}
Após o nome da classe derivada, colocamos a palavra-chave extends
Assim, modificamos as classes Person
Employee
class Person {
name;
age;
print() {
console.log(`Name: ${this.name} Age: ${this.age}`);
}
}
class Employee extends Person {
company;
work() {
console.log(`${this.name} works in ${this.company}`);
}
}
const tom = new Person();
tom.name = "Tom";
tom.age = 34;
const bob = new Employee();
bob.name = "Bob";
bob.age = 36;
bob.company = "Google";
tom.print(); // Name: Tom Age: 34
bob.print(); // Name: Bob Age: 36
bob.work(); // Bob works in Google
Agora, a classe Employee
Person
Person
Employee
Employee
name
age
print
Employee
Herança de Classe com Construtor
Junto com toda a funcionalidade, a classe derivada também herda o construtor da classe base. Por exemplo, definimos no classe base Person um construtor:
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
print() {
console.log(`Name: ${this.name} Age: ${this.age}`);
}
}
class Employee extends Person {
company;
work() {
console.log(`${this.name} works in ${this.company}`);
}
}
const tom = new Person("Tom", 34);
tom.print(); // Name: Tom Age: 34
const sam = new Employee("Sam", 25); // construtor herdado
sam.print(); // Name: Sam Age: 25
Neste caso, a classe Person
Employee
Employee
Definindo um Construtor na Classe Derivada e a Palavra-Chave super
A classe derivada também pode definir seu próprio construtor. Se a classe derivada define um construtor, então o construtor da classe base deve ser chamado dentro dele. Para acessar a funcionalidade da classe base, incluindo o construtor, usamos a palavra-chave super
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
print() {
console.log(`Name: ${this.name} Age: ${this.age}`);
}
}
class Employee extends Person {
constructor(name, age, company) {
super(name, age);
this.company = company;
}
work() {
console.log(`${this.name} works in ${this.company}`);
}
}
const tom = new Person("Tom", 34);
tom.print(); // Name: Tom Age: 34
const sam = new Employee("Sam", 25, "Google");
sam.print(); // Name: Sam Age: 25
sam.work(); // Sam works in Google
A classe Employee
Person
super(name, age)
Person
this
Sobrescrevendo Métodos da Classe Base
Assim como com o construtor, a classe derivada pode sobrescrever métodos da classe base. Por exemplo, no exemplo acima, o método print()
Person
print()
print()
Employee
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
print() {
console.log(`Name: ${this.name} Age: ${this.age}`);
}
}
class Employee extends Person {
constructor(name, age, company) {
super(name, age);
this.company = company;
}
print() {
console.log(`Name: ${this.name} Age: ${this.age}`);
console.log(`Company: ${this.company}`);
}
}
const sam = new Employee("Sam", 25, "Google");
sam.print(); // Name: Sam Age: 25
// Company: Google
No entanto, no código acima, a primeira linha do método print()
print()
Person
print()
super
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
print() {
console.log(`Name: ${this.name} Age: ${this.age}`);
}
}
class Employee extends Person {
constructor(name, age, company) {
super(name, age);
this.company = company;
}
print() {
super.print();
console.log(`Company: ${this.company}`);
}
}
const sam = new Employee("Sam", 25, "Google");
sam.print(); // Name: Sam Age: 25
// Company: Google
Assim, a chamada super.print();
this
super
Herança e Campos e Métodos Privados
Ao trabalhar com herança, é importante considerar que a classe derivada pode acessar qualquer funcionalidade da classe base, exceto campos e métodos privados. Por exemplo:
class Person {
#name;
constructor(name, age) {
this.#name = name;
this.age = age;
}
print() {
console.log(`Name: ${this.#name} Age: ${this.age}`);
}
}
class Employee extends Person {
constructor(name, age, company) {
super(name, age);
this.company = company;
}
print() {
super.print();
console.log(`Company: ${this.company}`);
}
work() {
console.log(`${this.#name} works in ${this.company}`); // Erro - campo #name não está acessível em Employee
}
}
Neste caso, o campo #name
Person
this.#name
super.#name
Verificação da Pertinência de um Objeto a uma Classe
O fato de uma classe derivada ser herdada de uma classe base significa que um objeto da classe derivada também é um objeto da classe base. Podemos verificar a qual classe um objeto pertence usando o operador instanceof
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
print() {
console.log(`Name: ${this.name} Age: ${this.age}`);
}
}
class Employee extends Person {
constructor(name, age, company) {
super(name, age);
this.company = company;
}
print() {
super.print();
console.log(`Works in ${this.company}`);
}
}
class Manager extends Person {
constructor(name, age, company) {
super(name, age);
this.company = company;
}
print() {
super.print();
console.log(`Manager in ${this.company}`);
}
}
const sam = new Employee("Sam", 25, "Google");
console.log(sam instanceof Person); // true
console.log(sam instanceof Employee); // true
console.log(sam instanceof Manager); // false
Aqui, a constante sam
Employee
Person
sam instanceof Person
sam instanceof Employee
true
sam
Manager
Manager
false