13. Classes

Aqui apresentamos as classes do ECMAScript 6. Primeiro, mostramos que as funções já podem ser utilizadas como classes.
13.1. script [class-00]
O script a seguir demonstra uma utilização invulgar das funções. Aqui, elas são utilizadas como objetos.
'use strict';
// a function can be used as an object
// an empty shell
function f() {
}
// to which external properties are attributed
f.prop1 = "val1";
f.show = function () {
console.log(this.prop1);
}
// use of f
f.show();
// a function g operating as a class
function g() {
this.prop2 = "val2";
this.show = function () {
console.log(this.prop2);
}
}
// instantiate the function with [new]
new g().show();
Comentários
- linhas 5–7: o corpo da função f não define quaisquer propriedades;
- linhas 9–12: as propriedades são atribuídas à função f a partir do exterior;
- linha 14: utilização da função (objeto) f. Note-se que não escrevemos [f()], mas simplesmente [f]. Esta é a notação para um objeto;
- linhas 17–22: definimos uma função [g] como se fosse uma classe com propriedades e métodos;
- linha 24: a função [g] é instanciada por [new g()];
Resultados da execução
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-00.js"
val1
val2
O ES6 introduziu o conceito de classes, o que agora nos permite evitar o uso de funções para criar classes.
13.2. script [class-01]
O script [class-01] apresenta uma classe [Person]:
// class
class Personne {
// manufacturer
constructor(nom, prénom, âge) {
this.nom = nom;
this.prénom = prénom;
this.âge = âge;
}
// getters and setters
get nom() {
return this._nom;
}
set nom(value) {
this._nom = value;
}
get prénom() {
return this._prénom;
}
set prénom(value) {
this._prénom = value;
}
get âge() {
return this._âge;
}
set âge(value) {
this._âge = value;
}
// toString to JSON
toString() {
return JSON.stringify(this);
}
}
// class call
function main() {
const personne = new Personne("Poirot", "Hercule", 66);
console.log("personne=", personne.toString(), typeof (personne), personne instanceof (Personne));
}
// hand call
main();
Comentários
- linha 2: a palavra-chave [class] denota uma classe;
- linhas 5–9: a palavra-chave [constructor] denota o construtor da classe. Pode haver, no máximo, um. É utilizado para construir e inicializar uma instância da classe. Note-se que não há declaração das propriedades [last_name, first_name, age];
- linhas 11–36: propriedades da classe. Aqui vemos elementos já abordados na secção sobre objetos 4, página 44. Apenas a sintaxe difere;
- linha 41: criação de um objeto do tipo [Person]. A partir de agora, o objeto [person] é utilizado como um objeto literal. [typeof (person)] é avaliado como “object” e a expressão [person instanceof (Person)] é verdadeira. É, portanto, possível determinar o tipo exato de uma instância de classe;
Resultados da execução
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-01.js"
personne= {"_nom":"Poirot","_prénom":"Hercule","_âge":66} object true
13.3. script [class-02]
Este script demonstra a capacidade de herdar de uma classe utilizando a palavra-chave [extends].
Primeiro, movemos a classe [Person] para um módulo chamado [Person.js]:
// classe
class Personne {
// constructeur
constructor(nom, prénom, âge) {
this.nom = nom;
this.prénom = prénom;
this.âge = âge;
}
// getters et setters
get nom() {
return this._nom;
}
set nom(value) {
this._nom = value;
}
get prénom() {
return this._prénom;
}
set prénom(value) {
this._prénom = value;
}
get âge() {
return this._âge;
}
set âge(value) {
this._âge = value;
}
// toString en JSON
toString() {
return JSON.stringify(this);
}
}
// export classe
export default Personne;
- linha 39: exportamos a classe [Person] para que os scripts possam importá-la;
O script [class-02] cria uma classe [Teacher] derivada da classe [Person]:
// imports
import Personne from './Personne';
// classe
class Enseignant extends Personne {
// constructeur
constructor(nom, prénom, âge, discipline) {
super(nom, prénom, âge);
this.discipline = discipline;
}
// getters et setters
get discipline() {
return this._discipline;
}
set discipline(value) {
this._discipline = value;
}
}
// appel de la classe
function main() {
const enseignant = new Enseignant("Poirot", "Hercule", 66, "détective");
console.log("enseignant=", enseignant.toString(), typeof (enseignant), enseignant instanceof Enseignant);
}
// appel de main
main();
Comentários
- linha 2: importamos a classe [Person] do módulo [Person.js], que se encontra na mesma pasta que [class-02];
- linha 5: a classe [Teacher] estende (herda da) classe [Person] utilizando a palavra-chave [extends]: adiciona uma propriedade [_subject] com os métodos getter e setter correspondentes;
- linhas 8–11: o construtor da classe [Teacher] recebe quatro valores para inicializar as quatro propriedades da classe;
- linha 9: a palavra-chave [super] chama o construtor da classe pai [Person], que irá, assim, inicializar as propriedades [_last_name, _first_name, _age];
- linha 10: a propriedade [_discipline] pertencente à classe [Teacher] é inicializada;
- linhas 14–19: os métodos getter e setter para a propriedade [_discipline];
- linha 25: é criado um objeto do tipo [Teacher];
- linha 26: utilizamos o método [teacher.toString()]. A classe [Teacher] não possui este método. Por isso, o método da sua classe pai é automaticamente utilizado. Este método renderiza a expressão [JSON.stringify(this)], onde [this] será aqui um objeto [Teacher], e não um objeto [Person]. Isto é o que se conhece na programação orientada a objetos como polimorfismo de classes. Um termo complexo para o JavaScript, que não é uma linguagem orientada a objetos. No entanto, o JavaScript faz o que se espera dele aqui: apresenta corretamente um professor;
Os resultados da execução são os seguintes:
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-02.js"
enseignant= {"_nom":"Poirot","_prénom":"Hercule","_âge":66,"_discipline":"détective"} object true
- linha 2: O JavaScript reconhece corretamente que a variável [teacher] é do tipo [Teacher];
13.4. script [class-03]
O script [class-03] mostra que uma classe filha pode substituir propriedades e métodos da sua classe pai. Aqui, substituímos o método [toString] da classe pai:
// imports
import Personne from './Personne';
// classe
class Enseignant extends Personne {
// constructeur
constructor(nom, prénom, âge, discipline) {
super(nom, prénom, âge);
this.discipline = discipline;
}
// getters et setters
get discipline() {
return this._discipline;
}
set discipline(value) {
this._discipline = value;
}
// redéfinition de toString
toString() {
return "[Enseignant]" + JSON.stringify(this);
}
}
// appel de la classe
function main() {
const enseignant = new Enseignant("Poirot", "Hercule", 66, "détective");
console.log("enseignant=", enseignant.toString(), typeof (enseignant), enseignant instanceof Enseignant);
}
// appel de main
main();
Os resultados da execução são os seguintes:
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-03.js"
enseignant= [Enseignant]{"_nom":"Poirot","_prénom":"Hercule","_âge":66,"_discipline":"détective"} object true
13.5. script [class-04]
O script [class-04] demonstra novamente o polimorfismo em ação: quando uma função espera um parâmetro formal do tipo [Person], podemos passar um tipo derivado, como [Teacher]. De facto, em virtude da derivação, o tipo [Teacher] possui todos os atributos do tipo [Person].
Primeiro, isolamos o tipo [Teacher] num módulo [Teacher.js]:
// imports
import Personne from './Personne';
// classe
class Enseignant extends Personne {
// constructeur
constructor(nom, prénom, âge, discipline) {
super(nom, prénom, âge);
this.discipline = discipline;
}
// getters et setters
get discipline() {
return this._discipline;
}
set discipline(value) {
this._discipline = value;
}
}
// export classe
export default Enseignant;
- linha 24: a classe [Teacher] é exportada para que outros scripts possam importá-la;
O script [class-04] é o seguinte:
// imports
import Enseignant from './Enseignant';
import Personne from './Personne';
// fonction acceptant une personne comme paramètre
function show(personne) {
// dans tous les cas
console.log("paramètre=", personne.toString(), typeof (personne));
// instance de Personne
if (personne instanceof Personne) {
console.log("personne=", personne.toString());
}
// instance de Enseignant
if (personne instanceof Enseignant) {
console.log("enseignant=", personne.toString());
}
}
// appel de show avec un enseignant
show(new Enseignant("Poirot", "Hercule", 66, "détective"));
show(new Personne("Marple", "Miss", 70));
- linha 6: a função [show] espera um tipo [Person] ou um tipo derivado;
- linha 8: a string do parâmetro e o seu tipo são apresentados. Encontraremos [object];
- linhas 10–16: podemos determinar se é um tipo [Person] ou um tipo [Teacher]. O código pode, portanto, ser adaptado ao tipo real do parâmetro;
Os resultados da execução são os seguintes:
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-04.js"
paramètre= {"_nom":"Poirot","_prénom":"Hercule","_âge":66,"_discipline":"détective"} object
personne= {"_nom":"Poirot","_prénom":"Hercule","_âge":66,"_discipline":"détective"}
enseignant= {"_nom":"Poirot","_prénom":"Hercule","_âge":66,"_discipline":"détective"}
paramètre= {"_nom":"Marple","_prénom":"Miss","_âge":70} object
personne= {"_nom":"Marple","_prénom":"Miss","_âge":70}
- linhas 4 e 6: o JavaScript reconhece corretamente o tipo das instâncias de classe;