Crear y renderizar un animal
Abra ‘src/Animals/Cat.jspp’ e ingrese el siguiente código:
external $; module Animals { class Cat { void render() { var $element = $( """ <div class="animal"> <i class="icofont icofont-animal-cat"></i> </div> """ ); $("#content").append($element); } } }
Una cosa que puede notar de inmediato es la string de varias líneas («»»…»»»). Cuando encerramos nuestra string entre comillas triples, podemos escribir una string de «múltiples líneas». Las strings de varias líneas son una característica de JS++ que son especialmente útiles cuando se trata de HTML. Notará que, con strings de varias líneas, no tuvimos que escapar de nuestros caracteres de comillas dobles («) o caracteres de nueva línea.
Además de la string de varias líneas, solo estamos pasando algo de HTML a jQuery a través de $(…) como de costumbre. jQuery reconocerá esto como HTML y creará dinámicamente los elementos HTML para nosotros. Sin embargo, los elementos HTML creados dinámicamente solo se mantienen en la memoria a menos que los representemos en la página. Lo hacemos con esta línea:
$("#content").append($element);
Notará que nombramos nuestra variable para el elemento jQuery como $elemento. Es una convención de nomenclatura común prefijar las variables que contienen objetos jQuery con el signo $.
También puede haber notado que declaramos el tipo de datos para la variable jQuery $element como ‘var’. Como discutimos en capítulos anteriores, es posible que no siempre haya un tipo de datos JS++ correspondiente para objetos complejos, por lo que solo podemos usar ‘var’ en estos casos (o incluso solo por conveniencia).
Nota al margen: jQuery y la API Document Object Model (DOM) para manipular páginas web se pueden clasificar como «altamente dinámicas». Algunas grandes empresas se equivocaron al tratar de agregar tipos de datos estáticos en estos casos, ya que hay muchos casos extremos en los que los tipos de datos estáticos serán incorrectos o fallarán, como en el caso de los «objetos host» de ECMAScript, que incluye la API DOM, donde la «implementación- El comportamiento definido”, como diferentes implementaciones de navegador de los mismos métodos DOM API, es válido de acuerdo con la especificación del lenguaje (y de hecho ocurre en implementaciones del mundo real). Otro ejemplo es la implementación del recolector de elementos no utilizados en las versiones de Internet Explorer donde el GC puede reclamar objetos de host en uso no cíclicos (como el «archivo html» ActiveXObject utilizado para la transmisión en tiempo real) demasiado pronto, un escenario que no es manejable. al análisis estático. A pesar de su conveniencia, los tipos de datos estáticos en estos casos crean una «falsa sensación de seguridad». Sin embargo, la discusión de estos temas está fuera del alcance de este tutorial.
Notarás que declaramos una función dentro de nuestra clase ‘Cat’. Una función declarada dentro de una clase se denomina comúnmente «método de clase» o simplemente «método» para abreviar. Las funciones que no son miembros de una clase se conocen como «funciones libres».
Declaramos una clase dentro de un módulo, por lo que este archivo por sí solo no se compilará. Necesitamos crear un «archivo principal» para que actúe como el punto de entrada del programa. En su carpeta ‘src’ (la carpeta principal de la carpeta ‘Animals’), recordará que creamos un archivo main.jspp vacío. Abra el archivo main.jspp e ingrese estas líneas de código:
import Animals; Cat cat = new Cat(); cat.render();
Primero instanciamos la clase para obtener una instancia de clase. Una vez que tenemos una instancia de clase, llamamos al método ‘renderizar’ en esa instancia de clase específica.
Compilando
La compilación va a ser ligeramente diferente en comparación con nuestros ejemplos de tutoriales anteriores debido a nuestra estructura de directorios profunda. Los usuarios de Mac/Linux no tendrán que hacer muchos ajustes, pero, para los usuarios de Windows, tenemos que empezar a usar el símbolo del sistema.
Para usuarios de Mac/Linux, simplemente abra su terminal en la carpeta de código ‘OOP’ e ingrese el siguiente comando:
$ js++ src/ -o build/app.jspp.js
Para usuarios de Windows, abra el símbolo del sistema. Navegue hasta el directorio de la carpeta ‘código’ de OOP (usando el comando ‘cd’). Una vez que navegamos a la carpeta, ingresamos el mismo comando que los usuarios de Mac/Linux:
> js++ src/ -o build/app.jspp.js
Si todo funcionó, debería ver un «OK» verde como se muestra en la captura de pantalla anterior (para todos los sistemas operativos: Windows, Mac y Linux).
Abra index.html (en la carpeta raíz ‘OOP’) en su navegador web. Debería ver un pequeño icono de gato en la página:
Estilizando a los animales
En este momento, nuestro gato es bastante pequeño y difícil de ver. Modifiquemos el estilo para que nuestro gato sea más grande y claro.
Abra style.css en la carpeta ‘estilo’. Debería estar vacío, pero agregaremos una regla CSS simple para que nuestro gato sea más claro:
.animal i { font-size: 50px; }
Guarde style.css y actualice index.html. Deberías ver un gato más grande.
Campos de clase
Más allá de los métodos que definen el comportamiento de una clase, las clases también pueden contener datos propios. En esencia, puede pensar en las clases como datos más métodos que operan con esos datos. Por ejemplo, con mascotas como los gatos, es posible que queramos poder darle un nombre al gato. El nombre son los datos y los ejemplos de métodos pueden ser funciones que nos permitan establecer o cambiar el nombre.
Los campos de clase nos permiten especificar datos que son exclusivos de la clase. Los campos son solo declaraciones de variables:
class Cat { string name; }
Los campos de clase difieren de las declaraciones de variables regulares porque solo se puede acceder a ellos a través de la clase o instancias de clase. Además, declaramos un campo de ‘nombre’ que es exclusivo de una instancia de clase anterior; esto significa que cada instancia única de la clase tendrá sus propios datos de nombre únicos.
Los datos que son únicos para una instancia específica pueden ser muy útiles, especialmente cuando se trata de una gran cantidad de objetos similares. Sin embargo, nuestro código actual que muestra el gato en la página en realidad no conserva los datos exclusivos de una instancia. Observemos; cambie el código main.jspp de la siguiente manera para llamar a render() por segunda vez:
import Animals; Cat cat = new Cat(); cat.render(); cat.render();
Compile el código y abra index.html. Debería ver dos gatos renderizados, pero solo tenemos una instancia de la clase ‘Gato’. Esto no es ideal; más bien, nos gustaría requerir dos instancias de ‘Gato’ si queremos representar dos gatos en la página. Para hacer eso, tenemos que examinar nuestro código render():
class Cat { void render() { var $element = $( """ <div class="animal"> <i class="icofont icofont-animal-cat"></i> </div> """ ); $("#content").append($element); } }
¿Ves lo que está mal?
Cada vez que se llama al método render(), estamos llamando a jQuery para crear un nuevo objeto, y luego representamos ese nuevo objeto en la página a través del método append() de jQuery. Lo que tenemos que hacer es hacer que la creación de los elementos de la página sea exclusiva de las instancias de clase . Podemos hacer esto simplemente moviendo la declaración de la variable en render() a un campo de clase. Aquí está nuestro código completo:
external $; module Animals { class Cat { var $element = $( """ <div class="animal"> <i class="icofont icofont-animal-cat"></i> </div> """ ); void render() { $("#content").append($element); } } }
No hemos hecho nada en el código anterior más que mover la declaración de variable de render() a la clase misma para que se convierta en un campo. Ahora, el campo solo se inicializará cuando instanciamos la clase. En otras palabras, la llamada a la función jQuery que ve que convierte HTML en un objeto jQuery no se ejecutará hasta que instanciamos nuestra clase usando la palabra clave ‘nuevo’.
Mantenga su código exactamente como lo tenía con las dos llamadas render() para la misma instancia de clase. Sin embargo, con el Cat.jspp actualizado, vuelva a compilar su código. Abra index.html. Debería ver solo un gato representado en la página.
Ahora intentemos crear dos gatos actualizando main.jspp para usar dos instancias de clase :
import Animals; Cat cat1 = new Cat(); cat1.render(); Cat cat2 = new Cat(); cat2.render();
Ahora debería ver dos gatos, uno para cada instancia de clase:
Nombrando a nuestros animales con campos y métodos
Si bien nuestro primer ejemplo de campos de clase involucró nombres, en realidad nunca agregamos un campo de nombre a nuestras clases. Sin embargo, en lugar de solo nombrar a nuestros gatos, también hagámoslo tangible al hacer que el nombre sea visible en el navegador web cuando pasamos el mouse sobre el animal. Como mostramos en nuestro ejemplo anterior, los campos como el nombre deben ser exclusivos de la instancia de la clase: no deben mostrarse dos elementos gato en la página con el mismo nombre si se les asignan nombres diferentes.
Inserte el siguiente código en Cat.jspp:
external $; module Animals { class Cat { string name; var $element = $( """ <div class="animal"> <i class="icofont icofont-animal-cat"></i> </div> """ ); void setName(string name) { this.name = name; } void render() { $("#content").append($element); $element.attr("title", name); } } }
Agregamos un nuevo campo: ‘nombre’ con tipo ‘string’. También agregamos un nuevo método ‘setName’. Contiene solo una línea de código:
this.name = name;
Notarás que el método toma un parámetro llamado ‘nombre’:
void setName(string name) { this.name = name; }
Para desambiguar el parámetro ‘nombre’ de nuestro campo de clase ‘nombre’, necesitamos usar ‘esto’. Cuando aparecen dos nombres en conflicto en el mismo método, esto se conoce como «sombreado variable». Es una conveniencia para que no tengamos que pensar en diferentes nombres de variables para describir el mismo concepto. Por lo tanto, lo que dice nuestra declaración es: establezca el campo de clase ‘nombre’ (‘este.nombre’) en el valor ‘nombre’ pasado como argumento a nuestro método.
La palabra clave ‘this’ dentro de una clase se refiere a la instancia de la clase. Los métodos de instancia de clase, como el método ‘setName’ que acabamos de definir, no se pueden llamar a menos que la clase haya sido instanciada primero. Una vez que hayamos instanciado la clase ‘Cat’, podemos llamar al método ‘setName’. Cuando llamamos al método de instancia ‘setName’, la palabra clave ‘this’ se refiere a la instancia de clase que ejecutó el método. Por lo tanto, la declaración anterior establecerá el campo ‘nombre’ de la instancia de clase en la que se está ejecutando ‘setName’; siempre es exclusivo de la instancia de la clase; por lo tanto, no habrá dos instancias de clase que terminen teniendo el mismo campo ‘nombre’ establecido después de una llamada al método ‘setName’.
Finalmente, agregamos la siguiente declaración a nuestro método ‘render’:
$element.attr("title", name);
Esto establecerá el atributo HTML ‘título’ de nuestro elemento cat HTML que representamos en la página. Al configurar el atributo ‘título’, podemos configurar el texto que aparece cuando pasamos el mouse sobre un elemento HTML. En este caso, cuando pasemos el cursor sobre nuestro elemento gato, veremos su nombre.
Antes de que podamos ver nuestros resultados, debemos establecer los nombres de nuestros gatos en main.jspp. Vamos a hacer eso:
import Animals; Cat cat1 = new Cat(); cat1.setName("Kitty"); cat1.render(); Cat cat2 = new Cat(); cat2.setName("Kat"); cat2.render();
Asegúrese de llamar a ‘setName’ antes que al método ‘render’.
Compile el código. Una vez más, para los usuarios de Windows, Mac y Linux, el comando ahora es el mismo:
$ js++ src/ -o build/app.jspp.js
Si el programa se compiló correctamente, abra index.html. Coloca tu nombre sobre cada gato. Deberías ver su nombre.