Clases, objetos, propiedades y métodos 1

Como se dijo en el anterior capítulo, las propiedades (o atributos) son el equivalente a las variables y constantes de la programación estructurada, mientras que los métodos son el equivalente a las funciones de la programación estructurada.

Dado que las propiedades son análogas a las variables, se hace una breve introducción a las variables en JavaScript.

Variables

En programación, los nombres que se asignan a los diferentes elementos del programa tienen el denominativo general de identificadores. Los nombres de las variables y constantes son también identificadores y en consecuencia, deben seguir las reglas generales para nombrar identificadores (la sintaxis).

En general, los identificadores pueden ser nombrados empleado letras, números, guiones bajos (_) y el símbolo de dólar ($), pero el nombre debe comenzar siempre con una letra, un guión bajo (_) o el símbolo $.

No obstante, JavaScript es mucho más flexible y permite emplear como primer carácter acentos, eñes, letras griegas y en general cualquiera de los cientos de caracteres Unicode que tienen la propiedad Id_Start. El resto del nombre puede contener cualquiera de los caracteres del conjunto Unicode (más amplio) con la propiedad ID_Continue.

Las variables en programación, al igual que en álgebra, son símbolos que representan algún tipo de información. En JavaScript, en particular, las variables pueden representar (hacer referencia) a todos los tipos de datos disponibles en el lenguaje. A diferencia de C/C++, las variables en JavaScript no tienen un tipo de dato fijo, por lo que pueden hacer referencia a cualquier tipo de dato.

A diferencia de C/C++, JavaScript es un lenguaje interpretado, es decir que ejecuta las instrucciones inmediatamente a medida que las va leyendo en el código. Esta característica confiere gran flexibilidad a todos sus componentes, incluidas las variables.

Para crear (declarar) variables en JavaScript se emplean las palabras reservadas var, let y const. Var crea variables que son válidas en todo el módiulo en que son creadas, mientras que let y const crean variables que son válidas únicamente en el bloque en que son creadas.

Aunque su nombre sugiere lo contrario, las constantes (const) en JavaScript (al igual que en C/C++ y en la mayoría de los lenguajes de programación) son también variables, sólo que su valor no puede ser modificado, por esa razón son conocidas también como variables inmutables.

Una variable puede ser sólo creada (declarada) o puede ser creada con un valor inicial (variable iniciada).

Por ejemplo, para solo crear las variables "a", "b", "c", "d" y "e", se escribe:

var a;
var b;
var c, d, e;

Estas variables tienen el valor undefined (indefinido):

print(a, b, c, d, e)

Observe que, al igual que en C/C++, las variables pueden ser declaradas una por una, como ocurre con las variables a y b, o dos o más al mismo tiempo (separándolas con comas) como ocurre con las variables c, d y e.

Observe también que, al igual que en C/C++, al final de cada instrucción se debe escribir un punto y coma (;). En realidad, el punto y coma sólo es necesario si la instrucción no termina con un salto de línea, no obstante, si la siguiente línea comienza con un paréntesis u otro símbolo de agrupación u operador, se produce un error. Por esa razón se debe escribir siempre un punto y coma al final de cada instrucción y en la calculadora JavaScript, el punto y coma es imprescindible, excepto en la última línea, donde si se escribe un punto y coma, el resultado no es mostrado.

En el ejemplo se ha empleado también la instrucción print. Esta instrucción imprime (en la calculadora) el valor de las variables o datos que se le mandan. Se emplea en este ejemplo porque se imprime el valor de cinco variables a la vez. Si sólo se quiere imprimir el valor de una variable y esa variable se encuentra en la última línea de la calculadora (o es la única instrucción) simplemente se escribe su nombre, por ejemplo, para imprimir el valor de la variable "b", simplemente se escribe b:

b

Igualmente, se emplea print, cuando el valor a imprimir no es la última de las instrucciones, como en el siguiente ejemplo:

print(a);
print(b);
print(c);
d

El equivalente (más avanzado) a print, en las consolas de los navegadores y otras herramientas de desarrollo, es console.log.

Para asignar un valor a una variable se emplea, al igual que en C/C++, el operador de asignación =, que tiene la siguiente sintaxis:

[var | let | const] nombre_de_la_variable = valor o expresión

Es decir que la sentencia de asignación puede estar precedida (cuando se crean variables) por var, let o const. Si la variable fue creada previamente, para asignarle un nuevo valor, se escribe directamente el nombre de la variable (sin var o let, al igual que en C/C++). Las variables declaradas con const no pueden ser modificadas, por lo que no es posible asignarles un nuevo valor.

Por ejemplo, con las siguientes instrucciones se crean las variables "x", "y" y "z" con los valores 4, 5 y 7.213×106:

var x = 4;
var y = 5;
var z = 7.213e6

Cuando una variable recibe un valor, asume el tipo de dato correspondiente al valor que recibe, así, en este caso, las variables "x", "y" y "z" son ahora de tipo number (pues han recibido un número). El tipo de dato asociado a una variable puede ser obtenido con el comando typeof:

print(typeof x);
print(typeof y);
print(typeof z)

Sin embargo, en JavaScript esta asociación no es permanente. Si la variable recibe otro valor, asume el tipo del dato correspondiente al nuevo valor recibido.

Al imprimir las variables, se obtiene, como era de esperar, los valores asignados:

print(x, y, z)

Con las variables se pueden llevar a cabo las mismas operaciones que con los tipos de datos que guardan, así, como en este ejemplo son datos numéricos, se pueden realizar todas las operaciones estudiadas en el anterior capítulo, por ejemplo, calcular la hipotenusa de los números guardados en "x" y "y":

Math.sqrt(x**2+y**2)

Valor que puede ser calculado, también, con el método estático, hypot:

Math.hypot(x, y)

Una variable puede recibir igualmente valores de tipo texto, conocidos en programación como cadenas de caracteres o simplemente cadenas (strings), por ejemplo, las siguientes variables reciben dos datos de tipo cadena:

var s1 = "Programación en",
s2 = " JavaScript";
print(s1, s2)

Como han recibido datos de tipo cadena, las variables "s1" y "s2" son de tipo string (cadena):

print(typeof s1, typeof s2)

Observe que, para crear un string, simplemente se escribe el texto entre comillas (al igual en en C/C++), pero, en JavaScript se pueden emplear indistintamente tanto comillas como apóstrofos (comillas simples). Además, se pueden emplear acentos invertidos `...`, con los se construyen plantillas literales.

Observe también que, al declarar las variables, la instrucción de asignación ha sido escrita en dos líneas (la instrucción termina recién en el punto y coma de la segunda línea). En JavaScript, los saltos de línea y espacios adicionales, son ignorados por el lenguaje, por lo que se aprovecha esa característica para escribir un código más claro y legible, sin que ello afecte ni a las instrucciones ni a los resultados. Para JavaScript la anterior instrucción es equivalente a la siguiente:

var s1="Programación en",s2=" JavaScript";print(s1,s2)

Que es más corta y hace exactamente lo mismo, pero que para los seres humanos es más difícil de leer y comprender.

Como se dijo, las variables pueden ser declaradas también con let y const, que se emplean exactamente igual que var, pero son formas más estrictas y por esa razón se emplean, casi exclusivamente, al interior de las funciones (métodos) y módulos. Ni let ni const permiten crear una variable con el mismo nombre de una variable creada previamente (algo que si permite var), por lo que resultan más convenientes al momento de escribir funciones, mientras que var es más conveniente cuando se crean variables en la calculadora.

Las cadenas (strings) tienen varios métodos que permiten manipularlas. Dichos métodos serán presentados y estudiados a medida que se requieran y más formalmente en un capítulo dedicado al tema. Por el momento es suficiente conocer las tres formas en que pueden ser creadas.

Con las cadenas se puede emplear el operador de suma (+) que, en el caso de las cadenas, concatena (une) dos o más cadenas, como se puede ver en los siguientes ejemplos:

s1+s2
var s3 = 'Juan Carlos',
s4 = 'Romero Céspedes';
s3+' '+ s4
var s5 = `La raíz cuadrada de 2 es: ${Math.sqrt(2)}`; s5

Observe que al concatenar los nombres y los apellidos (s3 y s4) se ha añadido un espacio (' ') para evitar que el segundo nombre y el primer apellido queden unidos.

Observe también que, en la última instrucción, se ha empleado una plantilla literal para calcular y mostrar el resultado. Para crear una plantilla literal se deben emplear acentos invertidos (acentos graves) y la expresión JavaScript se inserta con ${...}. En su interior (entre las llaves) se puede escribir cualquier instrucción JavaScript válida. Las plantillas literales son el equivalente aproximado de la función printf de C y al operador cout de C++.

Las cadenas de caracteres son de uso frecuente en programación. La mayor parte de la información que se recibe del usuario y la que se muestra al usuario, está en forma de texto.

En el siguiente ejemplo y en los ejercicios correspondientes, se emplearán dos funciones (métodos) disponibles en JavaScript (en el objeto Windows) para pedir y mostrar información: alert y prompt.

La instrucción alert despliega un cuadro de diálogo con un mensaje correspondiente a la información que se quiere mostrar y un botón Aceptar, en el que se debe hacer clic para cerrar el cuadro de diálogo. El cuadro de diálogo se muestra sobre la página.

Su sintaxis es la siguiente:

alert("mensaje")

Donde mensaje es el texto que aparece en el cuadro de diálogo.

La instrucción prompt despliega un cuadro de diálogo donde el usuario puede escribir texto.

El cuadro de diálogo prompt tiene dos botones: Aceptar y Cancelar. Si el usuario pulsa el botón Aceptar, prompt devuelve el texto escrito, si pulsa Cancelar, prompt devuelve null (nulo).

Su sintaxis es la siguiente:

variable = prompt("mensaje", "valor por defecto")

Donde: mensaje es el texto que se muestra en el cuadro de diálogo, para orientar al usuario con relación a lo que debe escribir.

Valor por defecto, es el texto que aparece inicialmente en el campo donde el usuario debe escribir el texto. Este texto sirve de ejemplo para el usuario. Este parámetro puede ser omitido (o ser una cadena vacía: ""), en cuyo caso no aparece ningún texto inicial en el cuadro de diálogo.

El valor que devuelve esta función es siempre de tipo texto (String), por lo que para transformarla en número (u otro tipo de dato) se debe emplear alguna de las funciones (u operadores) disponibles en el lenguaje. Por ejemplo, para convertir el texto escrito por el usuario en un número, se pueden emplear las funciones: parseFloat, parseInt y eval. Además, la mayoría de las funciones y operadores matemáticos, convierten automáticamente el texto a número cuando así se requiere.

Por ejemplo, en las siguientes instrucciones se pide al usuario, con la función prompt, que escriba un número. Ese número es guardado en la variable "valor", pero es un texto (no un número). En este caso el texto es convertido automáticamente en número por la función cbrt. Luego, se emplea una plantilla literal para convertir el resultado (que es un número) en texto y mostrarla al usuario con alert, finalmente se muestra el mismo resultado en la calculadora (evalúe la instrucción, con Shift+Enter, para ver en acción "prompt" y "alert").

var valor = prompt("Escriba un número válido:","0");
var rcubica = Math.cbrt(valor);
alert(`La raíz cúbica de ${valor} es: ${rcubica}`);

Después de ejecutar las anteriores instrucciones, podrá comprobar que la variable "valor" es de tipo cadena (string), no "undefined" como se muestra en este momento:

typeof valor

Si bien muchas de las conversiones de texto a número y viceversa, son manejadas automáticamente por JavaScript, se debe tener siempre en mente que la información escrita por el usuario es siempre texto (aunque el texto represente un número o cualquier otro tipo de dato) y que la información mostrada al usuario es, también, texto.

En JavaScript, al igual que en C/C++, se puede trabajar con datos de tipo booleano (datos de tipo lógico):

var b1 = true;
var b2 = false;
var b3 = 34>20;
var b4 = 7==6;
print(b1, b2, b3, b4);
print(typeof b1, typeof b2, typeof b3, typeof b4);

Como se puede ver en estos ejemplos, en JavaScript, al igual que en C/C++, un tipo booleano sólo puede tener uno de dos valores true (verdadero) y false (falso). Las variables que tienen uno de estos valores son variables de tipo boolean (variables booleanas).

JavaScript tiene los mismos operadores relacionales (>, <, >=, <=, ==, !=) y lógicos (&&, ||, !) que C/C++. Existen algunas diferencias que serán estudiadas en un capítulo posterior, pero por el momento es suficiente saber que, en JavaScript, se pueden construir las mismas expresiones lógicas que en C/C++.

Finalmente, otro tipo de dato de uso frecuente son los arreglos (matrices), más conocidos como arrays (por su denominación en inglés). En JavaScript, los arreglos se declaran simplemente escribiendo sus elementos entre corchetes (separados con comas):

var v1 = [1, 2, 3, 4, 5];
var v2 = ["a", "b", "c", "d", "e"];
print(v1, v2);
print(typeof v1, typeof v2);

En estos ejemplos se han creado dos arreglos "v1" y "v2", el primero con 5 números y el segundo con 5 letras, sin embargo, como se puede ver, al imprimir su tipo se obtiene object, no como se esperaría array. Esto se debe a que los arreglos son objetos de una clase: de la clase Array (no se trata de un tipo primitivo como number). En esos casos, para obtener el tipo de dato, se debe acceder el nombre (name) del objeto constructor:

print(v1.constructor.name, v2.constructor.name)

En JavaScript, los elementos de un arreglo, se manipulan igual que en C/C++: se accede a ellos por su índice escrito entre corchetes, siendo el primer índice 0. Por ejemplo, en la siguiente instrucción, se calcula la raíz cúbica de la suma del primer, tercer y quinto elementos de "v1":

Math.cbrt(v1[0]+v1[2]+v1[4])

En JavaScript los arreglos son dinámicos, a diferencia de C/C++ donde son estáticos. Esto significa que su tamaño (el número de elementos) puede ser modificado en cualquier momento, lo que es de mucha utilidad cuando se elaboran programas de propósito general. También, un arreglo puede estar conformado por elementos de diferentes tipos y no necesariamente de un solo tipo (como ocurre en C/C++):

var v3 = ["uno", 1, "dos", 2, true, false, ["r", "s"], 2.1e34];
v3

Los arreglos en JavaScript tienen a su disposición varios métodos, algunos de los cuales serán introducidos a medida que se requieran, mientras que el resto serán estudiados en un capítulo dedicado a los mismos. Por el momento es suficiente saber como se declaran (crean) y como se utilizan para realizar operaciones simples.

Clases y Objetos

Para comprender los tipos de propiedades y métodos es necesario comprender la diferencia que existe, en la programación orientada a objetos (POO), entre una clase y un objeto.

Las clases son un tipo especial de objetos que permiten crear otros objetos. Son como fábricas que producen, cada una de ellas, un determinado tipo de objeto. Son conocidas también como Objetos Constructores.

Un objeto es el producto (la implementación) de una clase. Cada objeto tiene su propio conjunto de datos (su estado) que lo diferencia de los otros objetos de la misma clase.

En una clase se definen todos los métodos y propiedades que tendrán los objetos de esa clase, pero no sus valores. Los valores se asignan a cada objeto al momento crearlos.

Todos los objetos creados a partir de una misma clase comparten el mismo conjunto de métodos, pero un método solo puede acceder a las propiedades del objeto desde el cual es llamado.

Propiedades y métodos estáticos

Existen dos tipos de propiedades y métodos, las propiedades y métodos estáticos y las propiedades y métodos dinámicos. En esta sección se estudian las características más relevantes de las propiedades y métodos estáticos.

Desde el punto de vista de la programación orientada a objetos (POO), las propiedades estáticas no son propiedades propiamente porque sólo pertenecen a la clase (al objeto constructor), no a los objeto que se crean a partir de esa clase.

Igualmente, desde el punto de vista de la POO, los métodos estáticos no son métodos propiamente porque no pueden ser llamados desde los objetos creados a partir de la clase, sino únicamente desde la clase (desde el objeto constructor). Además, estos métodos no tienen acceso directo ni a las propiedades de los objetos ni a las propiedades de la clase.

Las propiedades y método estáticos son simplemente variables y funciones estándar, solo que han sido declaradas al interior de una clase.

Los objetos que sólo constan de propiedades y métodos estáticos, como es el caso del objeto Math, se denominan objetos literales y son equivalentes a los espacios de nombres de C++.

En general, para acceder a las propiedades y métodos de cualquier objeto (literal, instancia o clase) se debe escribir el nombre del objeto un punto y el nombre de la propiedad o método al que se quiere acceder.

Por ejemplo, para determinar si los números 34.56 y 754 son enteros, empleando el método estático isInteger de la clase Number, se escribe:

Number.isInteger(34.56)
Number.isInteger(734)

Propiedades y métodos dinámicos

Las propiedades y métodos de los objetos creados a partir de una clase, son dinámicos: los valores de las propiedades son exclusivos de cada uno de los objetos (de las instancias) y los métodos de la clase tienen acceso directo a las propiedades de los objetos desde los cuales son llamados.

Es importante comprender que prácticamente todos los elementos en JavaScript son objetos (o son convertidos automáticamente en objetos cuando así se requiere). Los números no son la excepción y aunque casi siempre son creados como valores primitivos (escribiendo directamente el número) todos ellos pueden invocar a los métodos dinámicos de la clase Number:

Por ejemplo, para redondear el resultado de calcular la raíz cuadrada de 3.68, al cuarto dígito después del punto, se puede llamar (desde el resultado, que es un número) al método toFixed:

var r = Math.sqrt(3.68);
r.toFixed(4)

El método puede ser llamado, igualmente, directamente desde la función que devuelve el resultado (sin necesidad de emplear una variable):

Math.sqrt(3.68).toFixed(4)

Como se puede ver, el resultado devuelto por toFixed es una cadena (está encerrada entre comillas). Para convertir el resultado en un número se puede emplear el método estático: parseFloat:

Number.parseFloat(Math.sqrt(3.68).toFixed(4))

Igualmente, si se multiplica el número por 1, el texto es convertido en un número:

Math.sqrt(3.68).toFixed(4)*1

Cuando se llama a un método dinámico de la clase Number desde un entero literal, se debe dejar un espacio en blanco entre el número y el punto que precede al nombre del método, para que JavaScript no confunda ese punto, con un punto decimal. Por ejemplo, en la siguiente instrucción se muestra el número 732340, en notación exponencial, llamando al método dinámico toExponential:

732340 .toExponential()

Sin embargo, es más práctico y más claro encerrar el número literal entre paréntesis:

(732340).toExponential()