13. Clases

Aquí introducimos las clases de ECMAScript 6. En primer lugar, mostramos que las funciones ya se pueden utilizar como clases.
13.1. script [class-00]
El siguiente script demuestra un uso inusual de las funciones. Aquí, se utilizan como objetos.
1. 'use strict';
2. // a function can be used as an object
3.
4. // an empty shell
5. function f() {
6.
7. }
8. // to which properties are assigned from the outside
9. f.prop1 = "val1";
10. f.show = function () {
11. console.log(this.prop1);
12. }
13. // using f
14. f.show();
15.
16. // a function g acting as a class
17. function g() {
18. this.prop2 = "val2";
19. this.show = function () {
20. console.log(this.prop2);
21. }
22. }
23. // Instantiate the function with [new]
24. new g().show();
Comentarios
- líneas 5-7: el cuerpo de la función f no define ninguna propiedad;
- líneas 9-12: se asignan propiedades a la función f desde fuera;
- línea 14: uso de la función (objeto) f. Observa que no escribimos [f()] sino simplemente [f]. Esta es la notación para un objeto;
- líneas 17-22: definimos una función [g] como si fuera una clase con propiedades y métodos;
- línea 24: la función [g] es instanciada por [new g()];
Resultados de la ejecución
1. [Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-00.js"
2. val1
3. val2
ES6 introdujo el concepto de clases, que ahora nos permite evitar el uso de funciones para crear clases.
13.2. script [class-01]
El [class-01] script presenta una [Persona] class:
1. // class
2. class Person {
3.
4. // constructor
5. constructor(lastName, firstName, age) {
6. this.lastName = lastName;
7. this.firstName = firstName;
8. this.age = age;
9. }
10.
11. // getters and setters
12. get name() {
13. return this._name;
14. }
15. set name(value) {
16. this._name = value;
17. }
18.
19. get firstName() {
20. return this._first_name;
21. }
22. set firstName(value) {
23. this._first_name = value;
24. }
25.
26. get age() {
27. return this._age;
28. }
29. set age(value) {
30. this._age = value;
31. }
32.
33. // toString as JSON
34. toString() {
35. return JSON.stringify(this);
36. }
37. }
38.
39. // Call the class
40. function main() {
41. const person = new Person("Poirot", "Hercule", 66);
42. console.log("person=", person.toString(), typeof(person), person instanceof(Person));
43. }
44.
45. // call to main
46. main();
Comentarios
- línea 2: la palabra clave [clase] denota una clase;
- líneas 5-9: la palabra clave [constructor] denota el constructor de la clase. Puede haber como máximo uno. Se utiliza para construir e inicializar una instancia de la clase. Nótese que no hay declaración de las propiedades [apellido, nombre, edad];
- líneas 11-36: propiedades de la clase. Aquí vemos elementos ya tratados en la sección de objetos 4, página 44. Sólo difiere la sintaxis;
- línea 41: creación de un objeto de tipo [Person]. A partir de ahora, el objeto [persona] se utiliza como objeto literal. [typeof (persona)] evalúa a "objeto" y la expresión [persona instanceof (Person)] es verdadera. Por lo tanto, es posible determinar el tipo exacto de una instancia de clase;
Resultados de la ejecución
1. [Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-01.js"
2. person = {"_lastName":"Poirot","_firstName":"Hercule","_age":66} object true
13.3. script [class-02]
Este script demuestra la capacidad de heredar de una clase utilizando la [extends] palabra clave.
Primero, movemos la clase [Persona] a un módulo llamado [Person.js]:
1. // class
2. class Person {
3.
4. // constructor
5. constructor(lastName, firstName, age) {
6. this.lastName = lastName;
7. this.firstName = firstName;
8. this.age = age;
9. }
10.
11. // getters and setters
12. get lastName() {
13. return this._lastName;
14. }
15. set name(value) {
16. this._name = value;
17. }
18.
19. get firstName() {
20. return this._first_name;
21. }
22. set firstName(value) {
23. this._first_name = value;
24. }
25.
26. get age() {
27. return this._age;
28. }
29. set age(value) {
30. this._age = value;
31. }
32.
33. // toString as JSON
34. toString() {
35. return JSON.stringify(this);
36. }
37. }
38. // export class
39. export default Person;
- línea 39: exportamos la [Persona] clase para que los scripts puedan importarla;
El [clase-02] script crea una [Profesor] clase derivada de la [Persona] clase:
1. // imports
2. import Person from './Person';
3.
4. // class
5. class Teacher extends Person {
6.
7. // constructor
8. constructor(lastName, firstName, age, subject) {
9. super(lastName, firstName, age);
10. this.subject = subject;
11. }
12.
13. // getters and setters
14. get discipline() {
15. return this._discipline;
16. }
17. set discipline(value) {
18. this._discipline = value;
19. }
20.
21. }
22.
23. // call the class
24. function main() {
25. const teacher = new Teacher("Poirot", "Hercule", 66, "detective");
26. console.log("teacher=", teacher.toString(), typeof (teacher), teacher instanceof Teacher);
27. }
28.
29. // call to main
30. main();
Comentarios
- línea 2: importamos la [Persona] clase del [Person.js] módulo, que se encuentra en la misma carpeta que [class-02];
- línea 5: la [Profesor] clase extiende (hereda de) la [Persona] clase utilizando la [extiende] palabra clave: añade una [_sujeto] propiedad con los correspondientes métodos getter y setter;
- líneas 8-11: el constructor de la [Profesor] clase recibe cuatro valores para inicializar las cuatro propiedades de la clase;
- línea 9: la palabra clave [super] llama al constructor de la clase padre [Persona], que, por tanto, inicializará las propiedades [apellido, _primer_nombre, _edad];
- línea 10: se inicializa la [_disciplina] propiedad perteneciente a la [Profesor] clase;
- líneas 14-19: el getter y setter para la [_disciplina] propiedad;
- línea 25: se crea un objeto de tipo [Profesor] ;
- línea 26: utilizamos el método [profesor.toString()]. La clase [Profesor] no tiene este método. Por lo tanto, se utiliza automáticamente el método de su clase padre. Este método devuelve la expresión [JSON.stringify(this)], donde [this] será aquí un [Profesor] objeto, no un [Persona] objeto. Esto es lo que en programación orientada a objetos se conoce como polimorfismo de clases. Palabras mayores para JavaScript, que no es un lenguaje orientado a objetos. No obstante, JavaScript hace aquí lo que se espera de él: muestra correctamente un profesor;
Los resultados de la ejecución son los siguientes:
1. [Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-02.js"
2. teacher = {"_last_name":"Poirot","_first_name":"Hercule","_age":66,"_profession":"detective"} object true
- línea 2: JavaScript reconoce correctamente que la variable [profesor] es de tipo [Profesor];
13.4. script [class-03]
El [clase-03] script muestra que una clase hija puede anular propiedades y métodos de su clase padre. Aquí, sobrescribimos el [toString] método de la clase padre:
1. // imports
2. import Person from './Person';
3.
4. // class
5. class Teacher extends Person {
6.
7. // constructor
8. constructor(lastName, firstName, age, subject) {
9. super(lastName, firstName, age);
10. this.subject = subject;
11. }
12.
13. // getters and setters
14. get discipline() {
15. return this._discipline;
16. }
17. set discipline(value) {
18. this._discipline = value;
19. }
20.
21. // redefinition of toString
22. toString() {
23. return "[Teacher]" + JSON.stringify(this);
24. }
25. }
26.
27. // Call the class
28. function main() {
29. const teacher = new Teacher("Poirot", "Hercule", 66, "detective");
30. console.log("teacher=", teacher.toString(), typeof (teacher), teacher instanceof Teacher);
31. }
32.
33. // call to main
34. main();
Los resultados de la ejecución son los siguientes:
1. [Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-03.js"
2. teacher = [Teacher]{"_last_name":"Poirot","_first_name":"Hercule","_age":66,"_profession":"detective"} object true
13.5. script [class-04]
El [clase-04] script demuestra de nuevo el polimorfismo en acción: donde una función espera un parámetro formal de tipo [Persona], podemos pasar un tipo derivado como [Profesor]. En efecto, en virtud de la derivación, el tipo [Profesor] tiene todos los atributos del tipo [Persona] .
Primero, aislamos el [Profesor] tipo en un [Profesor.js] módulo:
1. // imports
2. import Person from './Person';
3.
4. // class
5. class Teacher extends Person {
6.
7. // constructor
8. constructor(last_name, first_name, age, subject) {
9. super(lastName, firstName, age);
10. this.subject = subject;
11. }
12.
13. // getters and setters
14. get discipline() {
15. return this._discipline;
16. }
17. set discipline(value) {
18. this._discipline = value;
19. }
20.
21. }
22.
23. // export class
24. export default Teacher;
- línea 24: la [Profesor] clase se exporta para que otros scripts puedan importarla;
El [class-04] script es el siguiente:
1. // imports
2. import Teacher from './Teacher';
3. import Person from './Person';
4.
5. // function accepting a person as a parameter
6. function show(person) {
7. // in all cases
8. console.log("parameter=", person.toString(), typeof(person));
9. // instance of Person
10. if (person instanceof Person) {
11. console.log("person=", person.toString());
12. }
13. // instance of Teacher
14. if (person is an instance of Teacher) {
15. console.log("teacher=", person.toString());
16. }
17. }
18.
19. // Call show with a Teacher
20. show(new Teacher("Poirot", "Hercule", 66, "detective"));
21. show(new Person("Marple", "Miss", 70));
- línea 6: la [show] función espera un [Persona] tipo o un tipo derivado;
- línea 8: se muestra la cadena del parámetro y su tipo. Encontraremos [objeto];
- líneas 10-16: podemos determinar si se trata de un [Persona] tipo o de un [Profesor] tipo. Por tanto, el código puede adaptarse al tipo real del parámetro;
Los resultados de la ejecución son los siguientes:
1. [Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-04.js"
2. parameter= {"_last_name":"Poirot","_first_name":"Hercule","_age":66,"_profession":"detective"} object
3. person = {"_last_name": "Poirot", "_first_name": "Hercule", "_age": 66, "_profession": "detective"}
4. teacher = {"_last_name":"Poirot","_first_name":"Hercule","_age":66,"_profession":"detective"}
5. parameter = {"_last_name": "Marple", "_first_name": "Miss", "_age": 70} object
6. person= {"_last_name":"Marple","_first_name":"Miss","_age":70}
- líneas 4 y 6: JavaScript reconoce correctamente el tipo de instancias de clase;