duduromeroa.com

Javascript

Programación para web con JS (5/8): clases, propiedades, valores, métodos, protección de valores


Estudio del lenguaje de programación javascript. www.duduromeroa.com, Guayaquil - Ecuador
George Póyla, matemático. Resolver problemas de diseño. www.duduromeroa.com

Por Eduardo J. Romero Andrade
| Guayaquil

Twitter   JS para Guayacxs   duduromeroa@gmail.com




SIMULAR EL MUNDO REAL MEDIANTE CLASES, PROPIEDADES Y VALORES

Tiempo después de la II Guerra Mundial (1939-1945), entre los años 1940 y 1960 científicos estadounidenses y europeos crearon sistemas de cómputo para simular, mediante datos numéricos, nuestro mundo teórico o físico. Es por eso que según Black[6] finalizada la guerra se idearon sistemas militares informáticos para simular con matemáticas interacciones complejas de comprobar en esos años, como la física nuclear.

La experiencia ganada en esos proyectos obligó a que esos mismos científicos se pregunten cómo un inmenso y complejo conjunto de propiedades y valores podrían formar categorías mejor definidas con tal de simular con fidelidad cualquier concepto matemático o físico. Es allí donde entra el objeto como un término de la computación moderna. En ciencias de la computación, el 'objeto' contiene propiedades y valores que pueden ser agrupados en clases, además de permitir simular otros objetos, almacenarlos en forma de datos, alterarlos y vincular mensajes entre más objetos[7]. El primer lenguaje de programación que tomó prestado esa visión fue Simula67, creado por los noruegos Ole-Johan Dahl y Kristen Nygaard entre 1960 y 1967. Simula67 aplicó el modelo de programación orientado a objetos, explicado en otra sección.

Hoy en día, lenguajes como Javascript intentan que un sistema de cómputo interprete el mundo como un gran conjunto de clases, o como "objetos dentro de objetos " –[6] pág. 9–; con propiedades y valores.

Para Flanagan[3, capítulo 9] los objetos en programación son entidades únicas. Un objeto se diferencia de otro en sus propiedadas y en sus comportamientos que adquieren cuando 'nacen' o se instancian de una clase madre.

Las propiedades son los casilleros que alojan datos de cada clase y cada objeto nacido –o instanciado– de cada clase. Los valores son las nuevas características de esas propiedades. En cada nuevo objeto creado las propiedades se heredarán pero los valores podrían ser totalmente nuevos (se alteró la sintaxis del siguiente código para explicar lo mencionado):

 class Clase {
...(propiedadA, propiedadB){
propiedadA = valor;
propiedadA = valor;
}}

/* Cada nuevo objeto agregará NUEVOS 
VALORES a las propiedades heredadas */
... objetoA = ... (nuevoValor, nuevoValor);
... objetoB = ... (nuevoValor, nuevoValor);

Todo eso ahorra tiempo de producción: las clases en programación funcionan como moldes o patrones –como el conjunto de dobleces usado para armar un avión de papel– desde donde se crean más objetos que heredan algo de su clase madre. Usar un patrón con propiedades base generará una herencia de datos que ahorrará trabajo al evitar duplicar cada gran conjunto de valores de propiedades en cada nuevo objeto. Es decir, ya sean uno o cien aviones de papel, cada avioncito creado a punta de doblar el mismo patrón heredará propiedades –forma y color, por ejemplo– a los que luego se le añadirán nuevos valores –un color diferente o una variación a la forma-.

Como veremos, Javascript usa un acercamiento diferente al darle más importancia a los objetos que a las clases; en comparación con otros lenguajes de programación, como Java o C#, en donde las clases gozan de mayor importancia en estructura y sintaxis.

CLASES Y OBJETOS

Para Svekis y Putten[5], las clases en JS son funciones madre con propiedades y sus valores. También, una clase es un conjunto de objetos con propiedades similares. Una palabra clave y un método permiten concebir una clase: la clave class y el método constructor. Y luego, el operador new permite que nazcan objetos desde esa clase.

PALABRA CLAVE CLASS

Para mdn web docs la clave class es una declaración creadora de objetos.

MÉTODOS

Para Svekis y Putten[5] los métodos son funciones dentro de las clases. Y cuando se los definen no es permitido anteceder a los métodos con la clave function. Simplemente se usa un identificador y luego, al invocarlo, se lo hace con el nombre del método.

MÉTODO CONSTRUCTOR

Para mdn web docs el método constructor crea e inicializa un objeto-clase. Para Svekis y Putten[5], el constructor es una única función dentro de una clase que permite crear instancias o 'nacimientos' de objetos a partir de la clase madre o plantilla de objetos. Así como ocurre en las funciones, un constructor es llamado o invocado a crear un objeto mediante la palabra clave new. Esa invocación le pide al constructor que agregue las propiedades de la clase al nuevo objeto:

PALABRA CLAVE THIS

En clases, la clave this conecta el valor de un objeto. Se detallará this en los siguientes párrafos.

OPERADOR NOW

Con el operador new ocurre un llamado al constuctor y luego un nacimiento de un objeto. Es decir, luego de la invocación se ejecuta una copia de propiedades desde la clase madre hacia el nuevo objeto pero con nuevos valores agregados en forma de argumentos. En el código siguiente, cada nuevo hijo –un objeto– tendrá dos propiedades heredadas de la clase madre: nombre y color de cabello. Pero en cada nacimiento o instancia, cada propiedad tendrá nuevo valor.

En el siguiente ejemplo se muestra cómo los elementos explicados se unen para crear clases –por acuerdo común, estas tienen la primera inicial en mayúscula–, métodos de clase, propiedades e instancias de objetos:

// -> Función con declaración de clase
class Madre{
/* Método que construye la clase y le 
da parámetros en forma de propiedades */
constructor(nombre, colorCabello){
// -> PROPIEDADES CON VALORES
this.nombre = nombre;
this.colorCabello = colorCabello;
}
// MÉTODO de la clase Madre
mensaje(){
console.log(primeroHijo.nombre + " es hermoso.");
}

}
// -> NACEN Objetos de la clase Madre
// -> Propiedad ------------|Nombre---|Cabello
let primeroHijo = new Madre("Julito", "rubio");
let segundoHijo = new Madre("Anita", "negro");

// -> Invocar un hijo de la clase Madre
console.log("El primer hijo se llama " + primeroHijo.nombre + 
" y es " + primeroHijo.colorCabello);
// -> El primer hijo se llama Julito y es rubio

// Se invoca nombre de objeto y nombre de función de clase
primeroHijo.mensaje();
// -> Julito es hermoso.

- Clases creadas con la declaración class deben ser invocadas –para instanciar objetos– con el operador new


- Las funciones arrow '=>' no permiten definir constructores



Por otro lado, en el ejemplo de abajo se crea una función 'patronAvion' con tres parámetros. Ya en el cuerpo de la función cada parámetro será una propiedad -pliegue, color, etc.– que representa a su propio identificador pero antecedido con la clave this. Luego se crean nuevas variables cuyo valor es un nuevo –new– objeto nacido de la función madre pero con nuevos valores. Finalmente, la invocación al identificador de cada variable mostrará a cada objeto con iguales propiedades, pero con características –valores– nuevos.

 
// Función padre, con parámetros
function patronAvion(pliegues, color, dimension){
/* Parámetros y propiedades tienen el mismo nombre. */
this.pliegues = pliegues;
this.color = color;
this.dimension = dimension;
}

// Nuevos objetos se crean con el operador constructor 'new'
// Nuevos argumentos inicializarán nuevas propiedades
let avionAA = new patronAvion("4", "rojo", "mediano"); 
let avionBB = new patronAvion("6", "blanco", "pequeño"); 

// Invocar nuevo objeto hijo
console.table(avionAA);
/* 
Se heredaron propiedades, 
pero sus valores son diferentes
┌───────────┬───────────┐
│  (index)  │  Values   │
├───────────┼───────────┤
│ pliegues  │    '4'    │
│   color   │  'rojo'   │
│ dimension │ 'mediano' │
└───────────┴───────────┘
*/

// Invocar nuevo objeto hijo
console.table(avionBB);
/* 
Se heredaron propiedades, 
pero sus valores son diferentes
┌───────────┬───────────┐
│  (index)  │  Values   │
├───────────┼───────────┤
│ pliegues  │    '6'    │
│   color   │ 'blanco'  │
│ dimension │ 'pequeño' │
└───────────┴───────────┘
*/

En otro ejemplo, una clase contiene dentro una función cuyo parámetro puede ser alimentado desde fuera al ser instanciado el objeto creado:

 // ---> CREAR CLASE <--- //
class Mascota{
	/* Se construye clase con 
	propiedades de la clase */
	constructor(nombre, tipo){
	this.nombre = nombre;
	this.tipo = tipo;
	}
		// Una función interna con parámetro
		vacunas(vacunado){
		// Condicional de parámetro
			if (vacunado == 1) 
			{return "SÍ tiene vacuna";} 
			else {return "NO tiene vacuna"};
			}
}

// ---> CREAR OBJETOS <--- //
/* Instacia 'perro' */
let perro = new Mascota("Nacho", "perro");

/* Instacia 'loro' */
let loro = new Mascota("Guille", "loro");

// ---> INVOCAR Y MOSTRAR <--- //
// De 'perro' 
console.log("-- Mi " + perro.tipo + " de nombre " + 
perro.nombre + " " + perro.vacunas() );
// -> -- Mi perro de nombre Nacho NO tiene vacuna

// De 'loro' 
console.log("-- Mi " + loro.tipo + " de nombre " + 
loro.nombre + " " + loro.vacunas(1) );
// -> -- Mi loro de nombre Guille SÍ tiene vacuna

PROTEGER LOS VALORES DE LAS PROPIEDADES

Se antecede el signo '#' a cada propiedad de la clase para prohibir su acceso desde fuera de las clase madre. Es decir, solo se podrá acceder –y pedir mostrar– los valores de esas propiedades únicamente desde dentro de la función. Con esa acción de bloqueo se concreta la encapsulación o protección de los datos desde una clase, una característica de la programación orientada a objetos.

 class Calificar {
// Propiedades protegidas
#semestreA; 
#semestreB;

constructor(semestreA, semestreB){
this.#semestreA = semestreA;
this.#semestreB = semestreB;

// Desde dentro se puede ACCEDER y MOSTRAR
console.log("Desde dentro -> Semestre A: " + semestreA);
// --> Desde dentro de la función -> Semestre A: 9.5
}}

/* Nuevo objeto creado y  
nuevos valores de propiedades. 
Pero esos valores NO PUEDEN accederse 
desde fuera de la clase Calificar. */
let estudiante = new Calificar(9, 10);
console.log(estudiante.semestreA);
// -> Undefined

Por otro lado, en el ejemplo de abajo se define un nombre identificador de un clase para calcular un número. También se inicializa dentro de la clase una propiedad que guarda un resultado para luego ser invocado:

 var EdadMascota = class {constructor(nace, hoy) 
{ this.edad = nace - hoy; } 
};

// Objeto > conocer la edad de Nico
let edadNico = new EdadMascota(2022, 2017).edad;

// Objeto > conocer la edad de Lilita
let edadLilita = new EdadMascota(2022, 2015).edad;

// Invocar edadNico
console.log("Nico cumple " + edadNico + " años de edad.");
// -> Nico cumple 5 años de edad.

// Invocar edadLilita
console.log("Lilita cumple " + edadLilita + " años de edad.");
// -> Lilita cumple 7 años de edad.

Subir al inicio Seguir a la parte sexta



BIBLIOGRAFÍA:
    3ra edición. 2018. Marijn Haverbeke. No starch press.
    Mozilla Foundation.
    David Flanagan (2020). Editorial O'Reilly.
    Ved Antani, Stoyan Stefanov (2017). Packt Publishing.
    Editorial Packt.
    Information and Computation. Elsevier.
    ACM SIGCSE BulletinVolume 19Issue 1Feb. 1987 pp 98–102https://doi.org/10.1145/31726.31742.