Aprende A Desarrollar Con JavaScript
Aprende A Desarrollar Con JavaScript
a desarrollar con JavaScript
Este libro, que trata sobre el aprendizaje en el desarrollo con JavaScript, se dirige a los lectores que deseen adquirir
las habilidades necesarias para dominar esta área, fundamental en los desarrollos Web. Es completamente esencial
dominar el software existente que permite adquirir el conocimiento del lenguaje JavaScript, si desea conseguir el
conocimiento suficiente dentro del sector específico relacionado con las tecnologías de la Web 2.0.
Partiendo de la base de que el lector solo tiene conocimientos básicos de programación, el autor comenzia recordando
y aportando conocimiento sobre algoritmia. A continuación, explica los conceptos principales del lenguaje JavaScript.
Los diferentes conceptos, principios o funcionalidades, se descubren a través de ejemplos concretos, fácilmente
reutilizables en otros desarrollos.
En la medida en que el lenguaje JavaScript se integra con otras tecnologías Web (o lenguajes), como el inevitable
HTML, las hojas de estilo CSS, los lenguajes orientados a la programación del lado servidor como PHP u otras
herramientas como Ajax, este libro también le permitirá dar sus primeros pasos, adentrándose en estas diferentes
tecnologías.
El autor se apoya en ejemplos que siguen una progresión lógica a lo largo de los capítulos.
Tiene a su disposición elementos adicionales que se pueden descargar desde esta página.
Los capítulos del libro:
Presentación del lenguaje JavaScript – Desarrollo a partir de algoritmos – Conceptos principales del lenguaje JavaScript
– Procesamiento condicionado – Procesamiento iterativo bucles – Tablas – Procedimientos y funciones – Enfoque
orientado a objetos en JavaScript – Principales objetos en JavaScript – Utilizar formularios para introducir datos –
Modelo DOM – Exploración del flujo XML via DOM – Gestión de las cookies en JavaScript – Almacenamiento local de datos
– Almacenamiento remoto: formato XML – Almacenamiento remoto: formato JSON – Geolocalización – Diseño HTML 5
CANVAS – Gráficos de gestión – Creación de documentos PDF – Creación de códigos QR
Christian VIGOUROUX
Christian VIGOUROUX es Doctor en la universidad de Rennes 1, en el área de componentes de gestión (IAE Instituto
de Gestión de Rennes). Ahí enseña desde hace casi de 30 años informática de gestión, encargado principalmente de la
enseñanza en Técnicas de Internet, Ingeniería de software e Informática decisional en el máster de Sistemas de
información y control de gestión, que él dirige. Adicionalmente, desarrolla actividades de consultoría en grandes
empresas, para la implantación de soluciones decisionales y la implantación de arquitecturas de software.
JavaScript, término que nos encontraremos muy a menudo en este libro con las siglas JS, es un lenguaje inventado
por Brendan Eich en 1995, que sirve principalmente para programar procesamientos del lado "cliente" en los
desarrollos Web. La primera versión de este lenguaje fue bautizado por LiveScript. El objetivo era proporcionar un
lenguaje de script al navegador (browser) Netscape Navigator 2.
Rápidamente, LiveScript fue renombrado por JavaScript, y una organización, el ECMA, se hizo responsable de los
aspectos relativos a la estandarización. En paralelo, Microsoft desarrolló su propia solución de scripting para su
navegador Internet Explorer.
La programación del lado "cliente" de JavaScript permite añadir una cierta interactividad a las páginas Web. En
particular, las páginas podrán reaccionar a las acciones del usuario, como la selección en una lista desplegable, la
selección de una casilla de selección o un clic en un botón de un formulario.
El código JavaScript, almacenado como archivos en un servidor Web, es accesible, a través del protocolo HTTP, por el
navegador del puesto "cliente", usando una llamada del usuario a través de la introducción de una URL o con un clic
en un enlace de hipertexto. El código JavaScript es no compilado y se interpreta por un motor dedicado, incorporado
al navegador.
El lenguaje JavaScript ha sufrido muchas evoluciones a lo largo del tiempo y se soporta prácticamente por todos los
principales navegadores (Microsoft Internet Explorer, Mozilla Firefox, Opera, Safari, Google Chrome...), que están en
los ordenadores, independientemente de su sistema operativo (diferentes versiones de Microsoft Windows, Unix,
Linux, Mac OS X...).
JavaScript se dejó de lado durante mucho tiempo porque tenía la reputación de ser difícil de depurar y tener
comportamientos muy diferentes entre un navegador y otro. Se han añadido muchas mejoras a lo largo de las
versiones (JavaScript 2.0 actualmente).
Puede encontrar la descripción completa de las novedades de JavaScript en el sitio web de Mozilla
(https://developer.mozilla.org/es/docs/Web/JavaScript).
Para terminar, JavaScript ha recuperado su esplendor con la aparición de muchas librerías de calidad y frameworks
(Ajax, jQuery, Dojo...). Por tanto, JavaScript es una piedra angular en los desarrollos de la "Web 2.0".
También mencionamos la confusión de los desarrolladores principiantes entre JavaScript y Java. No hay que confundir
Java y JavaScript. JavaScript es un lenguaje de programación de scripts desarrollado por Netscape Communications,
mientras que Java es un lenguaje de programación informático orientado a objetos, creado por James Gosling y
Patrick Naughton, empleados de Sun Microsystems. La sintaxis de los dos lenguajes es parecida, porque derivan los
dos del C++.
Comparativo Java/JavaScript:
Java JavaScript
Uso Se usa para desarrollar todo tipo de Se usa únicamente para "dinamizar"
aplicaciones las páginas Web
Muy a menudo, JavaScript se considera como un lenguaje muy accesible desde el punto de vista técnico.
Evidentemente, en desarrollos sencillos los principiantes podrán hacer sus intentos de manera fácil. Además, existe
una documentación importante sobre el tema (libros, sitios de Internet, foros, vídeos...).
Por el contrario, para aplicaciones profesionales, ya no será posible conformarse con descargar scripts y adaptarlos
para integrarlos en sus propias páginas HTML. Se deberá hacer una inversión real en formación y son necesarias
competencias mínimas en desarrollo de software.
De manera ideal, para controlar JavaScript en las mejores condiciones, hay que tener algunos conocimientos de
algoritmia, haber desarrollado previamente en un lenguaje de scripting o incluso, mejor, en un lenguaje evolucionado
como C++ o Java.
Este libro, accesible para los principiantes en desarrollo Web y en JavaScript en particular, repasará muchos requisitos
previos indispensables, en concreto de algoritmia (enfoque procedimental inicial) y del lenguaje HTML (sin hacer un
estudio exhaustivo), antes de abordar realmente JavaScript.
Es frecuente oír que "el desarrollo Web no necesita muchas herramientas". En un primer enfoque, es cierto que para
desarrollar páginas Web con lenguajes HTML y JavaScript es posible utilizar herramientas sencillas (y gratuitas). Un
editor de texto como Notepad y un navegador pueden ser suficientes. Incluso no es obligatoria una conexión a
Internet.
Por el contrario, para desarrollos importantes, puede ser útil tener piezas de software más evolucionadas (gratuitas o
de pago). Para elaborar sus scripts, puede utilizar editores de texto (gratuitos), que ofrecen prestaciones más
completas (coloración sintáctica, gestión multiarchivo, completar automáticamente el código, acceso FTP integrado,
soporte de múltiples lenguajes Web...). Por ejemplo, Notepad++ (http://notepadplusplus.org/) o Aptana Studio
(http://www.aptana.com/products/studio3/download) pueden sustituir a Notepad.
Kompozer (http://kompozer.net/) también es un software gratuito y puede ser una alternativa interesante. Se trata de
un software clasificado dentro de la categoría de IDE (Integrated Development Environment).
También existen muchos generadores de código o IDE gratuitos o de pago. El más conocido es Adobe Dreamweaver.
Para que sirva de orientación, muchos ejemplos utilizados en este libro se han desarrollado con Aptana Studio 3.4.1.
Los principales ejemplos de este libro se pueden descargar libremente desde la página Información. Para facilitarle su
uso, estos scripts están clasificados por capítulos. Se ha hecho un esfuerzo particular a nivel de la calidad de estos
scripts (comentarios, indentación, nomenclatura de variables...) para facilitar su reutilización.
Ubicamos también rápidamente el lenguaje JavaScript respecto a otros lenguajes o tecnologías habituales en los
proyectos de desarrollo Web. Sepa que el código JavaScript se utiliza de manera aislada muy raramente. Las
secuencias de código JavaScript son, la mayor parte de las veces, para animar los scripts HTML (HyperText Markup
Language). Para decir las cosas de una manera más sencilla, en la visualización de páginas Web, el lenguaje HTML
describe principalmente el contenido, mientras que el JavaScript, como se ha comentado anteriormente, gestiona la
interactividad.
Muy a menudo, el formateo de la información mostrada (secuencias de texto, tablas, imágenes...) no se asegura
directamente con directivas (etiquetas) del lenguaje HTML, sino usando una tecnología adicional (sin duda, es
exagerado hablar de lenguaje), el CSS (Cascading Style Sheets), también llamado "hojas de estilo en cascada".
También es muy importante entender que el lenguaje JavaScript está orientado al lado "cliente". Por lo tanto, es inútil
pedirle actuar en el lado "servidor". No puede acceder a las bases de datos almacenadas en el servidor y buscar
datos almacenados en las tablas. Hay lenguajes adicionales, muy utilizados en los proyectos Web, como PHP,
Microsoft ASP.NET e incluso Java, que tendrán precisamente este papel. Estos lenguajes, usando consultas SQL,
preguntan a las bases de datos y un intérprete (software de lado "servidor") genera sobre la marcha el código HTML,
que contiene la información leída de las tablas. Posteriormente se envía al navegador del puesto "cliente", usando el
protocolo HTTP. Solo queda que el navegador descodifique (descifre) el código HTML (y JavaScript si es necesario)
para conseguir una visualización sencilla consultable por un usuario humano.
Un algoritmo es la descripción de las operaciones necesarias para obtener un resultado a partir de valores de
entrada: los "datos". Un programa es un algoritmo escrito en un lenguaje concreto. Volveremos sobre esto más
adelante.
Una receta de cocina se puede considerar como un algoritmo. Para que sirva de ejemplo, la fabricación de un pastel
se basa en ingredientes (leche, mantequilla, harina, azúcar...) y se aplicará un procedimiento metódico (receta de la
abuela) para utilizar estos ingredientes (mezcla, tiempo de cocción...). Habrá comprobado en su día a día que
utilizamos algoritmos sin darnos cuenta realmente (recetas, noticias, planos de diseño, plantillas...).
Volvamos sobre nuestro ejemplo de la receta de cocina. En su ausencia, es posible conseguir el plato con una
sucesión de intentos (ensayos, tiempo de cocción aproximado). Evidentemente, esta forma de proceder (incluso si
para algunos es satisfactoria) no es eficaz (se pierde tiempo y es un lío de ingredientes).
La programación va a ser el medio de definir y especificar al ordenador el conjunto de operaciones necesarias para
resolver un problema. Se trata de la traducción a un lenguaje comprensible por la máquina de las secuencias de
acciones que se deben aplicar a los datos, en el marco de un procesamiento informático. Aquí también es posible
hacer una comparación con los idiomas; un mismo ordenador puede entender (ejecutar) varios lenguajes informáticos
(Pascal, C, C++, Java, ObjectiveC, JavaScript...). A partir de un algoritmo idéntico (una especie de modelo lógico),
será posible traducirlo de varias maneras programáticas.
En resumen, en el procesamiento de un problema, hay que distinguir dos fases principales:
l La búsqueda y redacción de una solución; un algoritmo (análisis del problema).
l La expresión del algoritmo en un lenguaje de programación para su explotación en el ordenador (codificación).
En este capítulo se exponen los principios generales de la algoritmia y se pone el acento en la formulación de
algoritmos en lenguaje descriptivo, en detrimento del lenguaje JavaScript, que se verá en detalle en los siguientes
capítulos.
Para que sirva de ejemplo, esto es lo que dice la enciclopedia Wikipedia sobre este asunto: un algoritmo (del griego y
latín, dixit algorithmus, y este a su vez del matemático persa AlJuarismi), es un conjunto prescrito de instrucciones o
reglas bien definidas, ordenadas y finitas que permite realizar una actividad mediante pasos sucesivos, que no generen
dudas a quien deba realizar dicha actividad. Dados un estado inicial y una entrada, siguiendo los pasos sucesivos, se llega
a un estado final y se obtiene una solución. Los algoritmos son el objeto de estudio de la algoritmia.
1. Presentación de las nociones de variable y tipo
Un algoritmo manipula objetos sobre los que puede realizar acciones. Los objetos simples son:
l números (3.14159, 1980, 9...),
l caracteres ("A", "9"...) y cadenas de caracteres ("PAULINA"...),
l valores booleanos o lógicos (verdadero o falso).
Para poder manipular estos objetos, hay operaciones disponibles. Estos objetos, así como las operaciones
asociadas, se deben definir perfectamente. Analicemos los tres ejemplos siguientes, que son situaciones de
intercambio entre un cliente y un vendedor.
Ejemplo 1:
l "Buenos días, quisiera 1 kg y 1 kg."
l "??"
Ejemplo 2:
l "Buenos días, señor, quisiera 1 kg de arroz y 1 kg de vino."
l "Aquí está su kilo de arroz y ¿qué más quería?"
Ejemplo 3:
l "Buenos días señor, quisiera 1 kg de arroz y 1 litro de vino."
l "Le he puesto todo en esta bolsa."
En estos ejemplos, comprobamos la necesidad de:
l citar la naturaleza de los objetos que vamos a manipular (arroz, vino...),
l no utilizar estos objetos de cualquier manera (el arroz se pesa, el vino se bebe...) es decir, para cada
naturaleza de objeto, hay operaciones particulares.
Se llama tipo a la asociación:
l de una naturaleza de objeto (arroz, vino, o incluso enteros, reales...),
l y las operaciones asociadas (pesar, lavar, cocinar el arroz, sumar, multiplicar enteros...).
2. Tipos básicos y operaciones asociadas
Hay cuatro tipos básicos: entero, real, booleano y carácter.
El tipo entero:
l Notación: se utiliza la notación decimal (ejemplos: 365, 15).
l Operaciones: adición, sustración, multiplicación, división entera, módulo (resto de la división entera), etc.
El tipo real:
l Los valores son números reales.
l Notación: el punto anglosajón se sustituye por la coma (ej.: 124.89, 0.136, 1986).
l Operaciones: las que se usan habitualmente con los números reales en aritmética.
El tipo booleano:
l Solo hay dos valores booleanos: verdadero o falso.
l Notación: Verdadero y Falso.
l Operaciones: se utilizan los operadores lógicos usuales (No, O e Y).
Recordemos el funcionamiento de los operadores lógicos No, Y y O, con esta tabla resumen:
A No A
Verdadero Falso
Falso Verdadero
A B A O B
A B A Y B
En resumen:
l El contrario de Falso es Verdadero e inversamente (cf. tabla de No).
l Con el O lógico, es suficiente con que uno de los operandos (A, B) sea Verdadero para que el resultado A O B sea
Verdadero (cf. tabla de O).
l Con el Y lógico, los dos operandos (A, B) deben ser simultáneamente Verdadero para que el resultado A Y B sea
Verdadero (cf. tabla del Y).
3. Interés de los tipos
La definición de estos tipos (naturaleza de los objetos y operaciones asociadas) es cercana a la "vida real". Este
lenguaje permitirá manipular los objetos de tipo "Sólido" y de tipo "Líquido".
Caractericemos estos dos tipos como sigue:
Sólido:
l Naturaleza: materia con forma propia
l Operaciones: fundir, comer
Líquido:
l Naturaleza: materia que tiende a fluir
l Operaciones: hervir, beber, vaciar
y escribimos un primer algoritmo:
Inicio
Sólido: mantequilla, queso, caucho
Líquido: aceite, agua, vino, refresco
Beber aceite, fundir mantequilla, fundir vino, comer caucho, beber sidra, cocinar caucho
Fin
Hay dos ventajas que se perciben con el uso de tipos en nuestro "lenguaje":
l Para describir objetos de la misma naturaleza, que admiten las mismas operaciones, es suficiente con describir el tipo
una vez para todos y anunciar que tal o cual objeto es de tal o cual tipo. Las repeticiones se evitan.
l El tipado (uso de tipos) proporciona un medio para detectar un determinado número de errores sin ejecutar el
algoritmo, simplemente examinando las operaciones respecto al tipo anunciado.
Sin realizar las acciones descritas en este algoritmo, vemos que la operación fundir vino es errónea, porque el vino
es un objeto declarado de tipo Líquido y la operación fundir no está asociada a este tipo. La operación comer caucho
es correcta, aunque el caucho sea indigesto. Beber sidra no es posible, porque la sidra no se ha citado como
elemento de tipo Líquido. Para terminar, es inútil declarar el agua y el refresco, porque no se usan.
4. Uso de variables en las expresiones
La manera más habitual de manipular los objetos es hacerlos intervenir en cálculos. Para esto, se utilizan los
operadores elementales sobre un operando (operadores unarios) o sobre dos operandos (operadores binarios).
Una expresión es la asociación de operadores y operandos. Las reglas gobiernan el orden de evaluación de los
diferentes términos de una expresión:
l Una operación se evalúa inicialmente si su prioridad es más fuerte que la de las operaciones adyacentes (ejemplo: el
l En caso de igualdad de prioridad, la evaluación tiene lugar de izquierda a derecha (ejemplo: 3+25 se evalúa
empezando por 3+2).
l Siempre podemos utilizar paréntesis para forzar el orden de evaluación (ejemplo: 3*(25) se evalúa empezando por
25).
5. Tabla resumen de los operadores
La siguiente tabla lista los operadores que se usan en algoritmia, así como la prioridad existente entre estos
operadores durante la evaluación de expresiones.
Resulta evidente que prácticamente siempre estos operadores se encontrarán (con las mismas notaciones) en los
lenguajes de programación. Volveremos más tarde en este libro sobre ellos, aplicados a JavaScript.
Los operadores se clasifican por orden de prioridad decreciente en esta tabla (el No es, por ejemplo,
prioritario respecto al O).
El orden de los caracteres se rige por la tabla ASCII. En esta tabla, cada carácter ocupa una posición numérica; el
65 para la letra "A", el 97 para la letra "a", lo que hace pensar que "a" es más grande que "A".
1. Nomenclatura de las variables
Durante el análisis de un problema, a menudo tenemos que descomponer este en subproblemas, que se deben
resolver en un orden secuencial concreto. Cada subproblema genera resultados que se pueden utilizar en los
subproblemas que siguen. Por tanto, para poder manipular estos resultados, conviene asignarles un nombre. Esta
nomenclatura se hace a través de un identificador. También se habla muy a menudo de variable en memoria.
A cada variable en memoria, se le asocia las siguientes características:
l su denominación, que se debe hacer con sentido (dos resultados diferentes se designan por identificadores
diferentes),
l su tipo (conjunto al que pertenece el valor que designa).
Estas características se precisan durante la declaración de la variable en memoria.
Sintaxis de la declaración:
Tipo IDENTIFICADOR
Tipo es el tipo e IDENTIFICADOR es la denominación de la variable en memoria.
Ejemplos:
Real PI
Car SEPARADOR
Bool TEST
Ent NBMESES, NBDIAS
Una vez que se define una variable en memoria, no se puede cambiar su tipo.
Cualquier variable en memoria utilizada en un algoritmo se debe haber declarado con antelación.
En lo sucesivo, se ha elegido nombrar a las variables en memoria en mayúsculas, para mejorar su legibilidad.
Debe saber que hay muchos lenguajes de programación que son sensibles a la diferencia entre mayúsculas y
minúsculas de las variables en memoria (una variable CANTIDAD es diferente de una variable Cantidad).
Evidentemente, en programación (JavaScript en nuestro caso), se pueden proponer diferentes convenciones de
nomenclatura.
En JavaScript, para las variables en memoria (y las funciones), la convención comúnmente aceptada es el
"camelCaps", es decir, que los nombres deben empezar sistemáticamente por una minúscula y después se insertan
mayúsculas al inicio de cada palabra que aparece en el nombre de la variable. Por ejemplo, una variable como
ACUMULADO_ANUAL (la convención en esta presentación de la algoritmia) se codificará como acumuladoAnual en
JavaScript.
2. Asignación
La asignación consiste en almacenar e incluso imputar una expresión a una variable en memoria. La sintaxis que se
mantiene en esta presentación de la algoritmia es:
IDENTIFICADOR < expresión
La asignación se representa con el símbolo "<" (y no con "=", que sirve para hacer comparaciones de igualdad).
La expresión debe ser del mismo tipo que los valores designados por el identificador. Esta expresión se convierte en
el nuevo valor, designado por IDENTIFICADOR.
Las convenciones que se mantienen aquí pueden ser diferentes de las que se usan en determinados lenguajes de
programación. Para JavaScript, la asignación se representa con "= ", mientras que la comparación en igualdad es
"= = ". Lo ha entendido con este pequeño ejemplo, pero es necesario estar muy atento durante la codificación en
programación. Tendremos la ocasión de volver sobre esta dificultad varias veces a lo largo de este libro.
Para ilustrar las diferentes nociones descritas, en adelante se presentan ejemplos en este libro. Esto le permitirá
descubrir los mecanismos de la algoritmia en cada situación. Después puede (también es el objetivo de esta
presentación) escribir sus propios algoritmos para procesamientos que usted codificará finalmente en JavaScript.
3. Ejercicio n.°1: Inversión del contenido de dos variables en memoria
Enunciado
Se le pide invertir el contenido de dos variables en memoria de tipo entero. La primera variable se llamará, por
ejemplo, A y la segunda B. El valor inicial de A será, por ejemplo, 5, mientras que el de B será 3. Utilizando un
algoritmo debe invertir los contenidos para que al final A contenga 3 y B, 5.
Inicio
Ent A, B, C
A < 5
B < 3
C < A
A < B
B < C
Fin
Para que sirva de ejemplo, el contenido de las variables en memoria a lo largo del desarrollo del algoritmo será:
l A < 5 (A contiene 5, B está vacío)
l B < 3 (A contiene 5, B contiene 3)
l C < A (A contiene 5, B contiene 3, C contiene 5)
l A < B (A contiene 3, B contiene 3, C contiene 5)
Terminamos con algunas reglas generales de formato y sintaxis:
l Puede prever una línea en blanco (interlineado) entre las secciones principales de su algoritmo (declaraciones,
inicializaciones, cálculos, visualización de resultados...) e incluso, por qué no, justo después de Inicio y antes de Fin.
l Prevea un trazo vertical para relacionar la palabra clave Inicio con la palabra clave Fin.
l Observe que las palabras clave aparecen en Negrita/Cursiva en las correcciones (inicial únicamente en mayúscula).
l Los nombres de las variables estarán completamente en MAYÚSCULAS (contrario a las convenciones habituales en
JavaScript).
4. Visualización de los resultados
En el ejercicio anterior, la inversión del contenido de las dos variables A y B se hace sin dificultad. Por el contrario, el
contenido de estas dos variables no se ha presentado en la pantalla (o en el visor). Es útil mostrar en pantalla el
resultado de los procesamientos, al menos el resultado final. Esta visualización (o escritura) de los resultados se
debe solicitar explícitamente.
A nivel de algoritmia, se va a considerar que la escritura se hace después en una sucesión de líneas, sin indicación
particular del formato de visualización (negrita, cursiva, fuente de caracteres específica...).
El orden de escritura se realiza por la instrucción Escribir(e1, e2, ..., ei, ..., en), donde las "ei" pueden representar:
l una expresión,
l una cadena de caracteres representada entre comillas,
l el orden Alineación, que hace empezar la impresión en la línea siguiente.
Ejemplo n.°1:
Escribir("El cuadrado de 4 es ", 4 * 4)
provoca la impresión de:
El cuadrado de 4 es 16
Ejemplo n.°2:
Escribir("La nota en español es ", 10 + 4, Alineación, "La nota en informática es ", (18 + 12) / 2)
provoca la impresión de:
La nota en español es 14
La nota en informática es 15
Ejemplo n.°3:
Escribir("La nota en español es ", 10 + 4)
Escribir("La nota en informática es ", (18 + 12) / 2)
provoca la impresión de:
La nota en español es 14
La nota en informática es 15
Real MAT, INFO
MAT < 15
INFO < 13
Escribir("La media es ", (MAT + INFO) / 2)
provoca la impresión de:
La media es 14
Ejemplo n.°5:
Real MAT, INFO, MED
MAT < 15
INFO < 13
MED < (MAT + INFO) / 2
Escribir("La media es ", MED)
provoca la impresión de:
La media es 14
En la gran mayoría de los lenguajes de programación, la instrucción de visualización de mensajes en pantalla no
permite la presentación simultánea de una información alfanumérica y numérica. Por tanto, también convendría en la
algoritmia integra esta restricción, usando la función Numero_a_cadena. En la mayor parte de las correcciones de
ejercicios propuestos en este capítulo esta función no se ha utilizado.
Ejemplo n.°6:
Real MAT, INFO
MAT < 15
INFO < 13
Escribir("La media es ", Número_a_cadena((MAT + INFO) / 2))
provoca la impresión de:
La media es 14
5. Ejercicio n.°2: Superficies de círculos
Enunciado
Calcular (y mostrar en pantalla) la superficie de dos círculos de radios predeterminados (5,5 metros y 3,5 metros,
por ejemplo), así como la diferencia entre estas dos superficies
Corrección
Inicio
Real RADIO1, RADIO2, PI, SUPERFICIE1, SUPERFICIE2, DIFERENCIA
RADIO1 < 5.5
RADIO2 < 3.5
PI < 3.14
SUPERFICIE1 < PI * RADIO1 * RADIO1
SUPERFICIE2 < PI * RADIO2 * RADIO2
DIFERENCIA < SUPERFICIE1 SUPERFICIE2
Fin
6. Introducción por el teclado
Los algoritmos no tienen un interés general si, durante cada ejecución, proporcionan siempre el mismo resultado.
Para acceder a los datos que el usuario ha introducido por el teclado (o se han leído de un archivo), a nivel de
algoritmia tendremos una instrucción dedicada. La entrada de datos en el periférico de entrada se hará a través de
la instrucción Leer.
La entrada de datos por Leer se asignará a una variable en memoria (declarada con antelación). La instrucción Leer
se deberá preceder obligatoriamente de un mensaje explicativo (Escribir("Su entrada de datos:") por ejemplo) para
indicar al usuario la entrada de datos esperada.
Ejemplo:
Inicio
Co Declaraciones Fco
Car NOMBRE, APELLIDO
Co Introducción del nombre por el teclado Fco
Escribir("Nombre: ")
NOMBRE < Leer
Co Introducción del apellido por el teclado Fco
Escribir("Apellido: ")
APELLIDO < Leer
Co Visualización de la pantalla para control Fco
Escribir("La identidad es ", NOMBRE, " ", APELLIDO)
Fin
NB:
Co significa inicio de comentario
Fco significa fin de comentario
Los comentarios situados en un algoritmo (y en un programa informático) no juegan un papel efectivo. En el caso de
un lenguaje de programación como JavaScript, serán ignorados por la máquina durante la ejecución del programa.
Sin embargo, son necesarios, porque permiten al programador (o a terceras personas que deban intervenir
posteriormente en el algoritmo o programa) entender más fácilmente el razonamiento codificado. Los comentarios se
sitúan, como mínimo, al inicio de cada porción de código específico.
7. Ejercicio n.°3: Superficie y volumen de una esfera
Enunciado
Calcular y mostrar la superficie y el volumen de una esfera, cuyo valor del radio se introducirá por el teclado
Corrección
Co Declaraciones Fco
Real PI, RADIO, SUPERFICIE, VOLUMEN
Co Introducción del radio por el teclado Fco
Escribir("Radio: ")
RADIO < Leer
Co Cálculos Fco
PI < 3.14
SUPERFICIE < 4 * PI * RADIO * RADIO
VOLUMEN < SUPERFICIE * RADIO / 3
Co Visualización de los resultados Fco
Escribir("Radio de la esfera = ", RADIO, Alineación, "Superficie = ", SUPERFICIE, Alineación,
"Volumen = ", VOLUMEN)
Fin
Una función predefinida es un "microprograma" autónomo, al que es posible pedir un procesamiento (un cálculo en
general), pasando uno o varios argumentos. Una vez que el cálculo está asegurado, la función restituye un valor de
retorno (la respuesta) al solicitante (secuencia de código que llama a la función). Esta noción seguramente le es
familiar si, por ejemplo, ha utilizado funciones nativas en Microsoft Excel (SUMA, BUSCAR...).
Veremos más tarde en esta presentación de la algoritmia (y también, sobre todo, en JavaScript) cómo desarrollar sus
propias funciones.
El objetivo aquí no es enumerar la lista de funciones habituales en algoritmia (además pueden variar de un autor a
otro), sino mostrarle cómo se pueden usar. Se utilizará una presentación a través de ejemplos o ejercicios.
1. Ejercicio n.°4: Visualización de la longitud de un nombre
Enunciado
Escribir un algoritmo que permita introducir por el teclado un nombre para mostrar el número de caracteres
Complemento del ejercicio: Una función Longitud(variable_cadena) predefinida se utilizará para determinar el
número de caracteres de la palabra.
Correcciones
Inicio
Co Declaraciones Fco
Car NOMBRE
Co Introducción del nombre por el teclado Fco
Escribir("Nombre:")
NOMBRE < Leer
Co Visualización del resultado Fco
Escribir(NOMBRE, " contiene " , Longitud(NOMBRE), " carácter(es)")
Fin
E incluso:
Inicio
Co Declaraciones Fco
Car NOMBRE
Ent NB_CAR
Co Introducción del nombre por el teclado Fco
Escribir("Nombre: ")
NOMBRE < Leer
Co Visualización del resultado Fco
NB_CAR < Longitud(NOMBRE)
Escribir(NOMBRE, " contiene " , NB_CAR, " carácter(es)")
Fin
2. Ejercicio n.°5: Determinación de iniciales
Escribir un algoritmo que permita la extracción de las iniciales de una persona, cuyo apellido y nombre se
introducirán por el teclado (ejemplo: AS para Ángel Sánchez)
Complemento: se utilizará una función Sub_cadena(CADENA, POSICION_INICIO, [POSICION_FIN]) predefinida.
Un argumento de función que no es sistemáticamente necesario se indica por convención entre corchetes.
En caso de la función Sub_cadena, si el tercer argumento no está, la extracción se hará a partir del carácter en
posición POSICION_INICIO, hasta el final de la cadena de caracteres.
En muchos lenguajes de programación, este tercer argumento (aquí POSICION_FIN) es, en realidad, un número
de caracteres que se ha de extraer a partir de la posición POSICION_INICIO).
En lo sucesivo, encontrará ejemplos concretos de la aplicación de la función Sub_cadena, así como de funciones
adicionales (Izquierda, Derecha, Concatenar...).
Car NOMBRE, APELLIDO, INICIALES
NOMBRE < "Ángel"
Sub_cadena(NOMBRE, 1, 3) vale ”Áng"
Izquierda(NOMBRE, 4) vale ”Ánge"
Sub_cadena(NOMBRE, 3, 2) vale ”el"
Sub_cadena(NOMBRE, 3) vale ”el"
Sub_cadena(NOMBRE, Longitud(NOMBRE), Longitud(NOMBRE)) vale ”l"
Sub_cadena(NOMBRE, Longitud(NOMBRE)) vale ”l"
Sub_cadena(NOMBRE, Longitud(NOMBRE)1, Longitud(NOMBRE)) vale ”el"
Derecha(NOMBRE, 2) vale ”gel"
Izquierda(APELLIDO, 1) & Izquierda(NOMBRE, 1) vale ”SA"
APELLIDO < "Sánchez"
INICIALES < Sub_cadena(APELLIDO, 1, 1) & Sub_cadena(NOMBRE, 1, 1) vale ”SA"
INICIALES < Concatenar(Sub_cadena(NOMBRE, 1, 1), Sub_cadena(APELLIDO, 1, 1)) vale ”AS"
El ampersand (&) sirve para concatenar dos elementos de tipo carácter.
Corrección
Inicio
Co Declaraciones Fco
Car APELLIDO, NOMBRE, INICIAL_APELLIDO, INICIAL_NOMBRE
Co Introducción del apellido Fco
Escribir("Apellido: ")
APELLIDO < Leer
Co Introducción del nombre Fco
Escribir("Nombre: ")
NOMBRE < Leer
Co Determinación de las iniciales Fco
INICIAL_APELLIDO < Sub_cadena(APELLIDO, 1, 1)
INICIAL_NOMBRE < Sub_cadena(NOMBRE, 1, 1)
Fin
E incluso:
Inicio
Co Declaraciones Fco
Car APELLIDO, NOMBRE, INICIALES
Co Introducción del apellido Fco
Escribir("Apellido: ")
APELLIDO < Leer
Co Introducción del nombre Fco
Escribir("Nombre: ")
NOMBRE < Leer
Co Visualización de las iniciales Fco
INICIALES < Izquierda(APELLIDO, 1) & Izquierda(NOMBRE, 1)
Escribir(APELLIDO, " ", NOMBRE, " tiene como iniciales: ", INICIALES)
Fin
En muchas situaciones, las acciones solo se realizan si se cumplen determinadas condiciones:
l Una ecuación de segundo grado tiene 0, 1 o 2 soluciones reales, según sea el discriminante negativo, nulo o positivo.
l Si una cantidad de artículos en stock baja de un determinado umbral, hay que hacer un pedido.
l Si hace bueno, entonces vamos a la playa. En caso contrario hacemos algoritmia juntos.
l Si no hace bueno, entonces hacemos algoritmia juntos.
Cada una de estas opciones está condicionada por una expresión booleana que, mientras sea verdadera, implica la
ejecución del procesamiento asociado.
La sintaxis de la algoritmia para programar los procesamientos condicionados es sencilla:
Si Condición
Entonces
T1
[En caso contrario
T2]
Finsi
Algunas observaciones sobre esta estructura tan intuitiva:
l Condición es una expresión con resultado booleano (Verdadero o Falso).
l T1 y T2 son los procesamientos.
l Finsi significa el fin del si.
l Existe una forma simplificada, sin alternativa (sin En caso contrario T2).
l Comprobar la condición se hace en una hipótesis de condición verdadera.
l Dibujar un trazo vertical (a la izquierda) entre Si y Finsi será un medio mnemotécnico para no olvidar el Finsi.
l Piense en indentar los procesamientos T1 y T2.
El organigrama de flujo correspondiente a esta estructura es el siguiente:
Inicio
Co Declaraciones Fco
Ent NBLU
Co Introducción por el teclado Fco
Escribir("Número: ")
NBLU < Leer
Co Determinación de la parte Fco
Si NBLU Mod2 = 0
Entonces
Escribir(NBLU, " es par")
En caso contrario
Escribir(NBLU, " es impar")
Finsi
Fin
1. Ejercicio n.°6: Polinomio de segundo grado
Enunciado
Calcular las raíces de un polinomio de segundo grado Ax2 +Bx+C (con A<>0 aunque esta prueba no se hará aquí).
Los valores A, B y C se introducirán por el teclado.
Corrección
Inicio
Co Declaraciones Fco
Real A, B, C, DELTA
Escribir("B: ")
B < Leer
Escribir("C: ")
C < Leer
Co Cálculo del discriminante Fco
DELTA < (B * B) (4 * A * C)
Co Determinación del número de raíces Fco
Si DELTA < 0
Entonces
Escribir("Sin soluciones")
En caso contrario
Si DELTA = 0
Entonces
Escribir("Solución única = ", B / (2 * A))
En caso contrario
Escribir("Dos raíces: ", (B+DELTA**0.5)/(2*A), " y ", (BDELTA**0.5)/(2*A))
Finsi
Finsi
Fin
El interés de este ejercicio, además de que revise un poco las matemáticas, es mostrar que es posible anidar
estructuras condicionales. La aplicación no es difícil, pero implica un mínimo de rigor, fundamentalmente no olvidar
cerrar sus estructuras con un Finsi y también indentar (añadir un nivel de desplazamiento) los procesamientos,
incluidos después de los Entonces y En caso contrario.
2. Ejercicio n.°7: Etiqueta del mes sin cifrar
Enunciado
Imprimir en letras el mes correspondiente a un número dado por el teclado (comprendido entre 1 y 12). El control de
la entrada de datos no se prevé.
Corrección
Inicio
Co Declaraciones Fco
Ent MESES
Co Introducción del número del mes Fco
Escribir("Número del mes (1 a 12): ")
MESES < Leer
Co Visualización del resultado Fco
Si MESES=1
Entonces
Escribir("Enero")
En caso contrario
Entonces
Escribir("Febrero")
En caso contrario
…
Finsi
Fin
Evidentemente, la solución propuesta es opuesta a su nivel de elaboración, pero desde el punto de vista técnico es
óptima. Por ejemplo, la entrada de datos de la cifra 2 provocará la visualización correcta ("Febrero").
También habría sido posible "superponer" 12 pruebas sucesivas, como se indica a continuación. Esta solución es
poco satisfactoria porque, independientemente del valor introducido por el teclado, se ejecutan las 12 pruebas.
Inicio
Co Declaraciones Fco
Ent MESES
Co Introducción del número del mes Fco
Escribir("Número del mes (1 a 12): ")
MESES < Leer
Co Visualización del resultado Fco
Si MESES=1
Entonces
Escribir("Enero")
Finsi
Si MESES=2
Entonces
Escribir("Febrero")
Finsi
…
Si MESES=12
Entonces
Escribir("Diciembre")
Finsi
Fin
La estructura de control Siguiente ... Finsiguiente es una solución elegante para gestionar este tipo de
problemática. La sintaxis es la siguiente:
Siguiente VARIABLE/EXPRESION
Valor_1: Accion_1
…
Valor_n: Accion_n
[Otrocaso: Acción por defecto]
Finsiguiente
La estructura Siguiente ... Finsiguiente (o su equivalente) no está implementada en todos los lenguajes de
programación.
3. Ejercicio n.°8: Etiqueta del mes sin cifrar (Siguiente ... Finsiguiente)
Inicio
Co Declaraciones Fco
Ent MESES
Co Introducción del número del mes Fco
Escribir("Número del mes (1 a 12): ")
MESES < Leer
Co Visualización del resultado Fco
Siguiente MESES
1: Escribir("Enero")
2: Escribir("Febrero")
...
12: Escribir("Diciembre")
Otrocaso: Escribir("Error de entrada de datos del n.° de mes")
Finsiguiente
Fin
En este ejercicio se muestra un mensaje de error dentro de Otrocaso. En contrapartida, será necesario que el
usuario del algoritmo (o del programa) lo ejecute de nuevo porque, de momento, no se ha previsto ningún
dispositivo para que se haga una nueva entrada de datos.
1. Concepto de iteraciones
En la mayor parte de los problemas, determinadas acciones se deben ejecutar varias veces.
Cuando el número de repeticiones es grande, resulta pesado rescribir n veces la misma secuencia de código. Esta
rescritura es imposible en el caso en que el número de repeticiones (iteraciones) es desconocido a priori (trazar un
conjunto de datos hasta que no haya más).
Es necesario poder expresar la repetición de una acción que, una vez inicializada, continuará hasta que se produzca
un determinado evento. Este evento de parada se especificará en el algoritmo con una condición.
2. Estructuras iterativas básicas
Vamos a estudiar cuatro tipos de iteraciones (bucles), que tendrán su equivalente en los principales lenguajes de
programación.
Bucle "Mientras" con una comprobación inicial de iteración:
Mientras Condición Hacer
Acciones
Volverhacer
Bucle "Hasta que" con una comprobación inicial de iteración:
Hastaque Condición Hacer
Acciones
Volverhacer
Bucle "Mientras" con una comprobación final de iteración:
Hacer
Acciones
Mientras Condición Volverhacer
Bucle "Hasta que" con una comprobación final de iteración:
Hacer
Acciones
Hastaque Condición Volverhacer
Estos cuatro bucles tienen un determinado número de puntos en común:
l Hastaque es una abreviación para Hasta que
l Mientras es una abreviación para Mientras
l Acciones representa una secuencia de acciones
Con las dos últimas iteraciones para las que se hace la comprobación del final de bucle, las Acciones se realizan al
menos una vez.
Los bucles "Mientras" y "Hasta que" tienen un funcionamiento muy parecido, en la medida en que es suficiente con
invertir la condición para pasar de una sintaxis a otra. Por ejemplo, CONTADOR > 10 en el caso de un bucle
"Mientras" se convertirá en CONTADOR <= 10 en caso de un bucle "Hasta que".
El siguiente diagrama de flujo corresponde a las estructuras "Mientras" y "Hasta que" (con una comprobación inicial
de iteración):
En caso de un bucle Hastaque:
l la flecha que une "Condición" a "Acciones" corresponde al estado Falso de la Condición,
l la flecha que une "Condición" a "Acciones siguientes" corresponde al estado Verdadero de la Condición.
En caso de un bucle Mientras:
l la flecha que une "Condición" a "Acciones" corresponde al estado Verdadero de la Condición,
l la flecha que une "Condición" a "Acciones siguientes" corresponde al estado Falso de la Condición.
3. Ejercicio n.°9: Media de 10 números
Enunciado
Calcular y mostrar la media de 10 números que se introducirán por el teclado
Inicio
Co Cálculo de la media de 10 números que se introducirán por el teclado Fco
Co Declaraciones Fco
Real NBLU, CPT, SUMA, MEDIA
Co Inicializaciones Fco
CPT < 1
SUMA < 0
Co Iteración Fco
Mientras CPT < 11 Hacer
Escribir("Número n.° ", CPT, ": ")
NBLU < Leer
SUMA < SUMA + NBLU
CPT < CPT + 1
Volverhacer
Co Visualización del resultado Fco
MEDIA < SUMA / 10
Escribir("Media: ", MEDIA)
Fin
4. Ejercicio n.°10: Media de una serie de n números
Enunciado
Calcular y mostrar la media de n números reales que se introducirán por el teclado (lista terminada con un cero)
Aprovechamos este enunciado un poco más complejo para mostrar que una misma problemática se puede resolver
utilizando múltiples algoritmos.
Corrección n.°1
Inicio
Co Declaraciones Fco
Real NBLU, CPT, SUMA, MEDIA
Co Inicializaciones Fco
CPT < 0
SUMA < 0
NBLU < 1 Co Para permitir pasar por la iteración, al menos una vez Fco
Co Bucle de lectura Fco
Hastaque NBLU = 0 Hacer
Escribir("Número (0 para terminar): ")
NBLU < Leer
CPT < CPT +1
SUMA < SUMA + NBLU
Volverhacer
Co Visualización del resultado Fco
MEDIA < SUMA / (CPT1)
Escribir("Media de los ", CPT 1, "números = ", MEDIA)
En esta corrección, la entrada del número cero no provoca la salida inmediata del bucle. Por tanto, es necesario
reducir el valor de la variable CPT (contador de la cantidad de números que se introducen por el teclado) en el
cálculo de la media. También es necesario pensar en asignar un valor inicial a la variable NBLU (aquí 1) antes de la
iteración, para que se pueda iniciar. Para terminar, con esta versión de corrección, se produciría un problema
(división por cero) si el primer número introducido por el teclado es un 0.
Corrección n.°2
Inicio
Co Declaraciones Fco
Real NBLU, CPT, SUMA, MEDIA
Co Inicializaciones Fco
CPT < 0
SUMA < 0
Co Bucle de lectura Fco
Hacer
Escribir("Número (0 para terminar): ")
NBLU < Leer
CPT < CPT +1
SUMA < SUMA + NBLU
Mientras NBLU <> 0 Volverhacer
Co Visualización del resultado Fco
Si CPT1=0
Entonces
Escribir("No se ha introducido ninguna cifra ")
En caso contrario
MEDIA < SUMA / (CPT1)
Escribir("Media de los ", CPT 1, "números = ", MEDIA)
Finsi
Fin
En esta corrección, se ha utilizado un bucle Mientras con una comprobación final de bucle. Aquí no es necesario
asignar un valor ficticio a la variable NBLU antes del bucle. Además, una estructura condicional después de la
iteración permite evitar una posible división por 0.
Corrección n.°3
Inicio
Co Declaraciones Fco
Real NBLU, CPT, SUMA, MEDIA
Co Inicializaciones Fco
CPT < 0
SUMA < 0
Co primera entrada de datos Fco
Escribir("Número (0 para terminar): ")
NBLU < Leer
Co Bucle de lectura Fco
CPT < CPT +1
SUMA < SUMA + NBLU
Escribir("Número (0 para terminar): ")
NBLU < Leer
Volverhacer
Co Visualización del resultado Fco
Si CPT=0
Entonces
Escribir("No se ha introducido ninguna cifra")
En caso contrario
MEDIA < SUMA / CPT
Escribir("Media de los ", CPT, "números = ", MEDIA)
Finsi
Fin
En esta corrección, se ha mantenido un bucle Mientras con una comprobación inicial de este. La particularidad es
que se hace una primera entrada de datos por el teclado (variable NBLU) antes de la iteración, lo que obliga a
continuación a prever la entrada de los números siguientes de la secuencia, al final de la iteración. El interés de esta
solución es que el cero final no se tiene en cuenta en la variable CPT.
5. Ejercicio n.°11: El común divisor más grande, por el método de las divisiones
sucesivas
Enunciado
Calcular el MCD de dos números enteros leídos por el teclado (método de la división)
El desarrollo del cálculo es la siguiente:
l Introducir los números A y B por el teclado
l Calcular el RESTO de la división entera de A por B
l Cuando este RESTO es nulo, B es el MCD buscado
l Sustituir A por B
l Sustituir B por este RESTO
l Empezar de nuevo a nivel del cálculo del RESTO
Aprovechamos este enunciado para destacar que los bucles Mientras y Hastaque se pueden utilizar
indistintamente en la resolución de los problemas iterativos; basta con invertir lógicamente la condición verificada.
Es necesario observar que el bucle Mientras es sistemáticamente implementado en los lenguajes de programación
(en general llamado While o Do While). El bucle Hastaque (que se traduciría por un Until o Do Until) no es,
por el contrario, sistemáticamente implementado.
Corrección n.°1
Inicio
Co Declaraciones Fco
Ent A, B, RESTO
Co Bucle de procesamiento Fco
RESTO < A Mod B
Mientras RESTO <> 0 Hacer
A < B
B < RESTO
RESTO < A Mod B
Volverhacer
Co Fin de procesamiento Fco
Escribir("MCD = ", B)
Fin
Corrección n.°2
Inicio
Co Declaraciones Fco
Ent A, B, RESTO
Co Introducción de los dos números Fco
Escribir("Primer número: ")
A < Leer
Escribir("Segundo número: ")
B < Leer
Co Bucle de procesamiento Fco
RESTO < A Mod B
Hastaque RESTO = 0 Hacer
A < B
B < RESTO
RESTO < A Mod B
Volverhacer
Co Fin de procesamiento Fco
Escribir("MCD = ", B)
Fin
6. Estructura iterativa Para
Las estructuras iterativas Hastaque Hacer … Volverhacer y Mientras Hacer … Volverhacer se pueden sustituir
por la estructura iterativa Para Hacer … Volverhacer cuando el número de iteraciones es conocido antes del inicio
de la estructura y solo en este caso.
Esta iteración, un poco confusa al inicio, tiene la particularidad de presentar un determinado automatismo respecto
a la gestión del contador de iteraciones realizadas.
Su sintaxis general es:
Para VARIABLE De EXPRESION_INICIO A EXPRESION_FIN [No EXPRESION_NO] Hacer
Volverhacer
Veamos sus particularidades:
l VARIABLE es una variable entera, que se debe declarar al inicio del algoritmo.
l EXPRESION_INICIO es una constante entera (por ejemplo, 1) o una variable entera, que se debe declarar al inicio del
algoritmo e inicializar antes de la estructura iterativa.
l EXPRESION_FIN es una constante entera (por ejemplo, 10) o una variable entera, que se debe declarar al inicio del
algoritmo e inicializar antes de la estructura iterativa.
l EXPRESION_NO es una constante entera (por ejemplo, 2) o una variable entera, que se debe declarar al inicio del
algoritmo e inicializar antes de la estructura iterativa. Lo más habitual es que No EXPRESION_NO no se prevea en este
tipo de iteración.
l EXPRESION_NO puede ser negativo. En este caso, EXPRESION_INICIO debe ser > (o eventualmente = ) a
EXPRESION_FIN.
l En informática, un argumento opcional se representa como sigue: [argumento]. Cuando el argumento es obligatorio,
los [] no se ponen.
7. Ejercicio n.°12: Cálculo de la media de 10 números
Enunciado
Calcular la media de 10 números que se introducirán por el teclado, con un bucle Para
Corrección
Inicio
Co Cálculo de la media de 10 números que se introducirán por el teclado Fco
Co Declaraciones Fco
Ent CPT
Real NBLU, SUMA, MEDIA
Co Inicializaciones Fco
SUMA < 0
Co Iteración Fco
Para CPT De 1 A 10 Hacer
Escribir("Número n° ", CPT, ": ")
NBLU < Leer
SUMA < SUMA + NBLU
Co NB: sobre todo, no hay que modificar el valor de la variable CPT en el bucle Fco
Volverhacer
Co Visualización del resultado Fco
MEDIA < SUMA / 10
Escribir("Media: ", MEDIA)
Co NB: Es necesario evitar dividir aquí la SUMA por CPT Fco
Co en la medida en que en determinados lenguajes Fco
Co CPT valdrá 11 en salida Fco
Como se indica en los comentarios en el algoritmo anterior, es mejor no utilizar directamente el valor de la variable
CPT (que ha servido para contar los números que se introducen por el teclado) porque, según las variantes de
implementación de los lenguajes de programación, CPT podría valer 10 u 11.
8. Ejercicio n.°13: Deducir el número de vocales de una palabra
Enunciado
Contar el número de vocales de una palabra introducida por el teclado
Recordatorio: se utilizará una función Longitud(CADENA) para determinar el número de caracteres de la palabra
introducida. La función Sub_cadena(CADENA, POSICION_INICIO, [POSICION_FIN]) también será necesaria.
Corrección
Inicio
Co Declaraciones Fco
Car PALABRA
Ent NB_VOCALES, CONTADOR
Co Introducción de la palabra por el teclado Fco
Escribir("Palabra: ")
PALABRA < Leer
Co Poner en mayúsculas la palabra Fco
PALABRA < Mayúsculas(PALABRA)
Co Inicialización de las variables Fco
NB_VOCALES < 0
Co Determinación del número de vocales Fco
Para CONTADOR De 1 ALongitud(PALABRA) Hacer
Co Analizar la letra actual Fco
Siguiente Sub_cadena (PALABRA, CONTADOR, CONTADOR)
"A": NB_VOCALES < NB_VOCALES + 1
"E": NB_VOCALES < NB_VOCALES + 1
"I": NB_VOCALES < NB_VOCALES + 1
"O": NB_VOCALES < NB_VOCALES + 1
"U": NB_VOCALES < NB_VOCALES + 1
Finsiguiente
Volverhacer
Co Visualización del resultado Fco
Escribir(PALABRA, "contiene: ", NB_VOCALES, " vocal(es)")
Fin
Por la primera vez, vemos una estructura condicional (Siguiente ... Finsiguiente) integrada en una estructura
iterativa (Para). Evidentemente, esta estructura condicional habría podido estar basada en un Si ... Finsi.
En función de la problemática que se ha de resolver, habrá comprobado que es necesario combinar lo mejor posible
las estructuras condicionales (Si ... Finsi o Siguiente ... Finsiguiente) con las diferentes variantes de bucles
(Mientras, Hastaque y Para) anidándolas, utilizándolas secuencialmente, etc.
Una tabla agrupa varios valores del mismo tipo. Globalmente, podemos nombrar todos los valores o designar de
manera precisa uno de ellos con una operación de scripting.
Por ejemplo, consideremos ALFABETO como el conjunto de letras del alfabeto. En este caso:
l ALFABETO designa una tabla que podrá servir para almacenar el conjunto de letras del alfabeto.
l ALFABETO(14) podría representar la letra "N".
l El entero 14 se llama índice.
En un algoritmo, como sucede con las variables (simples) vistas hasta ahora, las tablas se deben declarar antes de
poder utilizarlas. La sintaxis de declaración es:
Tipo IDENTIFICADOR(INF: SUP)
Observe que a nivel de esta declaración:
l IDENTIFICADOR es el nombre global de la tabla (nombre libremente elegido por el programador, en mayúsculas si
es posible).
l Tipo indica el tipo de los elementos de la tabla, y todos los elementos de la tabla tienen el mismo tipo (Entero,
Real, Bool, Carácter).
l INF y SUP son, respectivamente, los extremos inferior y superior del intervalo de variación del índice de la tabla. Una
tabla como esta tiene N elementos, donde N = SUP INF + 1.
l INF y SUP son constantes definidas con antelación (sin dimensionamiento "dinámico", aunque determinados
lenguajes de programación lo permiten).
l En determinados lenguajes de programación, el valor INF no se puede expresar. En este caso, el valor INF se considera
implícitamente como 1 (algunas veces también 0). Cuando es posible, es mejor evitar el uso del índice con valor cero.
La tabla ALFABETO mencionada anteriormente se podría declarar como sigue:
Car ALFABETO(1:26)
Car ALFABETO(0:25) > es un poco particular pero también muy usual.
Veamos ahora cómo utilizar este tipo de tabla (asignación de valores a las diferentes "celdas" y lectura de estos
valores a continuación). La sintaxis es intuitiva:
IDENTIFICADOR(ÍNDICE)
Observe a nivel del uso de las tablas:
l IDENTIFICADOR es el nombre de la tabla.
l ÍNDICE es una expresión entera, cuyo valor debe pertenecer al intervalo (INF: SUP).
l La notación IDENTIFICADOR(ÍNDICE) designa a un elemento de la tabla, identificado por su índice en la tabla.
1. Ejercicio n.°14: Contar los números pares en una tabla
Determinación de la cantidad de números pares en una tabla (entrada de datos inicial a través del teclado).
Corrección
Inicio
Co Determinación de la cantidad de números pares en una tabla Fco
Co Declaraciones Fco
Ent TB(1: 10)
Ent NB_PARES
Ent IND
Co Inicializaciones Fco
NB_PARES < 0
Co Carga de la tabla Fco
Para IND De 1 A 10 Hacer
Escribir("TB(", IND, "): ")
TB(IND) < Leer
Volverhacer
Co Determinación de la cantidad de números pares Fco
Para IND De 1 A 10 Hacer
Si TB(IND) Mod 2 = 0 Entonces
NB_PARES < NB_PARES + 1
Finsi
Volverhacer
Escribir("Cantidad de números pares de la tabla = ", NB_PARES)
Fin
En el procesamiento de las tablas, es preferible el bucle Para porque el conjunto de las celdas se utiliza a menudo o
se analiza.
Cuando los elementos de una tabla son ellos mismos tablas, se habla de tabla de varias dimensiones.
A nivel de la declaración de este tipo de tabla, hay que declarar los límites del índice para cada una de las
dimensiones, lo que no es ya una sorpresa:
Tipo IDENTIFICADOR(INF1: SUP1, ..., INFi: SUPi, ..., INFn: SUPn)
Para acceder a las diferentes celdas de una tabla de varias dimensiones, hay que indicar un valor de índice para cada
una de ellas. A modo de ejemplo, para una tabla de dos dimensiones (tabla de líneas divididas en columnas como una
matriz 2D en Microsoft Excel), el primer índice normalmente designa el número de la línea y el segundo el número de
la columna de la celda a la que se hace referencia. Por tanto, la sintaxis es:
IDENTIFICADOR(ÍNDICE1, ..., ÍNDICEi, ..., ÍNDICEn)
1. Ejercicio n.°15: Minihoja de cálculo
Enunciado
Sea la tabla TB de dos dimensiones con cuatro líneas y cinco columnas. Realizar los siguientes procesamientos:
l introducir por el teclado valores en las tres primeras líneas y las cuatro primeras columnas (se conserva la última
línea y la última columna libres, para los totalizadores de líneas y columnas),
l añadir las columnas de última línea y las líneas en última columna.
Corrección
Inicio
Co Declaraciones de las variables Fco
Ent TB(1: 4, 1: 5)
Ent LÍNEA, COLUMNA
Co Inicialización de la tabla TB con ceros Fco
Para LÍNEA De 1 A 4 Hacer
Para COLUMNA De 1 A 5 Hacer
TB(LÍNEA, COLUMNA) < 0
Volverhacer
Volverhacer
Co Inicialización de la tabla TB con los valores leídos Fco
Para LÍNEA De 1 A 3 Hacer
Para COLUMNA De 1 A 4 Hacer
Escribir("TB(", LÍNEA, ",", COLUMNA, ")=")
TB(LÍNEA, COLUMNA) < Leer
Volverhacer
Volverhacer
Co Añadir en columna 5 y línea 4 Fco
Para LÍNEA De 1 A 3 Hacer
Para COLUMNA De 1 A 4 Hacer
Volverhacer
Volverhacer
Fin
La inicialización de las celdas de la tabla a cero al inicio del procesamiento puede ser útil en determinados lenguajes
de programación porque los valores iniciales, de la línea 4 y de la columna 5 en nuestro ejemplo, pueden ser no
nulos.
1. Los objetivos
Estos nuevos mecanismos permiten al programador tratar un problema sin preocuparse, inicialmente, de las reglas
detalladas de los subproblemas. Se trata de herramientas muy similares a las funciones matemáticas.
En programación, un procedimiento o una función, representa un algoritmo que opera con argumentos o
argumentos formales (valores ficticios de alguna manera). La ejecución de este algoritmo se genera con la llamada
del procedimiento o de la función. Los datos de este algoritmo llamado son los argumentos efectivos (que provienen
del algoritmo que llama).
El interés metodológico de estos mecanismos en una primera etapa consiste principalmente en convertir los
subproblemas en procedimientos (o en funciones) y tratar el problema general (o principal) como si estos
subproblemas estuvieran solucionados. En una segunda etapa, se describen estos procedimientos o funciones. Otro
interés consiste en el hecho de que, si el mismo subproblema se debe resolver varias veces con argumentos
efectivos diferentes, el uso de un procedimiento o función permite una mejor legibilidad del algoritmo.
2. Los procedimientos
Comencemos el estudio de este mecanismo con la sintaxis de la declaración:
Procedimiento NOMBRE_PROCEDIMIENTO([Tipo1 IDFO1, ..., Tipoi IDFOi])
Cuerpo del procedimiento
Fin_procedimiento
En esta declaración:
l NOMBRE_PROCEDIMIENTO es un nombre elegido libremente por el programador.
l IDFOi es el nombre del enésimo argumento formal del procedimiento.
l Tipoi es el tipo del enésimo argumento formal del procedimiento.
l El procedimiento no devuelve valores a menos que intervenga sobre las variables (accesibilidad) globales.
l Procedimiento y Fin_procedimiento son palabras reservadas.
La llamada de un procedimiento desde otro o desde el algoritmo principal se hace respetando el siguiente esquema:
NOMBRE_PROCEDIMIENTO(IDEF1, IDEFi, ..., IDEFn)
con:
l NOMBRE_PROCEDIMIENTO es un nombre elegido libremente por el programador,
l IDEFi es el nombre del enésimo argumento efectivo.
3. Ejercicio n.°16: Llamada de un procedimiento con paso de argumentos
Enunciado
Corrección
Inicio
Co Uso de un procedimiento que muestra el doble de una pareja de valores Fco
Co Procedimiento DOBLE Fco
Procedimiento DOBLE(Ent X, Ent Y)
X < X * 2
Y < Y * 2
Escribir("El VALOR DOBLADO es (", X, ",", Y, ")")
Fin_procedimiento
Co Procesamiento que llama Fco
Ent A, B, C, D
Escribir("Programa que dobla los valores de una dupla")
Escribir("Valor 1 de la primera dupla: ")
A < Leer
Escribir("Valor 2 de la primer dupla: ")
B < Leer
DOBLE(A, B)
Escribir("Valor 1 de la segunda dupla: ")
C < Leer
Escribir("Valor 2 de la segunda dupla: ")
D < Leer
DOBLE(C, D)
Fin
En la corrección que se presenta, en realidad se introducirán dos duplas de números por el teclado (A y B y después
C y D), para mostrar la reutilización del procedimiento DOBLE.
Las variables A y B (después C y D) son cualificadas con argumentos efectivos. Durante la llamada del procedimiento
DOBLE, al argumento efectivo A se le asigna el argumento formal X, y al argumento efectivo B, el argumento formal
Y. Después, el procedimiento DOBLE realiza un doblado de los valores que se pasan como argumentos y muestra los
resultados. Es necesario observar que no hay retorno de valores con destino el procedimiento que llama. Los
valores A y B conservarán sus valores iniciales. No es posible tampoco que el procedimiento DOBLE actúe
directamente sobre las variables A y B (e incluso C y D).
En un paso de argumentos entre un procedimiento que llama (o un algoritmo principal) y un procedimiento llamado,
hay que considerar algunas reglas:
l Los argumentos efectivos (si hay varios) se deben separar por comas a nivel de la llamada.
l El argumento o los argumentos formales se deben declarar dentro de los paréntesis que siguen al nombre de la
función (o del procedimiento) llamado.
l Los argumentos formales (si hay varios) se deben separar por comas.
l Cada argumento efectivo corresponde a un argumento formal y los dos deben ser del mismo tipo.
Es posible pasar valores de tipos diferentes entre un procedimiento y otro (o una función).
La diferencia esencial entre los procedimientos vistos anteriormente y las funciones es que, en el caso de las
funciones, se envía un valor de vuelta al procedimiento que llama (o al algoritmo principal).
La sintaxis de la declaración es muy parecida a la de un procedimiento:
Función NOMBRE_FUNCIÓN([Tipo1 IDFO1, ..., Tipoi IDFOi]) Tipo_resultado
Cuerpo de la función (conteniendo Devolver expresión)
Fin_función
En esta declaración:
l La llamada a la función proporciona un valor del tipo Tipo_resultado indicado (Entero, Real, Bool, Carácter).
l NOMBRE_FUNCIÓN es un nombre elegido libremente por el programador.
l IDFOi es el nombre del enésimo argumento formal de la función.
l Tipoi es el tipo del enésimo argumento formal de la función.
l La función debe devolver una expresión (de tipo Tipo_resultado) en formato Devolver expresión.
l Función, Resultado, Devolver y Fin_función son palabras reservadas.
La llamada a una función desde otro procedimiento o desde el algoritmo principal se hace respetando el siguiente
esquema:
RESULTADO = NOMBRE_FUNCIÓN (IDEF1, IDEFi, ..., IDEFn)
con:
l NOMBRE_FUNCIÓN es un nombre elegido libremente por el programador,
l IDEFi es el nombre del enésimo argumento efectivo,
l RESULTADO es el nombre de la variable que recupera la respuesta proporcionada por la función.
5. Ejercicio n.°17: Llamada de una función con paso de argumentos
Enunciado
Uso de una función de cálculo del máximo de dos valores introducidos por el teclado y pasados como argumentos
Corrección
Inicio
Co Uso de una función de cálculo del máximo de dos valores introducidos por el teclado y pasados como
argumentos Fco
Co Función de cálculo del máximo Fco
Función MAXI(Ent X, Ent Y) Ent
Si X > Y
Devolver X
En caso contrario
Devolver Y
Finsi
Fin_función
Co Procesamiento que llama Fco
Ent A, B, C, D, E
Escribir("Cálculo del máximo de 2 números")
Escribir("Valor 1: ")
A < Leer
Escribir("Valor 2: ")
B < Leer
Escribir("El + grande es ", MAXI(A, B))
Escribir("Valor 3: ")
C < Leer
Escribir("Valor 4: ")
D < Leer
E < MAXI(C, D)
Escribir("El + grande es ", E)
Fin
En esta corrección, una misma función MAXI se llama dos veces con argumentos efectivos diferentes (A y B, después
C y D).
Las reglas de paso de argumentos entre un procedimiento que llama (o un algoritmo principal) y una función
llamada son idénticas a las vistas anteriormente en el marco de una llamada de procedimiento.
En los capítulos siguientes, se propone un aprendizaje progresivo del lenguaje JavaScript, con un enfoque
pedagógico. En ningún momento se tratará de ser exhaustivo. Por el contrario, se intentará conseguir que usted
descubra paso a paso JavaScript, retomando en particular los algoritmos desarrollados en los capítulos anteriores.
Hubiera sido posible, para cada uno de los algoritmos que se han estudiado, proporcionar inmediatamente el código
JavaScript. La elección que se ha tomado es presentar el algoritmo y el código JavaScript en capítulos diferentes del
libro. Este enfoque ofrece una ventaja sustancial, ya que sensibiliza al lector respecto a la importancia del análisis de
un problema, centrando el esfuerzo en conseguir un algoritmo de calidad, claro, fácil de interpretar y fiable, antes de
traducir este algoritmo a un lenguaje de programación, sea el que sea.
Después de la presentación del lenguaje JavaScript (hasta el capítulo Procedimientos y funciones), se estudia el
enfoque llamado "Programación orientada a objetos" de JavaScript (en el capítulo Enfoque orientado a objetos en
JavaScript) y después veremos los principales objetos "nativos" (que no tendrá que desarrollar usted mismo), así
como las propiedades y métodos asociados (capítulo Principales objetos en JavaScript).
El libro termina con capítulos más técnicos, enumerados en la tabla de contenidos, fundamentalmente el estudio de
los formularios, del modelo DOM (Document Object Model), la persistencia de datos, la geolocalización, el diseño, los
gráficos de gestión, la generación de documentos PDF y los códigos QR.
Para facilitar la localización de los ejercicios de JavaScript, se conservará la numeración que se ha visto en el capítulo
Desarrollo a partir de algoritmos.
1. Ejercicio n.°2: Superficies de círculos
Para empezar suavemente nuestro aprendizaje, retomemos el algoritmo del ejercicio n.°2 (Superficies de círculos),
que hemos visto en el capítulo Desarrollo a partir de algoritmos. Excepcionalmente, para este primer ejercicio, se
recordará el algoritmo.
Enunciado
Calcular (y mostrar en pantalla) la superficie de dos círculos de radios predeterminados (5,5 metros y 3,5 metros,
por ejemplo), así como la diferencia entre estas dos superficies
Corrección en lenguaje descriptivo de algoritmia
Inicio
Real RADIO1, RADIO2, PI, SUPERFICIE1, SUPERFICIE2, DIFERENCIA
RADIO1 < 5.5
RADIO2 < 3.5
PI < 3.14
SUPERFICIE1 < PI * RADIO1 * RADIO1
SUPERFICIE2 < PI * RADIO2 * RADIO2
DIFERENCIA < SUPERFICIE1 SUPERFICIE2
Escribir("Superficie 1 = ", SUPERFICIE1, Alineación, "Superficie 2 = ", SUPERFICIE2, Alineación, "Diferencia
= ", DIFERENCIA)
Fin
Corrección en JavaScript
<!--
NOMBRE DEL SCRIPT: Cap3_2.htm
REALIZACIÓN INFORMÁTICA: Christian VIGOUROUX
FECHA DE CREACIÓN: 01/01/2014
FECHA DE ÚLTIMA MODIFICACIÓN: 01/01/2014
OBJETIVO: Calcular (y mostrar) la superficie de dos círculos de radios
predeterminados (5,5 metros y 3,5 metros, por ejemplo)
y las diferencias entre sus dos superficies
-->
</head>
/* Cálculos */
superficie1 = pi * radio1 * radio1;
superficie2 = pi * radio2 * radio2;
diferencia = superficie1 - superficie2;
</script>
</body>
</html>
Comentarios del código JavaScript
l Caso 1: dentro de las etiquetas <script> ... </script> en la sección <body> ... </body> del
documento HTML principal, como en el caso del script comentado.
l Caso 2: dentro de las etiquetas <script> ... </script> en la sección <head> ... </head> del
documento HTML principal. Este será el caso de las funciones personales que desarrollaremos más adelante.
l Caso 3: en un archivo externo (de extensión .js), para las funciones que queremos poder llamar desde varios
scripts Web.
De momento, no insistimos en los casos 2 y 3. Estos modos de implementación del código JavaScript se verán desde
el punto de vista sintáctico, más adelante en este libro. También se presentarán ejemplos.
El código HTML DOCTYPE siguiente:
es la declaración del tipo de documento. Sirve para indicar al navegador el tipo de código HTML en el que está
escrito el script (página) HTML; puede ser HTML3.2, HTML4, XHTML...
En su formulación detallada, esta directiva tiene la siguiente estructura:
donde:
l type_HTML es el identificador de la versión de HTML utilizada,
l address_DTD es la URL de un Document Type Definition (DTD), es decir, de un documento que indica las
propiedades de cada elemento (etiquetas y atributos) para este tipo de código HTML.
La secuencia HTML siguiente es un ejemplo típico de comentarios:
Recordemos que los comentarios son explicaciones integradas en el script, que no se interpretarán por el
navegador. Estas líneas son, en cambio, fundamentales para entender las diferentes secuencias de código HTML del
script. En este caso, el objetivo del comentario es recordar el procesamiento que realiza el script.
Detengámonos en la etiqueta meta HTTP-equiv:
La sintaxis general de esta etiqueta es:
Esta etiqueta va a permitir:
l indicar el encoding de la página Web a través de la palabra clave Content-Type. Por ejemplo, para un encoding
UTF-8:
l indicar que no hay que guardar la página en la caché del navegador (la página no se guardará en los archivos
temporales del usuario), con la palabra clave pragma:
l indicar que, pasada una fecha de expiración, la página ya no estará disponible, con la palabra clave expires:
l requerir la actualización de la página cada n segundos, con la palabra clave refresh. Por ejemplo, para una
actualización cada 15 segundos:
l dirigir al internauta a otra página después de n segundos, con la palabra clave refresh. Por ejemplo, se obtendrá
una redirección a la página yahoo.es, después de la visualización del script actual, durante dos segundos:
Ahora centramos nuestra atención en nuestro código JavaScript. El script empieza con una directiva <script>
(precedida de un comentario expresado en HTML):
El comando alert (como veremos más adelante, se trata de un método) muestra un mensaje con el título del
ejercicio, en forma de ventana "pop up":
alert("Ejercicio Cap3_2");
Sin duda, habrá observado que cada instrucción de JavaScript termina con un punto y coma.
Después se declara un conjunto de variables. Estas variables corresponden, evidentemente, a las que se han visto
en el algoritmo. No hay razones fundamentales para modificar su sintaxis. El resto de los cambios de
mayúsculas/minúsculas se pueden prever para respetar una normalización de nombres de variables, métodos...
(normalización camelCase, por ejemplo).
Aquí, las declaraciones se hacen en una sola línea, con el prefijo var, que no es una declaración de tipo. A priori, en
JavaScript el tipo no existe, sino que las variables se asocian a un tipo en el momento en que se les asigna un
contenido.
Para las inicializaciones, se usa el signo =. Para el primer radio, esto resulta:
radio1 = 5.5;
El signo de asignación = utilizado aquí no se debe confundir con el signo ==, que servirá para realizar
comparaciones en igualdad.
Los cálculos no presentan dificultades particulares. Por ejemplo, para la primera superficie, el código es:
A continuación, para terminar, pasamos a la visualización del resultado. El comando document.write permite
mostrar el resultado de los cálculos en la ventana del navegador. A título de ejemplo, para la primera superficie,
esto se hace:
document.write es una sintaxis orientada a objetos, en la que el método write se aplica a un objeto
document. Volveremos a tratar la programación orientada a objetos (POO) en el capítulo Enfoque orientado a
objetos en JavaScript.
La cadena <br/> muestra que es posible integrar etiquetas HTML en una visualización de JavaScript. Aquí
<br /> provoca un cambio de línea antes de la siguiente visualización.
La visualización de la diferencia entre las dos superficies queda asegurada con el método alert, que ya
conocemos:
Los elementos que muestra el método alert se organizan como con el método document.write.
La sección escrita en JavaScript termina con </script>:
</script>
La siguiente secuencia (no comentada en el detalle aquí) permitirá al usuario visualizar el código HTML/JavaScript de
la página con un clic en un enlace de hipertexto:
2. Ejercicio n.°3: Superficie y volumen de una esfera
Enunciado
Calcular y mostrar la superficie y el volumen de una esfera cuyo radio se introduce por el teclado.
La novedad respecto al ejercicio anterior (Ejercicio n.°2), es la entrada del radio por el teclado.
Corrección en JavaScript
La corrección se reproduce completamente (no será el caso en el resto de los ejemplos).
<!--
NOMBRE DEL SCRIPT: Cap3_3.htm
<title>Cap3_3</title>
</head>
/* Cálculos */
superficie = 4 * pi * radio * radio;
volumen = superficie * radio / 3;
</script>
</body>
</html>
Comentarios del código JavaScript
A nivel de inicializaciones, la variable pi toma el valor 3,14 (valor aproximado) y la variable radio se inicializa
introduciendo su valor por el teclado (método prompt). El único argumento de este método es una etiqueta.
3. Ejercicio n.°4: Número de letras de una palabra
Enunciado
Escribir un algoritmo que permita introducir por el teclado un nombre y mostrar el número de letras
Corrección (parcial) en JavaScript
Comentarios del código JavaScript
Nos anticipamos al enfoque "Programación orientada a objetos" (POO) en JavaScript. La variable nombre es de tipo
String. En este tipo de objeto, es posible utilizar métodos específicos o acceder a los valores de propiedades
como length (número de caracteres).
El valor de la propiedad length aquí se muestra directamente con la llamada al método document.write.
También hubiera sido posible declarar una variable adicional en memoria, como longitudNombre por ejemplo, y
asignarle el valor de nombre.length, antes también de mostrar su valor con document.write.
Enunciado
Escribir un algoritmo que permita la extracción de las iniciales de una persona, cuyo apellido y nombre se
introducirán por el teclado (ejemplo: ÁS para Ángel Sánchez)
Corrección (parcial) en JavaScript
Comentarios del código JavaScript
Aunque habíamos utilizado la propiedad length en el ejemplo anterior, aquí usamos el método charAt para
determinar la inicial del apellido y el método substring para la inicial del nombre.
El método substring necesita dos argumentos: el primero indica la posición del primer carácter que se debe
extraer (0, como para el método charAt) y el segundo el número de caracteres que hay que extraer ( 1 para una
sola letra, es decir, la inicial).
Por tanto, el método substring puede sustituir al método charAt en todos los casos.
La estructura condicional en JavaScript es muy parecida sintácticamente a la que se ha visto con anterioridad en
lenguaje descriptivo de algoritmia.
Por supuesto, de manera clásica, el bloque de instrucciones que se ha de ejecutar en caso de que la condición sea
verdadera queda delimitado por llaves ({}). También es posible prever una secuencia de instrucciones alternativa con
la palabra clave else. Esta secuencia también se encerrará entre llaves.
El lenguaje JavaScript es muy permisivo respecto a la ubicación de estas llaves. De esta manera, encontrará scripts
con las siguientes construcciones:
if (condición)
{
Acciones_1;
}
else
{
Acciones_2;
}
o
if (condición) {
Acciones_1;
}
else {
Acciones_2;
}
o
donde:
l condición representa una comparación que genera un resultado booleano true o false,
l Acciones_1 y Acciones_2 representan secuencias de instrucciones (en general en varias líneas).
Observe que, para realizar una comprobación de comparación de igualdad, el operador es el doble igual (==); no
confundir con el igual sencillo (=), que sirve para realizar comparaciones.
En las comprobaciones de comparación con constantes, es mejor, por ejemplo:
if (5 == contador)
{
Acciones_1;
que
if (contador == 5)
{
Acciones_1;
}
else
{
Acciones_2;
}
ya que confundir = = con = es más fácil de detectar en el primer caso, porque JavaScript devuelve un error. En el
segundo caso (si pone = en lugar de ==) la secuencia Acciones_1 se ejecutará siempre, porque la evaluación de
contador = 5 siempre dará true (JavaScript estima que la asignación tiene éxito).
1. Ejercicio n.°6: Polinomio de segundo grado
Enunciado
Calcular las raíces de un polinomio de segundo grado Ax2+Bx+C (con A<>0 en valor absoluto, aunque esta prueba
no se realiza aquí). Los valores A, B y C se introducirán por el teclado
Corrección (parcial) en JavaScript
Comentarios del código JavaScript
Observe que ha sido necesario anidar dos estructuras condicionales para tratar el problema. Es posible no anidar
las estructuras (equivalente a tres Si ... Finsi sucesivos a nivel de algoritmia), pero esta solución no sería óptima.
Observe también el sentido particular aportado a nivel de la alineación de las llaves y a nivel de la indentación de
los bloques de instrucciones.
2. Ejercicio n.°8: Impresión de la etiqueta de un mes
Enunciado
Imprimir en letras, el mes correspondiente a un número dado por el teclado (comprendido entre 1 y 12). El control
de la entrada de datos no se realiza.
Corrección (parcial) en JavaScript
Comentarios del código JavaScript
En lugar de anidar, como en el ejercicio anterior, las estructuras condicionales (algo que resulta pesado de escribir
en nuestro caso), aquí se utiliza la estructura switch.
Observe a nivel de la entrada de datos del número del mes en la variable ’mes’ (no tipado a nivel de su declaración)
que se necesita una conversión con el método parseInt. Una vez que se realiza la entrada de datos y la
conversión, la variable mes será de tipo entero en el resto del procesamiento.
La variable mes se comprueba con la estructura condicional switch. En caso de que la variable mes valga 1, se
visualiza "Enero" y así sucesivamente.
En caso de que haya una entrada de datos errónea en el número de mes, entonces se ejecuta la instrucción
integrada en el caso default.
Observemos también el papel primordial de la instrucción break. En su ausencia al final de cada uno de los casos,
tan pronto como la condición se verifica, se ejecuta el procesamiento asociado, pero también el resto de los
procesamientos siguientes (incluso si la condición no se respeta para estos procesamientos). Por ejemplo, la
entrada de datos del valor 5 como número de mes generaría la visualización de Mayo, Junio, Julio, ...,
Diciembre.
En el marco del capítulo Desarrollo a partir de algoritmos, hemos estudiado cinco tipos de bucles que permiten tratar
todos los casos de procesamientos iterativos:
l Bucle Hasta que, con una comprobación de la condición al inicio de la iteración.
l Bucle Mientras que, con una comprobación de la condición al inicio de la iteración.
l Bucle Hasta que, con una comprobación de la condición al final de la iteración.
l Bucle Mientras que, con una comprobación de la condición al final de la iteración.
l Bucle Para.
Estas estructuras iterativas no se implementan en todos los lenguajes de programación. Por ejemplo, es posible
pasar del bucle Hasta que al bucle Mientras que, modificando la condición.
Por el contrario, el bucle Para prácticamente siempre está presente en los lenguajes. Su particularidad es que solo se
usa cuando el número de iteraciones es conocido al inicio del procesamiento. Siempre es posible recurrir a un bucle
Mientras que (o Hasta que).
En JavaScript, la elección de las estructuras iterativas se reduce a:
l while: bucle Mientras que, con una comprobación de la condición al inicio de la iteración,
l do ... while: bucle Mientras que, con una comprobación de la condición al final de la iteración,
l for: bucle Para.
1. Sintaxis
El bucle while permite traducir una lógica de Mientras que, con una comprobación inicial de estructura. La sintaxis
es la siguiente:
while(condición)
{
secuencia de código
}
Con el bucle while se ejecuta una secuencia de código mientras la condición entre paréntesis sea verdadera.
Por supuesto, con esta iteración es necesario que el estado de la condición pueda evolucionar a lo largo de la
secuencia del código integrado en las llaves. También es necesario estar muy atento al hecho de que la condición se
pueda evaluar la primera vez que se pasa por ella. Se trata de un motivo de funcionamiento erróneo frecuente. Muy
a menudo, la condición también se realiza sobre el estado de una variable de tipo contador. Por supuesto, para que
el contador pueda alcanzar un valor límite, hay que modificarlo durante la secuencia de código (incremento o
decremento).
Para terminar, observe en los scripts de este libro y en muchos de los ejemplos disponibles en Internet la siguiente
sintaxis alternativa (que ya habíamos mencionado para la estructura condicional if):
while(condición) {
secuencia de código
}
2. Ejercicio n.°9: Media de 10 números que se introducirán por el teclado
Enunciado
Calcular y mostrar la media de 10 números leídos por el teclado
Siendo rigurosos, este ejercicio se podría realizar con un bucle Para porque el número de iteraciones (10) es
conocido al inicio del procesamiento.
Corrección (parcial) en JavaScript
/* Inicializaciones */
cnt = 1;
suma = 0.0;
/* Bucle de procesamiento */
while (cnt<=10)
Comentarios del código JavaScript
El script no presenta dificultades particulares de interpretación.
Conviene prestar atención a la implementación del bucle while en JavaScript. La media se divide por 10 al final del
procesamiento. Una división por el contador del bucle cnt habría dado un resultado no satisfactorio porque la
división se hubiera hecho por 11.
No olvide realizar las conversiones en el bucle a tipo real para la variable nblu (con el método parseFloat para
los números reales) porque la variable nblu, aunque se haya declarado al inicio de script, no tiene tipo explícito.
Puede que haya observado la presencia de un espacio entre la palabra clave while y la condición; este espacio es
opcional y permite aligerar la sintaxis.
Enunciado
Calcular y mostrar la media de n números reales introducidos por el teclado (la lista termina con un cero).
Aquí nos enfrentamos a un problema que no es posible solucionar con una estructura iterativa de tipo Para ( for en
JavaScript).
Veamos cómo realizar este cálculo con un while.
Corrección (parcial) en JavaScript
/* Inicializaciones */
cnt = 1;
suma = 0.0;
/* Bucle de procesamiento */
while (nblu != 0)
{
suma = suma + parseFloat(nblu);
nblu = parseFloat(prompt("Número (0 para terminar): "));
cnt = cnt + 1;
}
Comentarios del código JavaScript
Para que la condición sea evaluable en la primera pasada de nblu != 0, es necesario haber introducido un
número por el teclado antes del bucle while. No hay que olvidar, en la secuencia de código integrado en el bucle,
prever un segundo prompt para que sea posible la lectura de los siguientes números.
En cuanto a visualización, hay que prever una comprobación para aislar el caso particular de una secuencia de cifras
que solo contenga el "marcador de fin de lista 0". En este caso, sobre todo hay que evitar la división por cero. En
realidad, en JavaScript, no hay error del navegador, sino que el valor que se muestra sería NaN (Not a Number).
Algunas notas en relación con las condiciones:
l Para indicar diferencia, el operador es != (en lugar de <>, que hemos visto en el capítulo Desarrollo a partir de
algoritmos).
l Para comparar con 1 en la visualización del resultado, hay que prever un doble igual (= = ). El signo igual (= ) en
JavaScript se reserva a la asignación.
1. Sintaxis
El bucle do while permite traducir una lógica de Mientras que, con una comprobación al final de la estructura. La
sintaxis es la siguiente:
do
{
secuencia de código
} while(condición)
Con el bucle do while, se ejecuta una secuencia de código mientras la condición entre paréntesis sea verdadera.
Hay una diferencia notable respecto al bucle while. Aquí la secuencia de código se ejecuta al menos una vez,
porque la comprobación de la condición se realiza al terminar la primera vuelta del bucle.
Enunciado
Calcular y mostrar la media de n números reales introducidos por el teclado (la lista termina con un cero)
Corrección (parcial) en JavaScript
/* Inicializaciones */
cnt = 0;
suma = 0.0;
/* Bucle de procesamiento */
do
{
nblu = parseFloat(prompt("Número (0 para terminar): "));
cnt = cnt + 1;
suma = suma + parseFloat(nblu);
} while (nblu != 0)
Comentarios del código JavaScript
Observe también que la inicialización del valor del contador cnt se hace con un cero.
Para terminar, como sucedía anteriormente, se añade el cero final (pero esto no tiene implicaciones en una adición)
y se contabiliza en la cantidad de números que forman parte de la lista. Por tanto, es necesario realizar una división
por contador-1 a nivel del cálculo de la media.
1. Sintaxis
Recordemos simplemente que este bucle solo se utiliza cuando el número de iteraciones que se van a realizar se
conoce al inicio del procesamiento.
La sintaxis es la siguiente:
No insistimos en el funcionamiento de este tipo de bucle porque ya se visto ampliamente en el capítulo Desarrollo a
partir de algoritmos.
Evidentemente la gestión de la progresión del contador está a cargo de la estructura for. Por tanto, no es
necesario prever un valor inicial para el contador antes del bucle (solo se hace la declaración del contador). El
valor inicial, el valor final y el paso de incremento/decremento del contador se tienen en cuenta por el bucle. No
hay que cambiar el valor del contador en la secuencia de código.
Enunciado
Calcular la media de 10 números que se introducen por el teclado, con un bucle for.
Este ejercicio ya se ha realizado con antelación con un bucle while (Ejercicio n.°9). Recordemos que siempre es
posible cambiar un bucle for por un bucle while (aunque no obligatoriamente a la inversa).
Corrección (parcial) en JavaScript
/* Inicializaciones */
suma = 0.0;
/* Bucle de procesamiento */
for (cnt=1; cnt<=10; cnt++)
{
nblu = parseFloat(prompt("Número n°" + cnt));
suma = suma + parseFloat(nblu);
}
Comentarios del código JavaScript
La declaración del contador cnt se podría haber omitido. Sin embargo, es preferible hacerla explícitamente, como
aquí (en determinados lenguajes de programación, este olvido generaría un error).
Observe que, a nivel del cálculo de la media, se ha mantenido un enfoque prudente, la división de la suma por 10.
Podría haberle tentado hacer una división por cnt, pensando que el bucle Para que termina con un valor de cnt de
10. Este sería un grave error porque en JavaScript, en la salida de este bucle, el contador vale 11.
3. Ejercicio n.°13: Contar el número de vocales en una palabra
Enunciado
Contar el número de vocales de una palabra introducida por el teclado
En el capítulo Desarrollo a partir de algoritmos de este libro, para este ejercicio habíamos introducido la función
Longitud(CADENA), para determinar el número de caracteres de la palabra introducida y la función Sub_cadena
(CADENA, POSICION_INICIO, [POSICION_FIN]), para localizar las letras sucesivas en la palabra. Van a ser
necesarias funciones equivalentes en JavaScript.
Corrección (parcial) en JavaScript
/* Introducción de la palabra */
Palabra = prompt("Palabra:");
Comentarios del código JavaScript
Ya lo habíamos visto en la versión "algoritmia" de este ejercicio; es mejor convertir a mayúsculas la palabra
introducida por el teclado (variable palabra) como sigue:
No insistimos en la estructura for en sí misma porque ya domina su sintaxis desde el ejercicio anterior.
Para evitar una batería de if anidados con objeto de evaluar si las letras sucesivas son vocales, se ha mantenido
el principio del uso de un switch (más elegante). Este switch tiene como condición la evaluación del valor
devuelto por el método palabra.charAt, que permite extraer las letras una por una. También habrá observado
la particularidad ya mencionada de la numeración de las letras en una cadena a partir de cero.
En el capítulo Desarrollo a partir de algoritmos, hemos visto de pasada el potencial de las tablas de dimensión única y
de dimensiones múltiples. Veamos cómo se gestionan en JavaScript.
1. Sintaxis
En JavaScript, una tabla de dimensión única es una variable en memoria "compuesta", en la que va a ser posible
almacenar varios datos independientes, de tipos diferentes, con una indexación de cada uno de los valores con un
número (o índice).
Por tanto, el acceso a cada dato de la tabla se hará con este valor de índice.
Una particularidad respecto a este índice es que su valor para la primera celda de la tabla es 0.
El lenguaje JavaScript proporciona varias maneras de crear una tabla:
l la sintaxis literal,
l la sintaxis llamada "Programación orientada a objetos".
Con una sintaxis literal, la declaración de una tabla de nombre tabSemana de siete celdas, que contiene las
etiquetas de los días de una semana, se hace como sigue:
Observe que la declaración está acompañada de la inicialización de cada una de las celdas de la tabla tabSemana
(de la celda de índice 0 a la celda de índice 6).
Con una sintaxis de "Programación orientada a objetos", tendríamos:
Hubiéramos podido declarar la tabla tabSemana sin asignarle valores. Se puede considerar asignaciones
posteriores, como por ejemplo para el Lunes:
tabSemana[0] = "Lunes";
Lo que es verdaderamente particular en la gestión de las tablas en JavaScript es la extrema flexibilidad:
l sin dimensionamiento a priori (siempre es posible extender el tamaño de la tabla en función de las necesidades),
l posibilidad de mezclar en una misma tabla datos de tipos diferentes,
l posibilidad de utilizar tablas asociativas (tablas cuyos índices se sustituyen por valores textuales).
En un procesamiento, para acceder al contenido de un valor de tabla asociado a una posición de índice particular, la
Es necesario recordar siempre que la numeración de los índices empieza en cero.
Para terminar, debe saber que JavaScript ofrece muchos métodos que se aplican en las tablas ( Array). Con estos
métodos puede fácilmente insertar, eliminar y encontrar elementos en una tabla. También existen métodos de
ordenación (sort, reverse) para clasificar fácilmente los valores contenidos en una tabla, sin tener que recurrir a
la pesada escritura de un algoritmo de ordenación.
2. Ejercicio n.°14: Contar los números pares en una tabla
Enunciado
Determinar la cantidad de números pares en una tabla (entrada de datos inicial de valores por el teclado).
Corrección (parcial) en JavaScript
/* Inicializaciones */
nbPares = 0;
for (i=1; i<=5; i++)
{
tabla[i] = parseInt(prompt("tabla[" + i +"]: "));
}
Comentarios del código JavaScript
Puede que haya observado que, en este script, la celda con índice 0 no se ha utilizado (la numeración del bucle for
empieza en 1). Esta elección hace más comprensible el algoritmo.
Es frecuente que necesitemos una tabla de dimensiones múltiples para gestionar problemas, fundamentalmente en
matemáticas, estadística...
JavaScript ofrece esta posibilidad.
1. Sintaxis
Como para las tablas de dimensión única, JavaScript permite declarar las tablas de dimensiones múltiples de varias
maneras:
l con una sintaxis literal,
l con una sintaxis llamada "Programación orientada a objetos".
Con una sintaxis llamada "Programación orientada a objetos" (incluso llamada JSON JavaScript Object Notation), la
declaración de una tabla de nombre tabMatriz de dos líneas, divididas en cuatro columnas con inicialización, se
hace como sigue:
2. Ejercicio n.°15: Minihoja de cálculo
Enunciado
Sea la tabla tb de dos dimensiones, con cuatro líneas y cinco columnas. Realizar los procesamientos siguientes:
l introducir por teclado valores en las tres primeras líneas y las cuatro primeras columnas (se conservan la última línea
y la última columna libres para los totalizadores de líneas y columnas),
l añadir columnas en la última línea y líneas en la última columna.
/* Inicialización de la tabla tb */
valor = 1;
for (numLinea=1; numLinea<=3; numLinea++)
{
for (numColumna=1; numColumna<=4; numColumna++)
{
tb[numLinea][numColumna] = valor;
valor = valor + 1;
}
}
Comentarios del código JavaScript
En primer lugar, la tabla tb se declara como una tabla de una sola dimensión, con cinco celdas, implícitamente
numeradas de 0 a 4, como sigue:
Observe que la línea de número cero no se utilizará en adelante. Esta elección se ha hecho porque el uso posterior
de esta línea no sería muy intuitiva.
Luego, las líneas de esta tabla se dividen en columnas, como se ve a continuación:
De hecho, se declaran seis columnas (numeradas de 0 a 5) y la columna número cero se ignora.
La inicialización de las "celdas" de la tabla tb (únicamente las líneas 1 a 3 y las columnas 1 a 4) se hace con la
siguiente notación:
tb[numLinea][numColumna] = valor;
El valor asignado es 1, en progresión a partir de 1 (por tanto, de 1 a 12). La entrada de datos se hubiera podido
realizar a partir de una entrada de datos por teclado.
Los procesamientos siguientes (puesta a cero de la línea n.°4 y de la columna n.°5), no merecen comentarios
particulares.
Los totales en la línea n.°4, en la columna n.°5 y en la celda [4][5] también se hacen con un conjunto de bucles for
anidados. La tabla general es naturalmente de 78, dando por hecho que la técnica de llenado de la hoja de cálculo
se mantiene.
Recordemos brevemente el interés de los procedimientos en programación (puede volver al capítulo Desarrollo a
partir de algoritmos, para más explicaciones). Querer codificar en JavaScript procesamientos demasiado complejos,
utilizando un número importante de variables y objetos e implicando, por ejemplo, a bucles y estructuras
condicionales anidadas, puede ser un freno importante para el mantenimiento del script. Esto es incluso más cierto
cuando el código está mal organizado (ausencia de comentarios, indentaciones aleatorias, nombres de variables y
objetos poco significativos, etc.).
Otro aspecto importante para codificar con procedimientos es la posible reutilización de estos procedimientos en
contextos diferentes. Será posible pasar argumentos a estos procedimientos. Si estas secuencias de código llamadas
desde un procesamiento principal devuelven un valor, hablamos en este caso de funciones. Esta factorización reduce
la longitud global del código fuente y permite, sobre todo, aislar (e incluir en un script físicamente diferente) una
secuencia de instrucciones, para la que no tendremos más preguntas que hacer respecto a su funcionamiento. Por
tanto, estos procedimientos (o funciones) se podrán considerar como piezas de software utilizables en la construcción
de una arquitectura de software.
1. Sintaxis
donde
después de la palabra clave function, hay que poner un nombre de procedimiento, seguido de una serie de
argumentos formales entre paréntesis. En caso de argumentos múltiples, conviene separarlos por comas.
Es sorprendente que se utilice la palabra clave function cuando en este párrafo hablamos de procedimiento.
Veremos más adelante que function es una palabra clave que sirve indistintamente a los procedimientos y a las
funciones en JavaScript.
La particularidad, ya mencionada, es que un procedimiento no devuelve un valor.
La llamada del procedimiento se hace con la siguiente sintaxis:
2. Ejercicio n.°16: Llamada de un procedimiento con argumentos
Enunciado
Corrección (parcial) en JavaScript
/* Procedimiento de doblado */
function doblado(x, y)
{
/* Doblado */
x = x * 2;
y = y * 2;
/* Visualización de la dupla de valores después del doblado */
document.write("La dupla doblada es (" + x + ", " + y +")<br />");
}
Comentarios del código JavaScript
Si es posible, el procedimiento doblado se coloca antes de las llamadas ( doblado(a, b); doblado (c,
d);), pero no es obligatorio.
En primer lugar, se introducen dos valores enteros a y b por el teclado. Estos dos valores serán los argumentos
efectivos del procedimiento doblado. Los valores de a y de b se asignan respectivamente a los argumentos x e y
(que de esta manera también se consideran como enteros). A continuación, el procedimiento garantiza el doblado
de cada uno de los valores y muestra la dupla de los valores doblados.
Caso particular de procedimiento sin argumentos
Los procedimientos también se utilizan sin argumentos, como se muestra en el siguiente script:
/* Procedimiento Hola_mundo */
function Hola_mundo()
Los paréntesis después del nombre del procedimiento también son necesarios cuando no hay argumentos.
1. Sintaxis
Una función es un procedimiento que devuelve un valor a la secuencia de código que llama.
El resultado devuelto se debe asignar a una variable o mostrar a través del método alert o document.write.
o
o
A nivel de la función, devolver un valor se hace como sigue:
/* Valor de retorno */
return valorDevuelto;
}
2. Ejercicio n.°17: Llamada de una función con argumentos
Enunciado
Uso de una función de cálculo del máximo de dos valores introducidos por teclado y pasados como argumentos.
Corrección (parcial) en JavaScript
Comentarios del código JavaScript
El código de la función maxi es fácil de interpretar. Devolvemos los argumentos efectivos a y b, después c y d, que
alimentan la función que se encarga de determinar el valor máximo. El resultado (x o y según el caso) se devuelve
al código que llama a la instrucción, a través de return. La función no se encarga aquí de la visualización del
máximo. El programa que llama recupera el máximo y se ocupa de esto (uso del método alert o del método
document.write).
Aunque la implementación del modelo de programación orientada a objetos (POO) no esté tan completa en JavaScript
como en C++ o Java, JavaScript ofrece los mecanismos principales gestionados por estos lenguajes.
Recordemos los conceptos más importantes de la POO:
l Encapsulación: reunión de un conjunto de propiedades (parte de tratamiento de datos) y de funciones, también
llamadas métodos (parte de procesamientos), dentro de un objeto tipo (quizás es más correcto hablar de clase), con la
posibilidad de crear (instanciar) objetos a partir de esta clase.
l Herencia: posibilidad de "fabricar" una nueva clase a partir de una clase existente; esta nueva clase hereda las
propiedades y métodos de la clase padre (se pueden añadir nuevas propiedades/métodos a la nueva clase).
l Polimorfismo: un método del mismo nombre asociado a varias clases puede tener comportamientos diferentes para
algunas de estas clases.
JavaScript siempre ha sido una pieza esencial en los desarrollos Web, principalmente para la programación del lado
"cliente", es decir, del lado del navegador. Habitualmente, sin sumergirse de lleno en el lenguaje, los desarrolladores
producen código JavaScript de calidad mediocre, contentándose con adaptar el código fuente recuperado de sitios
Web y manipulando los conceptos POO lo menos posible.
En paralelo, han aparecido un gran número de librerías JavaScript y su uso permite producir aplicaciones de mejor
calidad. El dominio de estas librerías supone tener conocimientos básicos de POO en JavaScript.
Por tanto, el objetivo de la exposición que sigue es presentarle lo que hay que saber sobre este asunto. Los
conceptos se van a explicar a través de una serie de ejemplos.
Algunos lectores que ya tengan una importante experiencia en otros lenguajes POO (PHP 5, Java, C++...) al principio
se pueden sentir incómodos con los aspectos específicos de la POO en JavaScript, la POO por prototipado.
1. Secuencia 1: Declaración de los objetos JavaScript de manera "Inline"
Se trata de la manera más sencilla de declarar un objeto en JavaScript.
El resultado obtenido de la ejecución será el siguiente:
Suma = 15
En este tipo de declaración de objeto, es posible prever la especificación de atributos (propiedades) y también de
métodos.
La palabra clave this sirve para indicar que se está haciendo referencia a los atributos del objeto en sí mismo.
Está claro que con este tipo de declaración no será posible reutilizar este tipo de definición para crear un objeto de
las mismas características (o parecidas). Por tanto, este método se utilizará poco (o nada) porque no permite la
herencia. No se preocupe, porque volveremos sobre esto más en detalle, a lo largo de esta exposición.
2. Secuencia 2: Creación de objetos JavaScript con un constructor
Veamos con un ejemplo el desarrollo que es necesario seguir:
En nuestro ejemplo, se define en primer lugar una función Coche. Integra un atributo booleano que indica que los
coches tienen un motor y un método (función) de nombre avanzar, que mostrará "avanza" cuando se pida, a
partir de un objeto de tipo Coche (se entenderá rápidamente).
Posteriormente, se construye un objeto de nombre simca1100 a partir del constructor Coche (siento que el
término "constructor" pueda ser confuso en un ejemplo basado en coches):
En el ejemplo de la secuencia anterior, habrá observado que las propiedades (atributos) llevan como prefijo la
palabra clave this. Esto es lo que las hace usables desde el exterior (caso de la propiedad tieneMotor). Por el
contrario, por necesidades locales del constructor (cálculo interno), puede declarar variables no expuestas, usando
como prefijo la palabra clave var.
Veamos un ejemplo concreto:
Se usa una variable local numeroRuedas en el constructor con el prefijo var. Esto solo es accesible, como estaba
previsto, desde dentro del constructor, como se muestra en la ejecución de este script:
4. Secuencia 4: Paso de argumento(s) a un constructor
En el ejemplo siguiente, vamos ver que es posible pasar uno o varios argumentos (lo habíamos visto ya para las
funciones clásicas) a un constructor:
El argumento modelo está en los paréntesis que siguen al nombre del constructor:
y está disponible en el cuerpo del constructor por:
this.modelo = modelo;
A continuación, es suficiente a nivel de la instanciación del objeto miCoche con pasar como argumento un valor
("simca1100" en nuestro caso):
La propiedad (atributo) modelo del objeto se mostrará por:
5. Secuencia 5: No compartición de los métodos por las instancias de objetos
En la medida en que los métodos se declaran durante la instanciación de los objetos, sus definiciones están
duplicadas en memoria.
En un ejemplo pequeño, el impacto es bajo.
Por el contrario, si su aplicación manipula muchos objetos con métodos múltiples y complejos en los constructores,
esto se convierte en inmanejable.
El siguiente ejemplo destaca el problema que acabamos de comentar:
La ejecución confirma que el método avanzar no está factorizado:
La noción de prototipo que vamos a descubrir a continuación va a resolver este problema.
6. Secuencia 6: Noción de prototipo
Un prototipo es un conjunto de elementos (atributos/propiedades y métodos) que se va a asociar a un constructor
(sin "almacenamiento" en el constructor en sí mismo). Durante la ejecución, cuando una propiedad de objeto
solicitada en el código no se encuentra en el constructor del objeto en cuestión, se realizará una búsqueda en esta
lista "adicional".
Veamos un ejemplo completo:
La opción que se ha utilizado en el ejemplo es codificar un constructor vacío. Después, se realiza una comprobación
para demostrar que cualquier constructor tiene un prototipo:
Posteriormente, se ha asociado un método zigzaguear al prototipo relacionado con el constructor Coche:
Coche.prototype.zigzaguear = function()
{
document.write("zigzaguea peligrosamente<br />");
};
Después de la instanciación habitual de un objeto simca1100 a partir del constructor Coche, se hace una llamada
al método zigzaguear para el objeto simca1100.
También se instancia un segundo objeto, renault12, a partir del constructor Coche para demostrar que esta vez
el método zigzaguear está compartido (es común) por los dos objetos.
7. Secuencia 7: Sobrecarga de un método
Para una instancia dada de objeto, es posible sobrecargar (modificar) un método (o una propiedad/atributo).
Veamos un ejemplo concreto de cómo aplicarlo:
La ejecución da como resultado:
Puede comprobar que la modificación (sobrecarga) solo impacta al objeto simca1100.
8. Secuencia 8: Extensión de un prototipo
La extensión es la adición posterior de un método suplementario a nivel de un prototipo de constructor. Veamos un
ejemplo de extensión:
La ejecución da como resultado:
El simca1100 acelera
El simca1100 frena
Cuando se ejecuta el método simca1100.frenar, en primer lugar el método frenar se busca en el constructor
Coche y, como este método no se define, se realiza una búsqueda en la extensión, es decir, en el prototipo.
Todavía no habíamos visto la noción de herencia, que permite, en los lenguajes de POO clásicos, establecer una
relación de tipo "Clase hijaClase padre" entre clases de un modelo arborescente con, para la clase hija, una
herencia (en ocasiones modificada por sobrecargas) de propiedades/atributos y métodos de su clase padre.
En JavaScript, el mecanismo de herencia será un poco diferente. Se obtendrá por extensión de prototipos (un
prototipo extendido a partir de otro).
Veamos su aplicación con un ejemplo concreto:
Cuando se ejecuta, el resultado obtenido será el siguiente:
El simca1100 acelera
El simca1100 frena
Por tanto, el simca1100 de tipo Coche puede:
l acelerar con el método acelerar del prototipo del constructor Vehiculo,
l frenar con el método frenar (añadido como sobrecarga) al prototipo del constructor Coche.
10. Secuencia 10: Límite de la herencia de la secuencia 9
Comprobémoslo con un ejemplo un poco diferente:
La ejecución muestra que el objeto simca1100 se considera solo como un objeto de tipo Coche (y no
Vehiculo):
11. Secuencia 11: Un segundo límite a nuestra herencia
Si un método se añade al prototipo de un tipo "padre" después de que se haya hecho la copia de los elementos
entre el prototipo "padre" y el prototipo "hijo", entonces este método no está disponible en los objetos
instanciados con el tipo "hijo", como se muestra en el siguiente ejemplo:
Cuando se ejecuta, nos encontramos con lo siguiente, como era de esperar:
El barco frena
el simca1100
Hemos visto en el capítulo anterior cómo crear y utilizar nuevos objetos en JavaScript. En realidad este lenguaje
propone de manera nativa una serie de objetos que hay que conocer.
Observe que los desarrolladores Web se contentan justamente con estos objetos nativos.
En este capítulo vamos a listarlos, pero no de manera exhaustiva. Es fácil encontrar documentación y ejemplos de
estos objetos. También hay repositorios completos accesibles en Internet.
Nuestro objetivo es ser lo más completos posible y sobre todo, aprender a implementar estos objetos, así como sus
métodos y sus propiedades, a través de ejemplos didácticos y comentados.
Puede consultar en Internet repositorios completos sobre este tema, fundamentalmente Mozilla Developer Network, en
la dirección: https://developer.mozilla.org/es/docs/Web/JavaScript
Los objetos se abordarán por orden alfabético en este capítulo.
1. Objeto Array
En la medida en que este objeto se ha estudiado en el capítulo Tablas, no volveremos aquí sobre él.
2. Objeto Date
La gestión de las fechas es una preocupación frecuente en los desarrollos Web.
Para que sirva de ejemplo, a continuación se enumeran los principales métodos de este objeto:
l getDate()
l getDay()
l getFullYear()
l getHours()
l getMilliseconds()
l getMinutes()
l getMonth()
l getSeconds()
l getTime()
l getTimezoneOffset()
l getYear()
l setDate()
l setFullYear()
l setHours()
l setMilliseconds()
l setMinutes()
l setMonth()
l setSeconds()
l setTime()
l setYear()
l toGMTString()
l toLocaleString()
La gran mayoría de los métodos que se han listado anteriormente se van a estudiar con un primer ejemplo llamado
FECHA_01.htm.
Ejemplo 1
Empecemos por el método getDate(), que da el número de día del mes, para un objeto de tipo Date. En nuestro
caso, la fecha analizada es el día de hoy. Se instancia una fecha fechaDeHoy con valor la fecha de hoy. La función
getDate() aplicada al objeto fechaDeHoy da el número del día del mes. El resultado se muestra para control.
El método getDay devuelve el número del día de la semana para un objeto de tipo Date. El procesamiento se
hace de nuevo sobre la fecha del día de hoy. El método getDay() proporciona un resultado entre 0 y 6. Una tabla
de correspondencia podría dar el nombre del día (no está previsto en nuestro ejemplo).
El número del mes (comprendido entre 0 y 11) se obtiene a partir de una fecha, con el método getMonth(). Una
vez más, el procesamiento se hace sobre la fecha del día.
El número del año (con cuatro posiciones) se obtiene a partir de una fecha con el método getFullYear(). En
nuestro ejemplo el procesamiento se hace sobre la fecha del día.
Para recuperar la hora (comprendida entre 0 y 23) a partir de un objeto Date, hay que recurrir al método
getHours().
Para los minutos, el método se llama getMinutes().
Y para terminar, para los segundos el método es getSeconds().
Pasemos ahora a los métodos que permiten asignar valores (setters).
Por ejemplo, es posible indicar la fecha correspondiente al 15 del mes para la fecha actual, como sigue:
Con la secuencia de código siguiente, puede realizar una "vuelta atrás " de un mes respecto a una fecha de
referencia (aquí, la fecha del día).
El mismo procesamiento también es posible para una "vuelta atrás" de un año:
Solo falta ver cómo convertir en versión española la fecha de sistema. Para esto, usamos el método
toLocaleDateString():
Un procesamiento idéntico se puede aplicar para obtener las horas, minutos y segundos en formato español:
Este script permite visualizar la siguiente pantalla durante su ejecución (el jueves, 15 de enero del 2015):
Ejemplo 2
En este segundo ejemplo, siempre relacionado con la fecha, vamos a mostrar la hora actual en formato hh:mm:ss.
</script>
El primer argumento de setInterval es una función que invoca a una función llamada mostrarHoraActual
(que veremos más adelante) y una duración expresada en milisegundos (1000 = 1 segundo), correspondiente
al ritmo de actualización de la visualización de la hora de sistema en formato hh:mm:ss.
Pasemos al código de la función mostrarHoraActual, ubicado en la sección HTML <head>.
/* Función mostrarHoraActual */
function mostrarHoraActual()
{
/* Recupera la hora de sistema */
var miHoraReferencia = new Date();
La hora de sistema (fecha de sistema) se recupera instanciando un objeto de tipo Date en la variable
miHoraReferencia.
A continuación, se hace una conversión de la parte horas/minutos/segundos de esta fecha, en formato local
(hh:mm:ss).
El script de la función termina mostrando esta información en la división mencionada anteriormente.
Ejemplo 3
Estudiemos un último ejemplo relacionado con la gestión del tiempo, pero sin utilizar explícitamente la noción de
objeto, en el que vamos a programar un cronómetro (timer) simple.
El código ubicado en la sección HTML <body> es el siguiente:
El código empieza con un formulario de dos botones, que ejecuta una función de inicio de un timer y después la
parada de este mismo timer.
Posteriormente, está prevista una capa para la visualización del timer.
Estudiemos ahora las funciones de la sección HTML <head>.
El código de la función iniciarTimer es:
/* Función iniciarTimer */
function iniciarTimer()
Esta función fija el valor de inicio del timer (11 en nuestro caso) y llama a la función de actualización del timer
(decremento de una unidad de todos los segundos).
La función actualizarTimer contiene este código:
/* Función actualizarTimer */
function actualizarTimer()
{
if (valorTimer > 0)
{
/* Decrementar una unidad (segundo) */
valorTimer = valorTimer - 1;
/* Visualización del valor actualizado del timer */
document.getElementById("visualizacionTimer")
.innerHTML = valorTimer;
/* Actualización llamando a la función actualizarTimer */
if(valorTimer > 0)
{
/* Actualización cada segundo (1000 milisegundos) */
miTimer = setTimeout("actualizarTimer()", 1000);
}
}
}
La función actualizarTimer se llama a ella misma (noción de recursividad en programación) cada segundo a
través del método setTimeout("actualizarTimer()", 1000).
La actualización se interrumpirá cuando la cuenta alcance el valor de cero.
La visualización del valor actual del timer se hace por:
Para terminar, el timer también se puede interrumpir con un clic en un botón dedicado del formulario, ejecutando la
función pararTimer.
El código de la función pararTimer es el siguiente:
/* Función pararTimer*/
function pararTimer()
{
El método clearTimeout(), al que se le pasa el nombre del timer que debe detener ( miTimer), provoca la
parada del timer.
La visualización obtenida en pantalla es:
3. Objeto Math
De nuevo, de este objeto, no se prevé hacer la revisión de todos los métodos. Puede consultar un repositorio como
el de Mozilla Developper Network, para obtener la lista exhaustiva de métodos, en la siguiente dirección:
https://developer.mozilla.org/enUS/docs/Web/JavaScript/Reference/Global_Objects/Math
El objeto Math es, como Array y Date, un objeto nativo. Los métodos asociados sirven para manipular los
elementos numéricos.
Es necesario observar que Math no es un constructor; por tanto, escribir miNumero = new Math() sería un
error.
A continuación, se muestra una aplicación de los principales métodos.
Empezamos por el método abs, que devuelve el valor absoluto de un número que se pasa como argumento.
El método ceil proporciona el valor entero inmediatamente superior a un número que se pasa como argumento.
El método floor devuelve el valor entero inmediatamente inferior de un número que se pasa como argumento.
El método max es particularmente interesante, porque devuelve el máximo, no solo de dos números, sino de una
serie de números. Por tanto, evita una multitud de comprobaciones en cascada.
El método min es el opuesto del método max, es decir, determina el valor mínimo.
El método pow sirve para elevar a una potencia (exponenciación). Necesita dos argumentos.
/* Valor 5 elevado a 2 */
document.write("<br />Valor 5 elevado a 2: " + Math.pow(5, 2));
A menudo es útil hacer tiradas aleatorias de números aleatorios. El método random genera un número
comprendido entre 0 y 1 de manera aleatoria. A continuación, es fácil volver a procesar este valor para obtener, por
ejemplo, una tirada de un dado de 6 caras (caras numeradas de 1 a 6).
El método round también es muy útil: permite redondear un número al entero más cercano.
El método sqrt también se usa frecuentemente. Sirve para obtener la raíz cuadrada de un número que se pasa
como argumento.
Ejecutando, obtenemos:
4. Objeto window
En esta sección vamos a hacer un repaso rápido (no exhaustivo) de los métodos y propiedades asociadas al objeto
DOM window.
El objeto window representa la ventana del navegador.
Ilustremos el uso de los diferentes métodos con cinco ejemplos.
Ejemplo 1
En este primer ejemplo, de nuevo el código está totalmente integrado en la sección HTML <body>.
El objetivo del código es sencillo: abrir una ventana popup desde la pestaña actual. Observe que el procesamiento
solo se ejecuta correctamente si el navegador autoriza la creación de ventanas de tipo "popup". A menudo, esta
posibilidad está prohibida (opción del navegador) para evitar la aparición de ventanas publicitarias intrusivas.
El código del método open es muy simple:
/* Apertura de la ventana */
/* Argumentos (en orden de aparición):
- URL (Opcional): Indica la dirección URL de la página que se ha de abrir.
Si no se especifica ninguna URL, una nueva ventana con about: blank se abre
- Nombre de la ventana (Opcional): Especifica el atributo destino o
el nombre de la ventana
Los siguientes valores se soportan:
_blank: URL se carga en una nueva ventana (valor por defecto)
_parent: URL se carga en el contenedor padre
_self: URL remplaza la página actual
_top: URL sustituye los juegos de contenedores que se pueden cargar
Nombre: El nombre de la ventana
- Especificaciones detalladas de la ventana:
* height=píxeles: Altura de la ventana (100 píxeles mínimo)
* left=píxeles: Posición de la ventana respecto a la izquierda de la ventana
* location=yes|no|1|0: Presencia o no de una barra de dirección
* menubar=yes|no|1|0: Presencia o no de una barra de menús
* resizable=yes|no|1|0: Posibilidad o no de redimensionar la ventana
* scrollbars=yes|no|1|0: Presencia o no de barras de scroll
* estado=yes|no|1|0: Presencia o no de una barra de estado
* titlebar=yes|no|1|0: Presencia o no de una barra de título
* toolbar=yes|no|1|0: Presencia o no de una barra de herramientas
* width=píxeles: Longitud de la ventana en píxeles
*/
miVentana = window.open("", "VENTANA_01", "width=200, height=100,
location=yes, titlebar=yes");
Los muchos comentarios situados en el código fuente indican de manera precisa el papel de los diferentes
argumentos. En nuestro ejemplo, no está prevista la URL (por tanto, a priori la ventana estará sin contenido). La
ventana aquí se llama (VENTANA_01). Para terminar, se indican sus dimensiones (longitud y altura se expresan en
píxeles) y la ventana aparece con una barra de direcciones (location) y una barra de título (titlebar).
Es posible, fundamentalmente en caso de la ausencia de URL, programar un contenido para la nueva ventana como
sigue:
/* Focus en la ventana */
miVentana.focus();
La ejecución del script da como resultado la siguiente visualización:
Ejemplo 2
En este segundo ejemplo, además de la apertura (creación) de una nueva ventana, vamos a ver el cierre. El código
está repartido entre la sección HTML <body> (el formulario tiene dos botones, para crear y cerrar la ventana) y la
sección HTML <head>.
Empezamos por el formulario:
<form>
Apertura de una ventana pasando la URL como argumento</br>
<input
type="button"
value="Abrir una ventana yahoo.es"
onclick="abrirVentana(’http://www.yahoo.es)"
/>
<br /><br /><br />
Cierre de la ventana</br>
<input
type="button"
value="Cierre de la ventana"
onclick="cerrarVentana()"
/>
</form>
Pasemos al código fuente de la función abrirVentana.
/* Función abrirVentana */
function abrirVentana(URL)
{
miVentana = window.open(
URL, "VENTANA_02",
"width=400,
height=200,
location=1,
titlebar=yes,
resizable=yes"
);
}
Este código no tiene secretos. La URL se pasa como argumento en primera posición en los paréntesis. A
continuación viene el nombre de la ventana (VENTANA_02) y sus especificaciones técnicas:
l width: longitud de la ventana expresada en píxeles,
l height: altura de la ventana expresada en píxeles,
l location: presencia de una barra de direcciones (1 equivale a yes),
l resizable: posibilidad para el usuario de redimensionar la ventana.
El código de la función cerrarVentana es el siguiente:
/* Función cerrarVentana */
function cerrarVentana()
{
miVentana.close();
}
El método close cierra la ventana. Después de la ejecución, se obtiene:
Ejemplo 3
El comportamiento de este script va ser muy parecido al del ejemplo anterior: un formulario con un único botón para
lanzar la creación y el cierre de la ventana 10 segundos después.
El código del formulario es el siguiente:
El código del método abrirVentana llama a la función cerrarVentana después de 10 segundos.
/* Función abrirVentana */
función abrirVentana(URL)
{
/* Apertura de la ventana */
miVentana = window.open(
URL,
"VENTANA",
"width=400,
height=200,
location=1,
titlebar=yes,
resizable=yes");
El método setTimeout usa dos argumentos:
l el nombre del método que se ha de ejecutar, el método cerrarVentana en nuestro caso,
l el tiempo de espera antes de ejecutarlo, 10.000 milisegundos, es decir, 10 segundos.
Cuando se ejecuta el script, la visualización es:
Cuando se hace clic en el botón, se abre una ventana de Yahoo y se muestra durante 10 segundos.
Ejemplo 4
En este ejemplo, vamos a ver cómo detectar la resolución gráfica de la pantalla del usuario. En función de la
resolución, será posible adaptar el formato de los contenidos Web.
La secuencia de código es muy sencilla:
En este quinto ejemplo, vamos a implementar dos scripts, WINDOW_05.htm y WINDOW_06.htm, que se van a
llamar mutuamente. Con este ejemplo, tendremos la oportunidad de estudiar un determinado número de métodos y
propiedades específicos de los objetos de tipo window.
En el script WINDOW_05.htm, tenemos un formulario en el que hay un botón de llamada del segundo script:
El botón activa una función llamada accederWINDOW_06, que se encuentra en la sección HTML <head> del script
WINDOW_05.htm. Su código fuente es:
/* Función accederWINDOW_06 */
function accederWINDOW_06()
{
/* Acceso a la página WINDOW_06.htm */
miVentana = window.open("WINDOW_06.htm", "_self");
}
El código no tiene secretos. Se trata de una llamada al script WINDOW_06.htm, que se va a mostrar en la misma
pestaña (argumento _self).
La ejecución del script da la siguiente visualización:
/* Propiedad host */
document.write("</br>Propiedad location.host: "
+ window.location.host);
/* Propiedad hostname */
document.write("</br>Propiedad location.hostname: "
+ window.location.hostname);
/* Propiedad href */
document.write("</br>Propiedad location.href: "
+ window.location.href);
/* Propiedad pathname */
document.write("</br>Propiedad location.pathname: "
+ window.location.pathname);
/* Propiedad port */
document.write("</br>Propiedad location.port: "
+ window.location.port);
</script>
La visualización de los valores de las propiedades da como resultado, en nuestro caso:
La propiedad host está formada por la dirección del servidor (dirección local 122.0.1.1 en nuestro caso), seguida
del puerto de comunicaciones del servidor (8100).
También hay un botón de retorno a la página anterior ( WINDOW_05.htm), en esta sección HTML <body>:
Este botón llama a una función llamada volverPaginaAnterior, cuyo código es:
/* Función volverPaginaAnterior */
función volverPaginaAnterior()
{
/* Volver a la página anterior */
window.history.back()
}
El método window.history.back() provoca el retorno al script que se encuentra inmediatamente antes de la
página actual en el histórico de navegación, es decir, en nuestro caso WINDOW_05.htm.
El código JavaScript estudiado con este ejemplo es muy interesante, fundamentalmente cuando se debe
implementar un control de acceso entre las páginas de un sitio Web.
5. Objeto navigator
Este objeto contiene las propiedades de su navegador. El lenguaje JavaScript tiene la reputación de ser sensible
(comportamientos diferentes) al navegador, incluso a la versión del navegador en la que se ejecuta. En las
propiedades del objeto navigator, encontrará lo necesario para resolver este problema.
En la sección HTML <body>, encontrará principalmente un botón de llamada a una función que lista las
propiedades, así como una capa de visualización:
La función comprobarNavegador tiene el código siguiente:
/* Función comprobarNavegador */
function comprobarNavegador()
{
var caracteristicasNavegador = "";
caracteristicasNavegador = "Código del navegador: "
+ navigator.appCodeName + "<br />";
caracteristicasNavegador += "Nombre del navegador: "
+ navigator.appName + "<br />";
caracteristicasNavegador += "Versión: "
+ navigator.appVersion + "<br />";
caracteristicasNavegador += "Soporte a las cookies: "
+ navigator.cookieEnabled + "<br />";
caracteristicasNavegador += "Sistema operativo: "
+ navigator.platform + "<br />";
caracteristicasNavegador += "User-agent header: "
+ navigator.userAgent + "<br />";
caracteristicasNavegador += "User-agent language: "
+ navigator.systemLanguage + "<br />";
Los propiedades appCodeName, appName y appVersion son particularmente interesantes para detectar el
navegador.
La propiedad cookieEnabled también se usa muy frecuentemente para saber si el navegador soporta o no las
cookies. En caso de tener en cuenta las cookies, será necesario implementar otras soluciones de almacenamiento
La propiedad userAgent también se usa mucho porque contiene, en formato cadena de caracteres, toda la
información necesaria para una detección precisa del navegador en el que se ejecuta el script.
Para que sirva como ejemplo, con mi propia configuración, la ejecución da el siguiente resultado:
6. Objeto String
Como en la mayoría de los lenguajes de programación, el procesamiento de las cadenas de caracteres es muy
importante. JavaScript ofrece para esto un juego completo de métodos. Vamos a estudiar los principales métodos
con un ejemplo comentado.
El siguiente código se sitúa en la sección HTML <body>.
Empecemos definiendo dos variables de texto:
Para la variable apellido, se ha recurrido explícitamente a un constructor. Las dos variables se muestran a
continuación por control.
Determinemos ahora la inicial del apellido:
El método charAt(), con argumento 0, permite esta operación fácilmente. Observe que los caracteres de una
cadena se numeran empezando por cero.
El método utilizado es charCodeAt(), utilizando como argumento la posición de la letra en la cadena. En nuestro
caso, la respuesta será 193, porque la letra "Á" está en la posición 193 en la tabla ASCII.
Desde los años 60, el código ASCII (American Standard Code for Information Interchange) se ha convertido en el
estándar en materia de codificación y de intercambio entre ordenadores. Permite la codificación de caracteres en 8
bits, es decir, 256 caracteres posibles.
Ahora, veamos cómo concatenar (yuxtaponer o añadir) dos cadenas de caracteres:
La concatenación es un poco sorprendente en JavaScript; el método concat() se aplica a la cadena de base, a la
que se añade una extensión (una constante u otra variable).
Estudiemos ahora las múltiples técnicas de localización o extracción de una subcadena en una cadena de
caracteres. La exposición no será completa porque JavaScript, como la mayoría de los lenguajes de programación,
soporta también las expresiones regulares, concepto que no se estudia en este libro.
Empecemos con la localización de la primera aparición de una letra (comenzando por la izquierda) en una cadena de
caracteres:
El método utilizado es indexOf(), pasando como argumento la letra que buscamos ("e" en nuestro caso). Habrá
observado en el ejemplo que el valor mostrado se incrementa en 1; no olvide que, en las cadenas de caracteres, la
numeración de las letras empieza por cero.
También es posible encontrar la última ocurrencia de una letra (búsqueda desde la derecha) con el método
lastIndexOf():
Para los métodos indexOf() y lastIndexOf(), la respuesta es 0 si no se encuentra ninguna ocurrencia.
Pasemos a la sustitución de una subcadena por otra en una cadena de caracteres:
En este ejemplo, la subcadena "nge" se sustituye por "egn" con el método replace().
También es frecuente que queramos extraer una subcadena a partir de una cadena de caracteres. Hay varios
métodos disponibles para esto.
Empecemos por el método slice():
El método slice() asegura aquí la extracción del primer carácter (numerado con cero) hasta el quinto no incluido.
Esto puede parecer sorprendente, por lo que la respuesta en nuestro caso será "Ánge".
El método substr()también se usa:
Con el método substr(), el segundo argumento tiene un significado diferente; se trata de la longitud de la
subcadena extraída. La respuesta también será "Ánge".
Para terminar, la tercera posibilidad es el uso del método substring():
La única diferencia entre slice() y substring() es que el segundo argumento es opcional en el caso del
método substring(). En ausencia del segundo argumento del método substring(), la extracción se hace
hasta que el último carácter de la cadena se estudie.
El método split() asegura la división de una cadena de caracteres en sus diferentes palabras:
En el mensaje de control, se reproduce el nombre del autor (Ángel), el nombre que ha sido almacenado en la
posición 1 de la tabla tablaAutor (no olvide la numeración de los elementos de las tablas a partir de cero).
Veamos también cómo asegurar las conversiones de cadenas de caracteres en mayúsculas (método toUpperCase
()) y en minúsculas (método toLowerCase()):
/* Conversión en mayúsculas */
document.write("<br />El apellido en mayúsculas: " +
apellido.toUpperCase());
/* Conversión en minúsculas */
document.write("<br />El nombre en minúsculas:
" + nombre.toLowerCase());
Para terminar, eliminamos los espacios no significativos al inicio y al final de la cadena de caracteres:
Los corchetes ([]) situados en los dos métodos document.write tienen como objetivo materializar la eliminación
de los espacios no significativos (en el segundo caso) asegurado por el método trim().
La visualización obtenida es la siguiente:
1. Control de entrada de datos en un campo de texto
El objetivo aquí va a ser simple; controlar que el usuario ha realizado correctamente una entrada de datos por el
teclado, en un campo de tipo texto, dentro de un formulario HTML, utilizando para ello una función JavaScript. En
este primer script, no se comprueba el tipo de datos (numérico, alfanumérico, lógico...). Estos aspectos se verán en
las siguientes secciones.
Presentación del script HTML/JavaScript
Para este script, se reproduce el código fuente completo a continuación:
</script>
</head>
</script>
</body>
</html>
Comentarios del script del formulario HTML
En primer lugar, vemos el formulario HTML:
l Campo de entrada de datos simple
l Campo de entrada de datos multilínea
l Campo oculto (entrada de contraseña)
l Botón de radio
l Botón checkbox (casilla de selección)
l Listas desplegables
l Selector de archivo
l Botones de función (envío, anulación...)
En este libro, que trata principalmente de JavaScript, no está previsto ver en detalle las etiquetas de gestión de los
diferentes dispositivos de entrada de datos. Encontrará una documentación abundante en Internet y en muchos
libros dedicados a HTML.
En contraposición, en los ejemplos que vienen a continuación, se comentará la etiqueta HTML <input>.
<input
type=’text’
id=’nombre’
/>
El valor text del atributo tipo sirve para indicar que se trata de una entrada de datos de tipo texto. En este campo
de entrada de datos, puede introducir datos de tipo texto, numéricos e incluso alfanuméricos. El control de la
naturaleza de la entrada de datos es justamente el papel de una secuencia de código JavaScript.
El atributo id es una información que permitirá identificar este campo de entrada de datos en el código JavaScript.
El nombre lo elige libremente el programador, pero debe poder servir para su posterior identificación. La definición
En lo que respecta a las convenciones de escritura a nivel del HTML, debe saber que no es sensible a las
mayúsculas/minúsculas (puede escribir sus etiquetas en MAYÚSCULAS o en minúsculas). En este libro, se ha hecho
la elección arbitraria de presentar el código HTML en minúsculas.
El segundo control de entrada de datos es un botón cuya función consiste en ejecutar la comprobación del valor
introducido en la zona de texto, identificada por el id nombre:
<input
type=’button’
onclick="noVacio(document.getElementById(’nombre’),
’Entrada obligatoria’)"
value=’Comprobación de la entrada de datos’
/>
El tipo del control es button.
El atributo onclick es el disparador que provoca la ejecución del código integrado en las comillas que siguen
("noVacio(document.getElementById(’nombre’), ’Entrada obligatoria’)").
El atributo onclick precisa que la función JavaScript noVacio (que estudiaremos más adelante) se ejecutará con
un clic en el botón. Observe que, en nuestro ejemplo, el botón no se ha identificado con un nombre (se podría haber
utilizado el atributo name para hacerlo) porque en nuestro caso este botón es el único de nuestro formulario.
La función noVacio, que se llama con un clic en el botón, tiene dos argumentos:
l document.getElementById(’nombre’), que indica el campo que se va comprobar por la función,
l un mensaje (’Entrada obligatoria’), que se mostrará por la función en caso de que no haya entrada de
datos en la zona de texto, identificada por el id nombre.
Observe también las restricciones del uso de las comillas en la formulación de la operación de ejecución en el
onclick.
Comentarios del script de la función JavaScript noVacio
Pasemos ahora a estudiar la función JavaScript noVacio. En este caso, la elección ha sido ubicar el script
HTML/JavaScript en la sección <head> ... </head>. También se podría haber situado en la sección
<body> ... </body>. Este ha sido a menudo el caso en los ejemplos del inicio de este libro. Para terminar, las
funciones JavaScript se pueden ubicar en un archivo separado (identificado con un nombre) y hacer referencia a él
desde el script actual.
La primera línea de la función menciona el nombre de la función (noVacio), así como el nombre de los dos
argumentos formales alimentados por document.getElementById(’nombre’) y por ’Entrada
obligatoria’:
if (campo.value.length == 0)
El argumento formal campo corresponde evidentemente a la zona de texto y value es la propiedad que
representa al contenido de esta zona.
Si la longitud es nula, se muestra una alerta (’Entrada obligatoria’) y el foco se sitúa en el campo de
entrada de datos, para que se pueda hacer la entrada de datos ( método focus() aplicado a campo). En caso
contrario, se muestra el nombre (’Su nombre es ...’).
Para que la ejecución de la función se interrumpa, obligatoriamente hay que prever un return en cada caso. En
nuestro script, no importa el valor devuelto (true, false...) porque no se ha previsto comprobar el valor devuelto
más adelante.
Resultado de la ejecución
La ejecución de este script da el siguiente resultado, en caso de una validación sin entrada de datos en el campo de
texto nombre:
y este es el caso inverso (mensaje de confirmación mostrando el valor introducido):
El objetivo es un poco diferente del perseguido en el ejemplo anterior. Aquí se aplicará un control de tipo numérico a
la entrada de datos, que se hace en una zona de texto.
Como el procesamiento presenta muchas similitudes con el script anterior, solo se presentará y comentará una
parte del script.
Presentación del script del formulario HTML
El código del formulario es el siguiente:
El campo de entrada de datos de tipo text no es muy diferente del anterior; se llama numero.
Para el botón de ejecución del control de tipo numérico, se construye la función esNumero, con dos argumentos:
l document.getElementById(’numero’), que indica el campo que la función va a comprobar,
l un mensaje (’Indique un número entero, por favor’), que mostrará la función, en caso de que la
Presentación (parcial) del script de la función JavaScript esNumero
Se declara una variable valoresAceptados y se inicializa con una expresión regular, que contiene los caracteres
aceptados para una entrada de datos de un número entero.
Solo falta comprobar el contenido (propiedad value) del campo, respecto a esta lista de signos aceptados (cifras
de 0 a 9), para indicar un error de entrada de datos o no (visualización de una confirmación del valor de entrada de
datos en este caso).
En el marco de este libro, no está previsto presentar de manera exhaustiva las múltiples posibilidades ofrecidas por
las expresiones regulares. Puede consultar muchos recursos en Internet sobre este tema, fundamentalmente:
l http://www.w3schools.com/jsref/jsref_obj_regexp.asp
l https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/RegExp
l http://www.javascriptkit.com/javatutors/re.shtml
Resultado de la ejecución
Si no se introduce un valor, se muestra el siguiente mensaje:
3. Control de caracteres alfabéticos de una entrada de datos en un campo de texto
Como se puede imaginar, el problema es parecido al del ejemplo anterior.
La diferencia se va a presentar a nivel de la expresión regular (la variable valoresAceptados):
Los valores aceptados serán únicamente las letras del alfabeto, tanto en mayúsculas como en minúsculas.
4. Control de caracteres alfabéticos y numéricos de una entrada de datos en un campo
de texto
Evidentemente, el resto de los signos, como los caracteres acentuados, por ejemplo, serán rechazados por la
función de comprobación.
5. Control de la longitud de una entrada de datos en un campo de texto
Este problema es frecuente, fundamentalmente cuando se trata de forzar una entrada de datos de una contraseña
de un tamaño mínimo o máximo.
El código del formulario HTML es el siguiente:
<form>
Campo (entre 5 y 10 caracteres obligatoriamente):
<input
type=’text’
id=’entrada’
/>
<input
type=’button’
onclick="longitudEntrada(document.getElementById(’entrada’),
5, 10, ’Escriba entre 5 y 10 caracteres, por favor’)"
value=’Comprobación de la entrada’
/>
</form>
La función longitudEntrada tiene cuatro argumentos:
l document.getElementById(’entrada’), donde entrada es el nombre del campo de texto,
l 5, el valor mínimo de la longitud aceptada para la entrada de datos,
l 10, el valor máximo de la longitud aceptada para la entrada de datos,
l ’Escriba entre 5 y 10 caracteres, por favor’, es el mensaje de error que se ha de mostrar en
caso de error.
A nivel de la función JavaScript longitudEntrada, el código es:
6. Control de entrada de datos en una dirección de email
La comprobación se hace respecto a la siguiente expresión regular:
El control se realiza como sigue, con el uso del método match:
7. Control de la selección de una lista desplegable (versión simplificada)
Abandonamos ahora los campos de tipo text, cuyos los controles pueden ser múltiples usando expresiones
regulares, para abordar las listas desplegables (o listas de selección).
Presentación del script del formulario HTML
El código del formulario HTML se presenta como sigue:
Presentación del script JavaScript de la función controlarEleccionLista
El código de la función controlarEleccionLista se muestra completo esta vez:
El código de esta función no presenta dificultades particulares. El valor asociado a la elección realizada se
comprueba al inicio del procesamiento. Si la elección es siempre el valor inicial (Su deporte favorito), se
muestra el mensaje de alerta habitual. En caso contrario, se presenta la etiqueta seleccionada.
Resultado de la ejecución
El resultado obtenido de la ejecución es el siguiente si se hace clic en el botón Comprobación de la entrada de
datos sin haber seleccionado nada de la lista desplegable:
l <option selected>opción por defecto</option>, para indicar que una opción particular será
seleccionada por defecto.
l <select name="miLista" multiple>, para especificar que se pueden seleccionar varias opciones
simultáneamente en la lista.
La etiqueta <optgroup> ... </optgroup> también permite dividir una lista desplegable en niveles
jerárquicos.
Presentación del script del formulario HTML
La lista desplegable se divide en dos grupos, con etiquetas ’Deportes de equipo’ y ’Deportes
individuales’. La lista se desplegará totalmente porque se prevén siete líneas de visualización (dos líneas
para los grupos y cinco deportes) por la integración del atributo size=7. En cada uno de los grupos, se
preselecciona un deporte (atributo selected) y es posible la entrada de datos de varios deportes al mismo tiempo
(atributo multiple).
La función a la que se llama con un clic en el botón de envío es controlarEleccionLista y tiene un único
argumento, el identificador de la lista.
Presentación del script JavaScript de la función controlarEleccionLista
El código fuente de la función controlarEleccionLista se presenta íntegramente a continuación:
Un bucle for recorre los cinco deportes propuestos en la lista desplegable. La secuencia
document.forms.formulario.lista.options.length determina justamente el número de opciones
presentes en la lista desplegable de nombre lista, del formulario de nombre formulario (cf. <form
name=’formulario’>, en la descripción del formulario en HTML).
Posteriormente, options[i].selected permite comprobar si el usuario ha mantenido la opción o no y, si se da
el caso, mostrar la etiqueta del deporte seleccionado (atributo text).
Resultado de la ejecución
El resultado obtenido con la ejecución es el siguiente:
Las dos confirmaciones siguientes aparecen cuando se hace la validación con el botón Validación entrada:
Ofrecer una selección entre varias opciones con un conjunto de botones de radio es una solución interesante.
Constituye una alternativa a la selección simple en una lista desplegable, en la medida en que la selección de un
conjunto de botones de radio no permite la multiselección.
Presentación del script del formulario HTML
Una vez más, nuestro formulario se debe llamar a nivel de la etiqueta form:
<form name="lista_deportes">
Después hay un título para el conjunto de botones:
y se presenta la lista de botones de radio:
<input
type="radio"
name="deportes"
value="golf">
Golf
</input>
Para la función seleccionarDeporte, asociada al evento onclick del botón de envío, solo se prevé un
argumento, un mensaje de alerta, que se mostrará en caso de que no se seleccione ningún botón de radio:
<input
type=’button’
onclick="seleccionarDeporte
(’Seleccione su deporte favorito’)"
value=’Comprobación de la entrada’
/>
Presentación del script JavaScript de la función seleccionarDeporte
El script JavaScript, relativamente largo, de la función seleccionarDeporte se reproduce completamente a
continuación:
El procesamiento empieza recuperando en una tabla la lista de los botones de radio integrados en el formulario
HTML:
El número de deportes propuestos en el formulario HTML se determina a continuación:
Para terminar, un bucle while recorre los diferentes botones de radio para determinar si han sido seleccionados o
no (normalmente solo uno). Observe que, en caso de no selección, también se ha previsto un control con una
estructura condicional.
Si el botón de radio se ha seleccionado:
if (tabDeportes[i].checked)
entonces se muestra su nombre (atributo value):
Un último mecanismo basado en una variable booleana deporteSeleccion también permite mostrar un mensaje
de alerta (la variable mensajeAviso pasado como argumento a la función) si no se ha seleccionado ningún botón
de radio.
Resultado de la ejecución
El resultado obtenido con la ejecución es el siguiente:
10. Control de la selección con casillas de selección
La selección dentro de un conjunto de casillas de selección presenta similitudes con la selección con botones radio.
La principal diferencia es que, en este caso, es posible la selección múltiple.
Presentación del script del formulario HTML
<form name="lista_deportes">
Deportes favoritos:<br />
<input
tipo="checkbox" name="deportes[]" value="golf">Golf
</input><br>
<input
tipo="checkbox" name="deportes[]" value="futbol">Fútbol
</input><br>
<input
tipo="checkbox" name="deportes[]" value="natacion">Natación
</input><br>
<input
tipo="checkbox" name="deportes[]" value="tenis">Tenis
</input><br>
<input
tipo=’button’
La programación del botón de envío es casi idéntica a la del apartado anterior. Se llama a una función
seleccionDeportes con un mensaje de alerta como argumento.
Presentación del script JavaScript de la función seleccionDeportes
El código de la función se muestra aquí íntegramente, aunque sea muy parecido al visto en el párrafo anterior.
/*
Función de comprobación de los valores seleccionados
en un conjunto de casillas de selección
*/
function seleccionDeportes(mensajeAlerta)
{
/*
Recuperación de los deportes propuestos
en el formulario en una tabla
*/
var tabDeportes = document.forms.lista_deportes.elements["deportes[]"];
/* Determinación del número de deportes propuestos */
var numeroDeportes = tabDeportes.length;
// alert("Número de deportes: " + numeroDeportes);
/* Recorrido de la tabla de los deportes propuestos */
var i = 0;
var numeroDeportesSeleccionados = 0;
while (i < numeroDeportes)
{
/* Prueba si el deporte se ha seleccionado */
if (tabDeportes[i].checked) {
/* Incremento del número de deportes seleccionados */
numeroDeportesSeleccionados = numeroDeportesSeleccionados + 1;
alert("Su deporte favorito es " + tabDeportes[i].value);
}
i = i + 1;
}
/* Mensaje de alerta si no se ha seleccionado ningún deporte */
if (numeroDeportesSeleccionados == 0) {
/* Mensaje de alerta */
alert(mensajeAlerta);
/* Valor de retorno */
return false;
} else {
/* Valor de retorno */
Algo específico es, sin duda, la recuperación de los deportes mostrados en el formulario HTML:
Resultado de la ejecución
El resultado obtenido cuando se ejecuta el script es el siguiente:
Las siguientes confirmaciones aparecen cuando se ejecuta la validación con el botón Comprobación de la entrada:
1. Definición del DOM
DOM (Modelo de Objeto de Documento o Document Object Model) es el modelo de acceso a los diferentes
componentes de los documentos HTML e incluso XML.
En el capítulo Exploración del flujo XML vía DOM, veremos en detalle cómo explotar el flujo XML en los scripts
JavaScript.
Gracias al DOM, dispone de una descripción estructurada del script HTML, y también proporciona el modo de acceso
a los elementos constitutivos del modelo.
Como desarrollador, este será un gran aliado para acceder a estos elementos y manipularlos con un lenguaje de
programación (JavaScript, por ejemplo, pero no en exclusiva).
DOM va a ser para nosotros un esquema de acceso a las partes que forman una página Web (formulario, campo...)
con etiquetas de marcado.
Este modelo proporciona una jerarquía de programación que organiza las propiedades, métodos y eventos.
El estudio y la correcta comprensión del modelo DOM son indispensables para poder utilizar lo mejor posible las
principales librerías JavaScript, como Prototype, jQuery, MooTools...
El modelo DOM es un árbol formado por objetos Node (nodos). Se trata de una estructura arborescente con un
nodo de tipo raíz y nodos hijo. En el siguiente ejemplo (script HTML), el nodo head es un hijo del nodo <html>. El
nodo <head> es padre del nodo <title>. Las etiquetas <input> integradas en la sección <body> ...
</body> representan un ejemplo de nodos del mismo nivel, que tienen un mismo padre, el formulario llamado
formulario_entrada.
<html>
<head>
<title>
</title>
</head>
<body>
<form name="formulario_entrada ">
<input ... </input>
<input ... </input>
</form>
</body>
</html>
El modelo DOM es aplicable a cualquier documento de tipo XML.
2. Definición de la arborescencia
Noción de nodo
Interfaz Node
La interfaz Node va ser nuestra caja de herramientas para recorrer los diferentes niveles de la arborescencia DOM.
Está formada por propiedades y métodos para asegurar los movimientos en el árbol.
Las propiedades (clasificadas por orden alfabético)
l atributes: lista de atributos del nodo actual.
l childNodes: lista de nodos hijos.
l firstChild: primer hijo de un nodo.
l lastChild: último hijo de un nodo.
l nextSibling: siguiente nodo del mismo tipo.
l nodeName : nombre del nodo.
l nodeType: tipo del nodo.
l nodeValue: valor contenido en el nodo.
l padreNode: nodo padre.
l previousSibling: nodo anterior de un tipo concreto.
Los métodos (clasificados por orden alfabético)
l appendChild(): adición de un nodo hijo.
l cloneNode(): duplicación de un nodo.
l deleteData(): borrado de datos en caracteres.
l getAtribute(): búsqueda del valor de un nodo atributo.
l getAtributeNode(): búsqueda de un nodo atributo.
l hasChildNodes(): control de la existencia de nodos hijos.
l insertBefore(): inserción de un nodo.
l removeAtribute(): borrado del valor de un nodo atributo.
l removeAtributeNode(): borrado de un nodo atributo.
l removeChild(): eliminación de un nodo.
l replaceChild(): sustitución de un nodo hijo.
l setAtribute(): definición del valor de un nodo atributo.
l setAtributeNode(): definición de un nodo atributo.
El objeto document es la raíz de todos los nodos de un script Web. Este objeto particular tiene sus propios
métodos, que se aplican al documento en su globalidad:
l createElement: creación de un nuevo elemento en la arborescencia.
l getElementsByName: recuperación del elemento que tiene el nombre específico.
l getElementsByTagName: recuperación del elemento con un tag específico.
Ejemplo
Dado un documento Web con un tag div, con el atributo id igual a ’container’, vamos a poner dentro otra
capa (div) con el texto ’Buenos días, mundo’:
En una serie de ejemplos, vamos a ver cómo es posible con JavaScript escribir texto (y elementos DOM más
complejos) en un documento HTML.
1. Script "Hello World"
En este primer script, vamos a ver cómo mostrar una cadena de caracteres "Hello World", en el cuerpo del
documento HTML, añadiendo también etiquetas de formato (negrita).
El siguiente script no está escrito en su integridad; solo se muestra la secuencia JavaScript en cuestión, integrada
en la sección HTML <body> del script:
</script>
Cuando se ejecuta el script, se obtiene la visualización, con el método alert, de un cuadro de diálogo con el título
del ejercicio (DOM_01):
En este ejemplo, se ve cómo integrar en la secuencia que se va a mostrar etiquetas de formato como <b> ...
</b> (negrita). En realidad, todas las etiquetas y atributos de etiquetas HTML se pueden integrar en el método
document.write. En general, se puede construir todo el documento HTML programándolo con JavaScript.
2. Diferencia entre write y writeln
En este pequeño ejemplo, vamos a ver la diferencia entre los métodos write y writeln.
</script>
La visualización de lo que se obtiene en la sección body cuando se ejecuta este script, es la siguiente:
3. Gestión de los enlaces hipertextos
En este nuevo ejemplo, aprenderemos a gestionar los enlaces hipertextos. La secuencia de código se integra una
vez más en la sección HTML <body> del script:
/* Salto de líneas */
document.write("<br /><br />");
</script>
Posteriormente, se muestra el número de enlaces del documento, el identificador del segundo enlace y la URL del
tercer enlace:
La numeración de los enlaces se realiza de 0 a n1.
Vamos a aprender a gestionar imágenes con un ejemplo. La secuencia de código se integra en la sección HTML
<body> del script:
</script>
Cuatro imágenes se presentan con etiquetas HTML <img>, con determinados atributos (id, border, src, width,
height).
l el número de imágenes del documento;
l los atributos de las imágenes.
La numeración de las imágenes se realiza de 0 a n1.
La ejecución del script da el siguiente resultado:
5. Gestión de formularios y de sus etiquetas
El código (parcial) del script es el siguiente:
</script>
En este script, se visualiza diferente información de los formularios y las etiquetas input integradas en ellos:
l Número de formulario(s) del documento:
l Nombre del primer formulario:
l Identificador del segundo formulario:
El script no presenta dificultades particulares. Tenga en cuenta las siguientes observaciones:
l La numeración de los formularios se realiza de 0 a n1.
l La propiedad length indica el número de elementos de cada colección (forms, input...).
La ejecución del script da el siguiente resultado:
6. Gestión de los anchors
Ahora veamos cómo gestionar los anchors con un pequeño ejemplo. El siguiente código (parcial) se sitúa en la
sección HTML <body> de nuestro script:
/* Salto de línea */
document.write("<br /><br />");
</script>
En este script se programan tres anchors HTML:
En general, los enlaces de hipertexto apuntan a scripts externos (encadenamiento entre páginas de un mismo sitio
o entre sitios web diferentes) con una sintaxis <a href="dirección absoluta/dirección relativa
de la página destino ">Nombre del enlace </a>.
En nuestro script, también hubiera sido posible programar accesos a los tres anchors (aquí no se ha hecho) con una
formulación del tipo <a href="#nombre_anchor">nombre del enlace </a>. Por ejemplo, en nuestro
caso, para el primer anchor sería:
Por el contrario, se ha utilizado un enlace hipertexto que apunta a http://www.google.es:
En la sección JavaScript de nuestra página, encontrará el recuento del número de anchors de la página:
y después la visualización del título del primer anchor:
y del nombre del segundo anchor:
Cuando se ejecuta el script, la visualización obtenida es:
El enlace a http://www.google.es no se contabiliza como anchor.
7. Gestión de la navegación entre páginas Web
Vamos a abordar la navegación entre páginas Web. No nos centraremos en las técnicas más avanzadas de paso de
argumentos entre páginas ni en los mecanismos de conservación de información (persistencia). Para que sirva de
ejemplo, encontrará más adelante en este libro un capítulo dedicado a la gestión de cookies (cf. capítulo Gestión de
las cookies en JavaScript).
Las cookies se presentan como pequeños archivos de texto, que pueden contener un número limitado de datos. Esta
técnica puede ser interesante para conservar contenidos de variables en memoria, reutilizables a lo largo de la
navegación, a través de muchas páginas de su sitio Web (conservación de identificadores, contraseñas, preferencias de
usuario...).
En el marco de este ejemplo, se van a implementar dos scripts.
El código fuente (situado en la sección HTML <body>) del primer script se presenta a continuación:
</script>
El script anterior no tiene ninguna particularidad. Evidentemente, los dos enlaces definidos que dan acceso a las
páginas DOM_07_02.htm y DOM_07_03.htm se habrían podido programar en HTML.
El segundo enlace llama al script DOM_07_03.htm, pasándole un argumento llamado libro, con el valor "ENI
JavaScript":
La visualización da el siguiente resultado:
Pasemos ahora al segundo script ( DOM_07_2.htm), llamado por el documento principal DOM_07_1.htm. El código
(en la sección HTML <body>) se muestra parcialmente a continuación:
La URL del documento que llama se mostrará en este script:
En nuestro caso, la visualización da como resultado:
Terminemos con el tercer script (DOM_07_3.htm), al que también se llama desde el documento principal
DOM_07_1.htm, pero esta vez pasando un argumento. La reproducción del código fuente es más completa porque
el JavaScript se sitúa en la sección HTML <head> y en la sección HTML <body>:
/* Función historyBack */
function historyBack()
{
/* Volver a la página anterior */
window.history.back();
}
</script>
</head>
/*
Mostrar la URL de la página
que da acceso al documento
*/
document.write("URL de la página que da acceso al documento: "
+ document.referrer + "<br />");
/*
Mostrar el valor del argumento
pasado por la página anterior
NB: param tendrá la cadena ?param=Eni%20JavaScript
*/
var param = window.location.search;
document.write("Argumento (antes de la recodificación): "
+ param + "<br />");
/*
Codificación del argumento (sustituyendo %20
por un espacio en nuestro caso)
*/
param = unescape(param);
document.write("Argumento (después de la recodificación): "
+ param + "<br />");
/*
Eliminación del nombre del argumento
(libro en nuestro caso)
*/
param = param.substring(param.lastIndexOf("=") + 1);
document.write("Valor del argumento: "
+ param);
</script>
La ejecución del script sigue esta secuencia:
l Procesamiento y visualización del argumento pasado por el script DOM_07_1.htm:
/*
Mostrar el valor del argumento pasado
por la página anterior
NB: param tendrá la cadena ?param=Eni%20JavaScript
*/
var param = window.location.search;
document.write("Argumento (antes de la recodificación): "
+ param + "<br />");
/*
Codificación del argumento (sustituyendo %20
por un espacio en nuestro caso)
*/
param = unescape(param);
document.write("Argumento (después de la recodificación): "
+ param + "<br />");
window.location.search aísla en la URL la parte que contiene el argumento (?libro=Eni%
20JavaScript). La función unescape permite sustituir los caracteres codificados durante la llamada al
documento desde DOM_07_1.htm. El espacio representado en la URL por la secuencia ’%20’ se restituye.
La visualización da el siguiente resultado:
Al final del script, encontrará un miniformulario con un botón que llama a una función JavaScript de nombre
historyBack (ubicada en la sección HTML <head>). Esta función provoca el retorno al script que llama
(DOM_07_1.htm):
window.history.back();
8. Visualización de las características generales del documento
Sin querer ser exhaustivo, el script va a mostrar cómo acceder a algunas características generales (título, URL, fecha
de última modificación...) del script actual:
</head>
</script>
Se muestran diferentes características generales del script:
l el título del documento:
l el dominio del documento:
l la URL (absoluta) del documento:
l la fecha de última modificación:
La ejecución del script, da el siguiente resultado:
9. Gestión de los botones en los formularios
Con el ejemplo propuesto en la sección dedicada a la gestión de los formularios y de sus etiquetas, habíamos
estudiado esta gestión en JavaScript.
Ahora vamos a ir más lejos con los formularios en los que vamos a ubicar los campos de entrada de los datos
(etiquetas HTML input).
Ejemplo 1
En un primer ejemplo, nos centramos principalmente en la recuperación de información (nombre, identificador) de los
botones de formularios. En la sección HTML <body>, nuestro documento contiene (presentación parcial) la
descripción HTML de tres formularios:
Cada botón ( <input type="button" ...>) llama a una función JavaScript. Para que sirva de ejemplo, el
primer botón del primer formulario llama a la función JavaScript desactivarBoton cuando se hace clic en él (se
dispara el evento onclick).
Estudiemos ahora en detalle la programación asociada a cada botón.
Para el botón con identificador miBoton del primer formulario, el código del botón (sección HTML <body>) es:
y el código fuente de la función que ejecuta (sección HTML <head>):
/* Función desactivarBoton */
function desactivarBoton()
{
document.getElementById("miBoton").disabled=true;
}
document.getElementById("miBoton") designa al botón identificado con un id igual a miBoton
y .disabled=true hace que este botón no sea accesible.
Para el botón con identificador miBoton1 del segundo formulario, el código del botón (sección HTML <body>) es:
<input
type="button"
id="miBoton1"
value="Boton1"
onclick="mostrarNombreBoton(this.value);"
/>
y el código fuente de la función que ejecuta (sección HTML <head>) es:
/* Función mostrarMiBoton */
function mostrarMiBoton(MiBoton)
{
alert("El título del botón seleccionado es "+ MiBoton);
}
El botón identificado con el identificador miBoton2, que no se comenta aquí, también llama a la función
mostrarMiBoton.
Para el botón con identificador miBoton3 del tercer formulario, el código (sección HTML <body>) es:
<input
type="button"
id="miBoton3"
y el código fuente de la función que ejecuta (sección HTML <head>) es:
/* Función mostrarIdentificadorBoton */
function mostrarIdentificadorBoton(idBoton)
{
alert("El botón seleccionado tiene como identificador " + idBoton);
}
El argumento this.id que se pasa a la función mostrarIdentificadorBoton, que representa al
identificador del botón (id="miBoton3"), se muestra
por el método alert de la función
mostrarIdentificadorBoton.
Para terminar, para el enlace hipertexto identificado con miEnlace en el tercer formulario, el código del botón
(sección HTML <body>) es:
<a
href="#"
id="miEnlace"
onclick="mostrarIdentificadorElement(this.id);">
Enlace hipertexto
</a>
y el código fuente de la función que ejecuta (sección HTML <head>) es:
/* Función mostrarIdentificadorElement */
function mostrarIdentificadorElement(idElement)
{
alert("El identificador del enlace seleccionado es " + idElement);
}
Ya tiene suficiente experiencia para detectar que la función mostrarIdentificadorElement también se
hubiera podido utilizar por los botones vistos anteriormente.
Recapitulemos lo que sucede con la ejecución de este script. Los formularios se muestran como sigue:
Un clic en el botón Botón1 muestra esto:
Un clic en el botón Botón3, muestra esta visualización:
Ejemplo 2
Estudiemos un segundo ejemplo relativo a los formularios y sus botones con un script un poco más complejo.
En la sección HTML <body>, tenemos:
/*
Mostrar el número de etiquetas input
en el segundo formulario
*/
var lista2Input = document.forms[1].getElementsByTagName(’input’);
var nombre2Input = lista2Input.length;
document.write("Número de etiquetas input en el segundo formulario: "
+ nombre2Input);
</script>
Se visualizan dos formularios. El primer formulario contiene tres campos de entrada de datos de tipo <input
type="button" ...> y el segundo formulario contiene dos.
Cada botón tiene los atributos (propiedades) id y value y ejecuta una misma función
mostrarPropiedadesBoton. Para cada llamada a la función mostrarPropiedadesBoton, se pasan dos
argumentos: la etiqueta del botón ( this.value) y el identificador (this.id).
Después de la visualización de los dos formularios, se presenta la siguiente información:
l el número de etiquetas input en los formularios;
l el número de etiquetas input en el segundo formulario.
La instrucción:
crea una tabla (lista) con los elementos DOM de nombre input en nuestro documento.
Después se determina el número de elementos:
y mostrará:
Para determinar el número de elementos DOM de nombre input en el segundo formulario, la sintaxis es muy
parecida:
En esta sintaxis, forms[1] indica que solo los input del segundo formulario (numerado con 1) se deben
contabilizar.
Queda ver el contenido de la función mostrarPropiedadesBoton (sección HTML <head>):
/* Función mostrarPropiedadesBoton */
function mostrarPropiedadesBoton(miBoton, idBoton)
{
alert("El título del botón seleccionado es
" + miBoton + " y este botón pertenece al formulario "
+ document.getElementById(idBoton).form.name);
}
El procesamiento no tiene sorpresas.
Recapitulando una vez más lo que sucede cuando se ejecuta el script, los formularios se muestran como sigue:
Un clic en el botón Boton4 del segundo formulario provoca esta visualización:
10. Gestión de las tablas (etiqueta HTML table)
De nuevo, veamos a través de una serie de ejemplos lo que puede hacer con las tablas HTML con un mínimo de
conocimientos en JavaScript.
Ejemplo 1
El objetivo es aprender a modificar las características de una tabla (border, cellspacing, cellpadding y
caption) con JavaScript.
Recordemos brevemente a qué corresponden estos cuatro atributos:
l atributo border: grosor del marco (por defecto 1) expresado en píxeles,
l atributo cellspacing: tamaño del borde entre las celdas expresado en píxeles,
l atributo cellpadding: espacio comprendido entre el contenido de las celdas y los bordes de la tabla expresado en
píxeles,
l atributo caption: nombre la tabla.
El resultado de la ejecución del script se propone en la presentación de este ejemplo.
Vemos el contenido de la sección HTML <body> de nuestro ejemplo:
l atributo id: miTabla
l atributo border: 1
l atributo cellspacing: 1
l atributo cellpadding: 1
En esta tabla se ha implementado un formulario con cuatro botones. Los botones tienen la función (en el orden de
su presentación en el formulario) de:
l modificar el valor del atributo border,
l modificar el valor del atributo cellspacing,
l modificar el valor del atributo cellpadding,
l añadir un título (atributo caption).
Para las cuatro llamadas a las funciones JavaScript, no hay paso de argumentos. Las cuatro llamadas se asocian al
evento onclick.
Pasemos ahora a estudiar las cuatro funciones JavaScript (sección HTML <head>).
El código de la función modificarBorder es:
}
else
{
/* Pasar a un grosor de 1 */
document.getElementById(’miTabla’).border = "1";
}
}
Se hace una comprobación sobre el grosor del borde de la tabla, localizada por su identificador
(getElementById):
if (document.getElementById(’miTabla’).border == "1")
Si el grosor del borde es igual a 1 (el valor por defecto en el código HTML visto anteriormente), entonces el grosor
se cambia a 5 (e inversamente, se devuelve a 1 en caso contrario).
El código de la función modificarCellspacing es:
/* Función modificarCellspacing */
function modificarCellspacing()
{
if (document.getElementById(’miTabla’).cellSpacing == "1")
{
/* Pasar a un cellspacing de 40 */
document.getElementById(’miTabla’).cellSpacing = "40";
}
else
{
/* Pasar a un cellspacing de 1 */
document.getElementById(’miTabla’).cellSpacing = "1";
}
}
Como puede ver, el código es muy parecido al de la función anterior; solo cambia el atributo cellSpacing (en
lugar de border).
La última función, AñadirCaption, es la siguiente:
Se crea un título para la tabla con identificador miTabla a través de una función llamada createCaption.
Posteriormente, se hace la asignación del título en la parte superior de la tabla por:
Veamos el resultado de la ejecución de este script. Empecemos por el estado inicial (antes del uso de los botones):
Después del uso de estos cuatro botones, la visualización es la siguiente:
En este segundo ejemplo, el objetivo es automatizar con JavaScript la implementación de un trazo horizontal de
encabezado que se muestre por encima de la tabla HTML (también se dibujará un trazo al pie de la tabla). No hay
dificultad alguna desde un punto de vista técnico, pero nos permitirá de descubrir un atributo HTML relativamente
desconocido, frame.
Recordemos que este atributo HTML puede tener dos valores:
l above: visualización de bordes externos en la parte superior de la tabla únicamente,
l below: visualización de bordes externos en la parte inferior de la tabla únicamente.
Además de la tabla HTML vista en el ejemplo 1, se construye un formulario:
El código del primer procedimiento es:
/* Función situarTrazoEncima */
function situarTrazoEncima()
{
document.getElementById(’miTabla’).frame = "above";
}
Y del segundo es:
/* Función situarTrazoDebajo */
function situarTrazoDebajo()
{
document.getElementById(’miTabla’).frame = "below";
}
En los dos casos, la propiedad (atributo HTML) frame se configura para la tabla identificada por miTabla.
Cuando se ejecuta el script, el estado inicial de la tabla es el siguiente:
Y después de ejecutar el segundo botón, la visualización se convierte en:
Nos basamos de nuevo en la tabla propuesta en los ejemplos 1 y 2. A continuación (en la sección HTML <body>),
se definen dos formularios:
Pasemos al código JavaScript de la función mostrarCelda (situado en la sección HTML <head>):
/* Función mostrarCelda */
function mostrarCelda()
{
/*
Mostrar el número de la línea
seleccionada en la tabla
*/
var numeroLinea =
paseInt(document.getElementById(’numLinea1’).value);
alert("Número de línea: " + numeroLinea);
/*
Mostrar el número del columna
seleccionada en la tabla
*/
var numeroColumna =
parseInt(document.getElementById(’numColumna1’).value);
alert("Número de columna: " + numeroColumna);
/*
Mostrar el número de líneas de la tabla
*/
var numeroLineas =
parseInt(document.getElementById(’miTabla’).rows.length);
alert("Número de línea(s) de la tabla: " + numeroLineas);
/*
Mostrar el número de columnas de la tabla
El primer objetivo de la función es recuperar en variables en memoria el número de la línea y de la columna de la
celda que se desea visualizar:
y
Posteriormente, para que se pueda realizar un control de coherencia del número de la línea y del número de la
columna que se introducirán en el formulario, se debe determinar el número de líneas y de columnas de la tabla:
var numeroLineas =
parseInt(document.getElementById(’miTabla’).rows.length);
var numeroColumnas =
parseInt(document.getElementById(’miTabla’).rows[0].cells.length);
Por ejemplo, para la línea número 2 de la tabla, el resultado será: <td>Lamborghini
Miura</td><td>385</td>
Recordemos que la propiedad innerHTML proporciona el contenido HTML del elemento de tabla (aquí, una línea
entera).
Los diferentes elementos de la línea (celdas o columnas) se sitúan a continuación en una tabla en memoria:
var tabLinea =
document.getElementById(’miTabla’).rows[numeroLinea].cells;
Esto permite mostrar el valor de la columna de destino (sin el código HTML) como sigue:
Por ejemplo, para el número de línea 2 y el número de columna 1, el resultado mostrado será 385.
Solo se implementa un control de validación para comprobar el número de la línea y de la columna:
La segunda función, modificarCelda, tiene un código fuente muy parecido al de la función mostrarCelda.
Nos centramos en algunas diferencias.
Como sucedía anteriormente, las celdas de la tabla de la línea implicada se ubican en una tabla en memoria:
Posteriormente, solo falta modificar el contenido de la celda de destino. En nuestro ejemplo, el valor de sustitución
es una constante (" Nuevo valor"). Evidentemente, en una aplicación más evolucionada, este valor se introduciría
a través de un formulario. El código para esta sustitución (modificación) es el siguiente:
/* Modificación */
tabLinea[numeroColumna].innerHTML="Nuevo valor";
Si introducimos 1 como número de línea y 1 como número de columna en el primer formulario, aparecen las
siguientes visualizaciones:
y
Ejemplo 4
Partimos de la tabla propuesta en los ejemplos anteriores (que, en su versión inicial, tiene tres coches de deporte).
El objetivo en este nuevo ejemplo va a ser insertar en primera línea (directamente bajo el título) un nuevo vehículo,
así como un segundo al final de la tabla. Para no complicar el código del ejemplo (y las explicaciones relacionadas),
los datos insertados serán valores constantes. Sabrá cómo personalizar fácilmente este código para que los datos
se puedan introducir por el teclado.
Para la adición en la cabecera de tabla (bajo el título), el formulario es el siguiente:
Cuando se ejecuta el script, el estado inicial de la tabla es el siguiente:
Estudiemos el código JavaScript de la función añadirLineaInicioTabla (ubicado en la sección HTML <head>):
/* Función añadirLineaInicioTabla */
function añadirLineaInicioTabla()
{
/*
Añadir una columna 0 (Modelo) en la línea creada
y almacenar un valor
*/
var columna0=tabLinea.insertCell(0);
columna0.innerHTML="Ferrari F40";
/*
Añadir una columna 1 (Potencia) en la línea creada
y almacenar un valor
*/
var columna1=tabLinea.insertCell(1);
columna1.innerHTML="478";
}
En primer lugar, conviene insertar una línea (vacía de momento) bajo el título, en la tabla ’miTabla’. Observe que
la numeración de las líneas empieza en las tablas HTML por 0; la línea insertada será, por tanto, la número 1. El
método es insertRow.
var tabLinea=document.getElementById(’miTabla’).insertRow(1);
Una vez que la línea se ha insertado, hay que prever la descripción de las columnas (dos en nuestro caso) y poner
en ellas los datos. Para la primera columna (también numerada por 0), el código es:
var columna0=tabLinea.insertCell(0);
columna0.innerHTML="Ferrari F40";
La tabla HTML después de esta inserción se presenta como sigue:
/* Función añadirLineaFinTabla */
function añadirLineaFinTabla()
{
/*
Mostrar el número de líneas de la tabla
*/
var numeroLineas =
parseInt(document.getElementById(’miTabla’).rows.length);
/*
alert("Número de línea(s) de la tabla: " + numeroLineas);
*/
/*
Añadir una línea vacía después de la última línea
actual de la tabla
*/
var tabLinea = document.getElementById(’miTabla’)
.insertRow(numeroLineas);
/*
Añadir una columna 0 (Modelo) en la línea creada
y almacenar un valor
*/
var columna0 = tabLinea.insertCell(0);
columna0.innerHTML = "Porsche 959";
Es necesario, en primer lugar, determinar el número de líneas presentes en la tabla HTML:
var numeroLineas =
parseInt(document.getElementById(’miTabla’).rows.length);
Después añadimos una línea al final de la tabla, con el método insertRow:
/*
Añadir una línea vacía después de la última línea
actual de la tabla
*/
var tabLinea = document.getElementById(’miTabla’)
.insertRow(numeroLineas);
Solo falta introducir el contenido en las dos columnas (como anteriormente para la primera línea). Para la segunda
columna (numerada con 1), correspondiente a la potencia, el código es:
La tabla HTML después de esta inserción se presenta como sigue:
Este formulario no tiene sorpresas. Incluye un campo de entrada de datos (identificado por numLinea) y un botón
de llamada a la función eliminarLineaTabla.
/* Función eliminarLineaTabla */
function eliminarLineaTabla()
{
/*
Mostrar el número de la línea que se ha de eliminar
en la tabla
*/
var numeroLinea =
parseInt(document.getElementById(’numLinea’).value);
/* alert("Número de línea a eliminar: " + numeroLinea); */
/*
Mostrar el número de líneas de la tabla
*/
var numeroLineas =
parseInt(document.getElementById(’miTabla’).rows.length);
/* alert("Número de línea(s) de la tabla: " + numeroLineas); */
/*
Eliminación de la línea
*/
if ((numeroLinea >= 1) && (numeroLinea < numeroLineas))
{
/* Eliminación */
document.getElementById(’miTabla’).deleteRow(numeroLinea);
}
else
{
/* Número de línea errónea */
alert("Número de línea errónea");
}
}
Para que sea posible indicar si un número de línea es incorrecto (inferior a 1 o superior o igual al número de líneas),
se determina el número de líneas de la tabla:
var numeroLineas =
parseInt(document.getElementById(’miTabla’).rows.length);
La eliminación se realiza a través del método deleteRow como sigue:
document.getElementById(’miTabla’).deleteRow(numeroLinea);
Si se solicita la eliminación de la línea número 4, la visualización de la tabla se convierte en:
Terminamos nuestro ejemplo con un script en el que vamos a colorear las diferentes líneas de la tabla HTML con
JavaScript:
l la línea de título, en naranja,
l las líneas de datos con número par, en plata (silver),
l las líneas de datos con número impar, en blanco (white).
Siempre utilizaremos nuestra tabla HTML habitual (una línea de título y tres líneas de datos):
Modelo Potencia
Ferrari 512 BB 380
Lamborghini Miura 385
Porsche 964 3.6 360
El código HTML del formulario (sección <body>) que incluye los botones de llamada a las funciones JavaScript es el
siguiente:
Un primer botón <inputtype="button" ... > con identificador botonColorearTituloTabla llama a
una función de nombre colorearTituloTabla y un segundo botón <input
type="button" ... > con
identificador botonColorearLineasTabla llama a una función con nombre colorearLineasTabla.
Analicemos el código de la función colorearTituloTabla (sección HTML <head>):
/* Función colorearTituloTabla */
function colorearTituloTabla()
{
/* Mostrar el número de columnas de la tabla
(determinando el número de celdas de la línea de título)
*/
var numeroColumnas =
parseInt(document.getElementById(’miTabla’).rows[0].cells.length);
alert("Número de columna(s) de la tabla: " + numeroColumnas);
/*
Añadir en la tabla memoria (tabLinea) las celdas
de la línea número0 (título)
*/
var tabLinea =
document.getElementById(’miTabla’).rows[0].cells;
/*
Modificación del color de las celdas de la línea número0 (título) */
for ( numeroColumna = 0; numeroColumna<numeroColumnas; numeroColumna++)
{
/*
Color de la celda actual
en naranja (código RGB #FFA500)
*/
tabLinea[numeroColumna].bgColor = "#FFA500";
}
}
En primer lugar, se determina el número de columnas (calculando el número de celdas de la línea n°0):
Posteriormente, también como hemos visto en ejemplos anteriores, las celdas de la línea número 0 (línea de título)
se ubican en una tabla en memoria (tabLinea) como sigue:
var tabLinea=
document.getElementById(’miTabla’).rows[0].cells;
Solo falta utilizar un procesamiento iterativo (bucle for en nuestro código) para recorrer las celdas de esta tabla y
colorearlas (en naranja para el título) como sigue:
tabLinea[numeroColumna].bgColor = "#FFA500";
Terminemos por el código de la función colorearLineasTabla:
/* Función colorearLineasTabla */
function colorearLineasTabla()
{
/* Mostrar el número de líneas de la tabla
*/
var numeroLineas =
parseInt(document.getElementById(’miTabla’).rows.length);
alert("Número de línea(s) de la tabla: " + numeroLineas);
/*
Mostrar el número de columnas de la tabla
(determinando el número de celdas de la línea de título)
*/
var numeroColumnas =
parseInt(document.getElementById(’miTabla’).rows[0].cells.length);
alert("Número de columna(s) de la tabla: " + numeroColumnas);
/*
Color de las líneas (fuera del título)
alternativamente en silver/white
*/
for (i = 1; i<numeroLineas; i++)
{
/*
Añadir en la tabla memoria (tabLinea)
las celdas de la línea actual
*/
var tabLinea =
document.getElementById(’miTabla’).rows[i].cells;
/*
Modificación del color de las celdas
de la línea actual
*/
for ( numeroColumna=0; numeroColumna<numeroColumnas;
numeroColumna++)
Aquí, de nuevo, hay muchos puntos comunes con los ejemplos anteriores. Se determina el número de líneas de la
tabla HTML:
var numeroColumnas =
parseInt(document.getElementById(’miTabla’).rows[0].cells.length);
El número de columnas también se calcula como en la función colorearTituloTabla.
Posteriormente, un bucle for recorre las líneas de la tabla HTML, empezando con la línea número 1 (primera línea
de datos):
La línea actual se almacena en la tabla en memoria tabLinea, ya vista en la función mostrarTituloTabla:
var tabLinea =
document.getElementById(’miTabla’).rows[i].cells;
tabLinea[numeroColumna].bgColor = "silver";
y el color blanco (white), para las líneas con numeración impar:
Para los códigos de los colores, es posible utilizar el pseudónimo de los colores (orange, silver, white...) o el código
RGB asociado al color (# seguido de seis códigos hexadecimales; por ejemplo, #FFA500 para el color naranja).
La visualización de la tabla se presenta a continuación, después de la aplicación de las funciones de coloración del
título y de las líneas de datos:
El formato de datos XML (eXtensible Markup Language) es omnipresente en las aplicaciones informáticas. XML es un
lenguaje de marcado extensible. Este lenguaje se llama extensible porque permite crear extensiones con su propio
vocabulario y su gramática. Para que sirva como ejemplo, XHTML, XSLT, RSS son extensiones.
XML se utiliza principalmente para automatizar los intercambios de datos entre sistemas heterogéneos. Permite
definir conjuntos de datos complejos, como estructuras arborescentes.
Encontrará en Wikipedia una presentación muy completa de XML, en la dirección:
http://es.wikipedia.org/wiki/Extensible_Markup_Language
DOM, el modelo de acceso a los diferentes componentes de los documentos HTML e incluso XML, que hemos
estudiado en el capítulo Modelo DOM, va a ser la herramienta principal para recorrer los archivos XML.
En este capítulo, también veremos por primera vez cómo acceder a los archivos remotos con el objeto
XMLHttpRequest.
Para ilustrar las posibilidades en materia de exploración de flujo XML, se van a estudiar muchos ejemplos. En los
primeros, se ofrecerán comentarios detallados.
Además, las diferentes técnicas expuestas serán muy útiles cuando abordemos el almacenamiento remoto (capítulo
Almacenamiento remoto (Ajax PHP MySQL XML).
1. Ejemplo 1: Visualización del contenido de un mail codificado en XML
El objetivo en este primer ejemplo va a ser mostrar en HTML un flujo de datos XML recuperado en un sitio Web.
Archivo email.xml
El documento en cuestión (email.xml) tiene una estructura muy simple:
<email>
<de>María González-Aller</de>
<a>Ángel Sánchez</a>
<asunto>Importante</asunto>
<mensaje>Partido de tenis el sábado a las 10 horas</mensaje>
</email>
Como habrá comprobado, se trata de un mensaje de tipo mail (codificado aquí en XML) entre un autor (María
GonzálezAller) y un destinatario (Ángel Sánchez).
Sección HTML <body>
En el script HTML/JavaScript (llamado DOM_01.htm), el código de gestión del flujo XML se muestra íntegramente en
la sección HTML <body>.
El script empieza con la colocación en la página Web del mensaje XML. En realidad, el mensaje no aparece a este
nivel, sino que solo se trata de establecer una capa HTML (que incluye etiquetas span identificadas).
En general, la etiqueta <div> se emplea para contener y anotar otros elementos HTML (input, span...),
mientras que la etiqueta <span> se usa para enmarcar e identificar palabras o grupos de palabras.
El código implementado para la visualización del contenido del mail es el siguiente:
Cada elemento span está identificado, lo que permitirá registrar el mensaje con los datos efectivos leídos en el
archivo XML email.xml.
El script JavaScript se sitúa en esta misma sección HTML <body>, que se lista aquí íntegramente (más adelante, se
comentará en detalle):
</script>
El script empieza con la instanciación de un objeto de la clase XMLHttpRequest. Este objeto se llama xmlhttp y
en nuestro caso sirve para comunicar con el servidor remoto, en el que hay un archivo XML de nombre email.xml.
Observe que, para las versiones antiguas del navegador Microsoft Internet Explorer (versiones 6 y anteriores), hay
que recurrir a un objeto ActiveX y poner un objeto XMLHttpRequest.
Posteriormente, la apertura del archivo remoto se hace con el método open del objeto xmlhttp. El método open
l El método de acceso (GET o POST): en general, se utiliza el valor GET y es suficiente. El valor POST se reserva
para enviar argumentos voluminosos al servidor y cuando los argumentos se registran por un formulario.
l El nombre del archivo que se va a leer (email.xml en nuestro caso).
l El comportamiento síncrono o asíncrono de la consulta enviada al servidor, el modo síncrono (false) elegido en
nuestro caso, sirve para indicar que cualquier actividad del navegador se suspende durante la ejecución de la consulta
(este valor no es el valor aconsejado).
La consulta se envía a continuación al servidor por el método send, que aquí se utiliza sin argumentos.
La respuesta enviada por el servidor, es decir, el archivo XML, se asigna a continuación a una variable llamada
xmlDoc:
Esta variable se va a explotar con los métodos DOM para extraer el contenido útil.
Por ejemplo, para la recuperación del campo autor del mail, el código es:
Con el método DOM getElementsByTagName, se extrae del flujo XML el nombre del autor (María González-
Aller, en nuestro caso) y se asigna al elemento HTML llamado de.
La secuencia [0].childNodes[0].nodeValue indica que hace referencia al primer tag de nombre de del
documento y al valor de su primer hijo.
La visualización es la siguiente:
2. Ejemplo 2: Lista de marcas de coches (archivo coches.xml)
El objetivo en este primer ejemplo va a ser mostrar en HTML un flujo de datos XML recuperado de un sitio Web.
Archivo coches.xml
El documento coches.xml es el que se va a utilizar en el script del segundo ejemplo y también en el resto de los
ejemplos de este capítulo. Es el siguiente:
<coches>
<coche origen="ITALIA" grupo="FIAT">
<marca>FERRARI</marca>
<modelo>512 BB</modelo>
<motor>V12 FERRARI</motor>
<cilindrada>5</cilindrada>
<potencia>380</potencia>
<velocidad_punta>280</velocidad_punta>
<sitio_web>
http://es.wikipedia.org/wiki/Ferrari_Berlinetta_Boxer
</sitio_web>
</coche>
<coche origen="ITALIA" grupo="VOLKSWAGEN">
<marca>LAMBORGHINI</marca>
<modelo>MIURA</modelo>
<motor>V12 LAMBORGHINI</motor>
<cilindrada>3.9</cilindrada>
<potencia>385</potencia>
<velocidad_punta>280</velocidad_punta>
<sitio_web>
https://es.wikipedia.org/wiki/Lamborghini_Miura
</sitio_web>
<sitio_web>
http://en.wikipedia.org/wiki/Lamborghini_Miura
</sitio_web>
</coche>
<coche origen="ALEMANIA" grupo="VOLKSWAGEN">
<marca>PORSCHE</marca>
<modelo>964 TURBO</modelo>
<motor>FLAT 6 PORSCHE</motor>
<cilindrada>3.6</cilindrada>
<potencia>360</potencia>
<velocidad_punta>295</velocidad_punta>
<sitio_web>
https://en.wikipedia.org/wiki/Porsche_964
</sitio_web>
</coche>
</coches>
Sección HTML <body>
En este script, no hay zonas de visualización span en una capa HTML; la información simplemente se va a mostrar
en la página Web con el método document.write.
La secuencia de código empieza por la creación de una tabla en memoria, llamada marca, en la que se
almacenarán los nodos marca del archivo coches.xml:
Posteriormente, pasamos a la visualización:
Evidentemente, esta solución de visualización no es del todo satisfactoria porque depende del número de coches
(tres) del archivo XML coches.xml. Veremos en un ejemplo más adelante cómo resolver esta dificultad.
Cuando se ejecute, tendremos la siguiente visualización:
3. Ejemplo 3: Lista de las marcas de coches con un bucle
Habíamos indicado un límite molesto en el ejemplo anterior; veamos cómo salvar esta dificultad con un bucle.
El código es muy simple:
Después de recuperar los nodos marca en una tabla, es posible recorrer esta tabla con un bucle
for. Los
elementos de la tabla se enumeran de manera clásica de cero hasta marca.length - 1 (siendo length el
número de elementos de la tabla).
En cada pasada del bucle, la marca se mostrará con marca[i].childNodes[0].nodeValue, siendo i el
índice del bucle for.
La visualización obtenida es la siguiente:
Por lo tanto, es estrictamente idéntico al ejemplo anterior.
4. Ejemplo 4: Lista de nodos conectados a la raíz
El objetivo de este ejemplo es quizás de orden técnico. Se trata de conocer la lista de los nodos conectados a la raíz
y el nombre de esta raíz:
Se crea una tabla en memoria llamada listaNodosRaiz, con:
Esta tabla se recorre con un bucle for.
Una particularidad es que, para mostrar solo los nodos directamente conectados a la raíz, hay que prever una
comprobación del tipo de nodo, como sigue:
if (listaNodosRaiz[i].nodeType == 1)
La visualización se obtiene con:
Después de este bucle for, a título de ejemplo, el nombre y el tipo del nodo raíz (coches) también se muestran
en pantalla.
La indicación nodeType puede tomar los siguientes valores en un árbol DOM (fuente developer.mozilla.org):
l 1: Nodo elemento,
l 2: Nodo atributo,
l 3: Nodo texto,
l 4: Nodo de sección CDATA,
l 5: Nodo de referencia a una entidad,
l 6: Nodo de entidad,
l 7: Nodo de instrucción de procesamiento,
l 8: Nodo de comentario,
l 9: Nodo de documento,
l 10: Nodo de tipo de documento,
l 11: Nodo de fragmento de documento,
l 12: Nodo de notación.
5. Ejemplo 5: Lista de los campos (nodos) de cada coche
En este ejemplo, vamos a listar los campos (nodos) de cada coche.
En nuestro caso, obtendremos la siguiente visualización:
También hemos aprovechado este recorrido por los campos para mostrar los dos enlaces Web que describen el
segundo coche de nuestro archivo coches.xml.
Después de la creación del objeto XMLHttpRequest, el acceso al archivo XML coches.xml y la creación del
documento DOM en memoria, analizamos la secuencia de código específica de este ejemplo.
La primera secuencia tiene que ver con la lista de campos (nodos) de cada coche:
/*
Mostrar la lista de campos (nodos) de cada coche
NB: La lista se basa en la del primer coche
*/
/*Mostrar el título de la lista */
document.write("Lista de los campos (nodos) de cada coche:<br />")
/* Constitución de la lista de los nodos hijos
de coche (basada en el primer coche) */
listaCamposCoche =
xmlDoc.getElementsByTagName("coche")[0].childNodes;
/* Inicialización del valor del primer hijo (marca) */
campoCoche =
xmlDoc.getElementsByTagName("coche")[0].firstChild;
/* Recorrido de los hijos */
for (i=0; i<listaCamposCoche.length; i++)
{
/* Prueba el tipo del nodo para mostrar solo los nodos elementos */
/*
nodeType: 1 -> nodo elemento
nodeType: 2 -> nodo atributo
nodeType: 3 -> nodo texto
nodeType: 4 -> nodo de sección CDATA
nodeType: 5 -> nodo de referencia a una entidad
nodeType: 6 -> nodo de entidad
nodeType: 7 -> nodo de instrucción de procesamiento
nodeType: 8 -> nodo de comentario
nodeType: 9 -> nodo de documento
nodeType: 10 -> nodo de tipo de documento
nodeType: 11 -> nodo de fragmento de documento
nodeType: 12 -> nodo de notación
*/
if (campoCoche.nodeType == 1)
{
document.write(" - " + campoCoche.nodeName + "<br />");
}
/* Pasar al campo siguiente */
campoCoche = campoCoche.nextSibling;
}
Después de haber formado la lista de los nodos que dependen (hijos) del nivel coche, nos basamos en la primera
ocurrencia de coche como sigue:
listaCamposCoche =
xmlDoc.getElementsByTagName("coche")[0].childNodes;
campoCoche =
xmlDoc.getElementsByTagName("coche")[0].firstChild;
Solo falta recorrer los campos, usando el método nextSibling (pasando al nodo siguiente del mismo nivel).
Observe que hay que filtrar una vez más para mostrar solo en caso de nodo de tipo 1 (nodo elemento).
Una segunda secuencia posterior sirve para mostrar los dos enlaces Web, que describen el segundo coche:
/*
Mostrar el número de sitios Web que describen
el segundo coche (con número 1)
*/
document.write("<br />");
document.write("Lista de los sitios Web que describen el segundo coche:<br />")
listaCamposCoche = xmlDoc.getElementsByTagName("coche")[1].childNodes;
campoCoche = xmlDoc.getElementsByTagName("coche")[1].firstChild;
for (i=0; i<listaCamposCoche.length; i++)
{
if (campoCoche.nodeType == 1 && campoCoche.nodeName == "site_web")
{
document.write(" - " + campoCoche.nodeName + ": "
+ campoCoche.childNodes[0].nodeValue + "<br />");
}
/* Pasar al campo siguiente */
campoCoche = campoCoche.nextSibling;
}
Observe que el desarrollo es muy similar al del procesamiento anterior. La única diferencia está a nivel de la
comprobación:
6. Ejemplo 6: Sustitución de un valor de nodo
Aunque se trate de una operación menos frecuente, veamos cómo es posible modificar un valor en el documento
XML en memoria, después de su lectura desde el archivo coches.xml. El código está, una vez más, ubicado en la
sección HTML <body>:
No hay nada complicado en realidad. Después de haber detectado la primera ocurrencia de la etiqueta coche, es
suficiente con intervenir sobre el valor del nodo (nodeValue). A continuación, se realiza un control para comprobar
el impacto de la modificación.
Cuando se visualiza el script, obtenemos:
7. Ejemplo 7: Acceso a los atributos
Volvamos al contenido del archivo XML coches.xml:
<coches>
<coche origen="ITALIA" grupo="FIAT">
...
</coche>
<coche origen="ITALIA" grupo="VOLKSWAGEN">
...
</coche>
<coche origen="ALEMANIA" grupo="VOLKSWAGEN">
...
</coche>
</coches>
Veamos cómo acceder a los atributos origen y grupo de los diferentes coches:
El código está muy comentado y no necesita explicaciones adicionales. Solo señalemos que la propiedad
attributes devuelve una colección de atributos específicos del elemento dado.
La visualización obtenida cuando se ejecuta el script es la siguiente:
8. Ejemplo 8: Acceso a un nodo padre
Durante la navegación por un árbol XML, puede ser interesante acceder al nodo padre del nodo actual. Veamos
cómo realizar esta operación con una pequeña secuencia de código:
En nuestro ejemplo, recorremos la tabla en memoria marcasCoches, que contiene todos los nodos marca, con un
bucle for.
Con la instrucción marcasCoches[i].parentNode.nodeName, se recupera el nombre del nodo padre.
No es ninguna sorpresa descubrir que cada nodo marca tiene como padre el nodo coche:
Estudiemos también con un pequeño script cómo recorrer hacia atrás una lista de nodos (del último al primero):
En primer lugar, se construye la lista de los nodos hijos del tercer coche (numerado con 2):
listaCamposCoche =
xmlDoc.getElementsByTagName("coche")[2].childNodes;
Posteriormente, la ubicación en el último hijo se hace como sigue:
campoCoche = xmlDoc.getElementsByTagName("coche")[2].lastChild;
A continuación, tenemos una estructura iterativa con, esta vez, el uso del método previousSibling:
campoCoche = campoCoche.previousSibling;
10. Ejemplo 10: Sustitución sistemática de un valor de atributo
Recordemos los valores de atributos para nuestros tres coches:
<coches>
<coche origen="ITALIA" grupo="FIAT">
...
</coche>
<coche origen="ITALIA" grupo="VOLKSWAGEN">
...
</coche>
<coche origen="ALEMANIA" grupo="VOLKSWAGEN">
...
</coche>
</coches>
Es posible efectuar una sustitución sistemática de estos valores como sigue:
El método setAttribute aplicado a cada elemento de la tabla coche permite modificar el valor de este atributo.
Recordemos que coche es una tabla que reagrupa todos los nodos coche del archivo coches.xml.
La ejecución del script da la siguiente visualización:
11. Ejemplo 11: Conversión XML en HTML
Para hacer la visualización del flujo XML más sencilla, puede ser pertinente realizar una conversión en código HTML.
/*
Creación de la tabla HTML
*/
/* Etiqueta HTML de inicio de tabla */
document.write("<table border=’1’>");
/* Establece la línea de nombres de columnas */
document.write("<tr>");
document.write("<td>");
document.write("marca");
document.write("</td>");
document.write("<td>");
document.write("modelo");
document.write("</td>");
document.write("</tr>");
/* Recorrido de la lista de coches */
var coche = xmlDoc.getElementsByTagName("coche");
for (i=0; i<coche.length; i++)
{
/* Establece una nueva línea en la tabla HTML */
document.write("<tr>");
/* Apertura de la primera columna (marca del coche) */
document.write("<td>");
/* Escritura de la marca del coche */
document.write(coche[i]
.getElementsByTagName("marca")[0]
.childNodes[0]
.nodeValue);
/* Cierre de la primera columna */
document.write("</td>");
/* Apertura de la segunda columna (modelo del coche) */
document.write("<td>");
El script, un poco largo, no tiene ninguna dificultad. Una tabla coche se construye a partir de la lista de nodos
coche:
Después se recorre con un bucle for.
La recuperación de los dos valores de nodo (campo) para cada coche se obtiene como sigue:
document.write(coche[i]
.getElementsByTagName("marca")[0]
.childNodes[0]
.nodeValue);
document.write(coche[i]
.getElementsByTagName("modelo")[0]
.childNodes[0]
.nodeValue);
El resto del código está formado por el formato HTML de la tabla.
La tabla HTML tendrá la siguiente apariencia:
Nos falta ver cómo eliminar un nodo de un documento DOM en memoria.
El método removeChild es fácil de implementar.
En contrapartida, vamos a tener que desarrollar un ejemplo un poco más interesante para realizar una eliminación
de nodo.
Sección HTML <body>
En esta parte, se llama consecutivamente a tres funciones JavaScript, que estudiaremos más adelante:
La secuencia es muy lógica. En primer lugar, se lee el archivo XML coches.xml para formar nuestro árbol y
después se visualiza antes de la eliminación de un nodo controlado con un confirm (se trata del primer uso del
método confirm en este libro). Una vez que se ha realizado la eliminación, se vuelve a visualizar el árbol, como
veremos más adelante.
Sección HTML <head>
La primera función, cargarCoches, no tiene nada de nuevo:
/* Función cargarCoches */
function cargarCoches()
{
/* Creación de un objeto XMLHttpRequest para intercambiar datos
con el servidor en formato texto, XML o JSON
La función mostrarCoches retoma el código visto en el ejemplo anterior; por tanto, no se muestra aquí.
La tercera función, eliminarCoche, es más interesante:
/* Función eliminarCoche */
function eliminarCoche()
{
/* Mostrar el número de coche(s) antes del borrado */
alert("Número de coche(s) antes del borrado: "
+ xmlDoc.getElementsByTagName(’coche’).length);
/* Borrar el primer coche */
cocheEliminado = xmlDoc.getElementsByTagName("coche")[0];
xmlDoc.documentElement.removeChild(cocheEliminado);
/* Mostrar el número de coche(s) después del borrado */
alert("Número de coche(s) después del borrado: "
+ xmlDoc.getElementsByTagName(’coche’).length);
document.write("<br /><br />Lista de los coches después del borrado");
mostrarCoches();
/* Valor de retorno */
return true;
}
El borrado del primer coche se hace con la secuencia:
Esta función también llama a la función mostrarCoches cuando se hace la eliminación del primer coche, por
control:
Obtenemos esta visualización cuando se ejecuta el script:
Gracias a las cookies, es posible escribir en el puesto del usuario información de manera permanente. Sin esta
posibilidad, sería necesario recurrir a un lenguaje de programación "orientado a servidor" (PHP, Microsoft ASP.NET,
por ejemplo), para almacenar datos en un sistema de gestión básico de datos (MySQL, PosgreSQL...).
Las cookies, que se presentan como pequeños archivos de texto, pueden contener un número limitado de datos,
pero esta técnica puede ser muy valiosa para conservar contenidos de variables en memoria, reutilizables a lo largo
de la navegación a través de muchas páginas de su sitio Web (conservar identificadores, contraseñas (aunque esto
sea peligroso), preferencias de usuario...).
Observe que es posible impedir, en la gran mayoría de los navegadores, que se usen las cookies. Es cierto que esta
técnica es relativamente intrusiva. Un sitio Web podría, por ejemplo (si no se previene), almacenar en su disco duro
sus preferencias respecto a compras y consultas y, de esta manera, proponerle durante una sesión en Internet
posterior productos y servicios correspondientes a sus expectativas. En realidad, pocos usuarios bloquean el uso de
las cookies, porque una gran mayoría de sitios Web las usan (el bloqueo volvería casi imposible la navegación por el
sitio la mayor parte del tiempo).
Referencia: http://www.w3schools.com/js/js_cookies.asp
La creación de una cookie se hará a través de una función JavaScript, que vamos a crear (poco importa su nombre)
como sigue:
/* Mensaje de control */
document.write("La cookie miCookie (contiene Ediciones ENI) se ha escrito
correctamente en el disco duro");
La función creacionCookie tiene dos argumentos obligatorios: el nombre y el valor de la cookie.
El valor de la cookie puede contener caracteres especiales. La función JavaScript escape() permite sustituir estos
caracteres especiales (acentos...) por códigos hexadecimales. Evidentemente, cuando se lee la cookie, se realiza una
codificación inversa, con la función unescape().
Según la fuente developper.mozilla.org, las funciones escape y unescape permiten proteger las cadenas de
caracteres, codificando y descodificando los caracteres especiales. Con escape, cada carácter que se pueda
interpretar como un carácter especial se formatea con %NN, donde NN representa el valor hexadecimal del carácter en el
conjunto de caracteres ISO Latin 1 (ISO88591).
En caso de ausencia de este argumento opcional, la cookie será automáticamente eliminada al final de la sesión
(secuencia de código, en general de PHP, durante la cual la conservación de las cookies está prevista).
El argumento rutaCookie indica la ruta en el servidor. Con el valor /, la cookie será utilizable en todo el sitio Web.
Si el argumento no se indica o si es null, el valor por defecto será la URL de la página Web.
El argumento dominioCookie juega casi el mismo papel que rutaCookie, pero esta vez para el dominio
indicado.
Para terminar, es posible proporcionar un último argumento, relacionado con la seguridad. El argumento
securityCookie deberá ser igual a true para un uso en conexiones seguras https.
Cuando se ejecuta del script, obtenemos:
En primer lugar, nuestra función lee el contenido completo de la cookie. Posteriormente la función lecturaCookie
aísla el elemento deseado (el valor) para devolverlo.
El código (parcial) del script es el siguiente:
El script empieza comprobando la presencia del archivo cookie:
if (document.cookie.length == 0)
Si no se encuentra, se devuelve un valor null.
En caso contrario, el flujo de datos se almacena en una tabla de elementos de nombre tabElements, basándose
en la presencia de separadores de duplas "punto y coma" (uso de la función split). Solo falta trazar la primera
dupla (numerada con 0), que es la que nos interesa. Esta dupla tiene por nombre de elemento el nombre de la cookie
en sí misma, y como valor, el contenido (la cadena "Ediciones ENI"), en nuestro caso. Para aislar el nombre del
elemento y el contenido, se usan funciones de procesamiento de cadenas nativas, indexOf y substring. El valor
de retorno de la función lecturaCookie será, en este caso, el valor del elemento número 0 (primera dupla del
archivo cookie).
La visualización obtenida cuando se ejecuta el script es la siguiente:
La técnica utilizada para eliminar el archivo de cookie es básica. Es suficiente con crear de nuevo la cookie (como se
hace en la función creacionCookie) y poner una fecha de expiración anterior a la fecha de sistema (adición de un
plazo negativo, por ejemplo).
/* Mensaje de control */
document.write("La cookie miCookie se ha eliminado del disco");
El script no merece ningún comentario particular.
La ejecución del script genera la siguiente visualización:
En el capítulo anterior, hemos visto cómo almacenar pequeñas cantidades de información en las cookies (4 KB como
máximo).
Hay dos soluciones, llamadas Web Storage, que son alternativas al uso de cookies:
l el almacenamiento de la sesión,
l el almacenamiento local.
Como para las cookies, el almacenamiento con estas dos interfaces llamadas respectivamente sessionStorage y
localStorage se lleva a cabo en el lado navegador. Por tanto, no hay que confundir estas dos técnicas con un
almacenamiento remoto en base de datos. Además, en el próximo capítulo veremos cómo implementar este tipo de
soluciones usando el protocolo SOAP (Simple Object Access Protocol), una librería PHP dedicada NuSOAP y el sistema
de gestión de base de datos MySQL.
El Web Storage, también llamado DOM Storage, apareció con HTML 5. Sin embargo, este modo de almacenamiento es
aceptado por la gran mayoría de los navegadores.
La ventaja principal del Web Storage respecto a las cookies es la posibilidad de almacenar una mayor cantidad de
información (5 MB como máximo). Además, contrariamente a lo que sucede con las cookies, las interfaces
sessionStorage y localStorage no requieren tráfico HTTP en la red. Recordemos que las cookies se guardan
en el disco duro del usuario (por lo que es necesaria una transferencia HTTP), mientras que la información gestionada
por sessionStorage y localStorage son locales (sin transferencia HTTP).
1. Almacenamiento con sessionStorage
La persistencia de datos está limitada a la duración de la sesión del usuario; los datos solo se conservan para la
ventana activa (o la pestaña). Los datos almacenados solo se pueden recuperar a través del navegador que los ha
almacenado.
Es necesario observar que, en la descarga del almacenamiento con sessionStorage (también es cierto para
localStorage), los datos no se cifran y esto puede tener un impacto en los datos almacenados en un puesto de
trabajo utilizado por varios usuarios.
Cuando se cierra el navegador, los datos se eliminan.
2. Almacenamiento con localStorage
La interface localStorage es muy parecida a la anterior. La persistencia se gestiona de manera diferente. A
priori, no hay límite temporal al almacenamiento. Los datos se conservan más allá del cierre de la ventana activa (o
de la pestaña). También es posible utilizar los datos almacenados en varias ventanas (o pestañas) de un mismo
dominio. Como para el almacenamiento con sessionStorage, el mecanismo necesita utilizar el mismo navegador.
Evidentemente, como para sessionStorage, existen dos métodos dedicados para eliminar los datos guardados
bajo demanda.
1. Ejemplo 1: Almacenamiento por localStorage de cadenas de caracteres
En este primer ejemplo, el objetivo va a ser estudiar las posibilidades que ofrece localStorage en la gestión
(creación, acceso y eliminación) de información de tipo cadenas de caracteres.
Script completo
El código fuente del script se muestra completo a continuación:
<!--
NOMBRE DEL SCRIPT: LOCAL_STORAGE_01.htm
REALIZACIÓN INFORMÁTICA: Christian VIGOUROUX
FECHA DE CREACIÓN: 01/01/2014
FECHA DE ÚLTIMA MODIFICACIÓN: 01/01/2014
OBJETIVO: Almacenamiento usando localStorage
-->
/* Función escribirLocalStorage */
function escribirLocalStorage()
{
/* Verifica posibilidades de usar localStorage */
/* Función leerLocalStorage */
function leerLocalStorage()
{
/* Función eliminarLocalStorage */
function eliminarLocalStorage()
{
</head>
</script>
</body>
</html>
Formulario con tres botones
El primero (id="botonEscritura") ejecuta una función llamada escribirLocalStorage, que sirve para
almacenar tres datos (nombre, apellido y dirección de mail de una persona en un sistema de almacenamiento
localStorage).
Para terminar, el último botón (id="botonEliminacion"), a través de la función eliminarLocalStorage,
eliminará los datos almacenados en el sistema de almacenamiento.
Visualización del contenido del localStorage
También se muestra el contenido del sistema de almacenamiento en el formulario:
Función JavaScript escribirLocalStorage
En la función escribirLocalStorage, se realiza una comprobación para saber si el navegador soporta la
gestión de un localStorage:
En caso favorable, almacenamos consecutivamente la información en el localStorage (caso para
nombrePersona siguiente):
Evidentemente, en una aplicación más realista, los datos no serían solo constantes, sino, por ejemplo, datos de
formulario o incluso resultados de cálculo.
Como se indica al inicio de la presentación de este ejemplo, también tenemos una actualización de tres campos
<span> ... </span> en el formulario, con tres botones para mostrar el contenido de nuestro localStorage:
/* Visualización de control */
document.getElementById("nombrePersona").innerHTML = nombrePersona;
Función JavaScript leerLocalStorage
Como en la función escribirLocalStorage, se comprueba la capacidad del navegador para gestionar un
localStorage.
Una vez que el contenido del almacenamiento localStorage se lee, como para la función
escribirLocalStorage, se actualizan los tres campos <span> ... </span>.
Función JavaScript eliminarLocalStorage
El objetivo de esta última función es eliminar completamente el contenido del sistema de almacenamiento
localStorage.
También se hace una comprobación de la capacidad del navegador para gestionar un localStorage.
En el script que se ha presentado, se utiliza el método removeItem del objeto localStorage para cada uno de
los datos que se han de eliminar.
También es posible eliminar completamente el sistema de almacenamiento localStorage con el método
Session Storage.clear();.
Resultado de la ejecución
Un clic en el botón Escritura en localStorage provoca la siguiente visualización:
Después de la lectura del contenido del localStorage, la visualización se convierte en:
2. Ejemplo 2: Almacenamiento en el localStorage de un objeto JavaScript
En este segundo ejemplo, el objetivo es asegurar con funciones JavaScript la grabación de la información (nombre,
apellido y mail de una persona), en un sistema de almacenamiento localStorage. Pero, esta vez, los tres datos
se guardarán en un objeto JavaScript. Para asegurar el almacenamiento, tendremos que recurrir a una serialización
JSON y a la inversa; para recuperar los valores será necesario una deserialización.
Script completo
El código fuente del script se muestra completo a continuación:
<!--
NOMBRE DEL SCRIPT: LOCAL_STORAGE_02.htm
REALIZACIÓN INFORMÁTICA: Christian VIGOUROUX
FECHA DE CREACIÓN: 01/01/2014
FECHA DE ÚLTIMA MODIFICACIÓN: 01/01/2014
OBJETIVO: Almacenamiento usando localStorage y JSON
-->
/* Función escribirLocalStorage */
function escribirLocalStorage()
{
/* Prueba posibilidades de usar localStorage y JSON */
if (typeof localStorage != "undefined" && JSON)
{
/* Definición de un objeto JavaScript
datosContactoPersona */
var datosContactoPersona =
{
nombre: document.getElementById("nombre").value,
apellidos: document
.getElementById("apellidos").value,
mail:document.getElementById("mail").value
};
/* Serialización en un objeto JSON
de nombre identidad */
localStorage.setItem("identidad",
JSON.stringify(datosContactoPersona));
alert("Registro en localStorage terminado");
}
else
{
/* Mensaje de error (sin posibilidades
de almacenamiento localStorage) */
alert("localStorage no soportado");
}
};
/* Función eliminarLocalStorage */
function eliminarLocalStorage()
{
/* Prueba posibilidades de usar localStorage y JSON */
if (typeof localStorage != "undefined" && JSON)
{
/* Eliminación de la entrada identidad
en el localStorage */
/* NB: sessionStorage.clear(); eliminará
también las entradas
del localStorage */
</script>
</head>
</script>
</script>
</body>
</html>
Introducción de los datos que se van a guardar en el localStorage
En este script, más evolucionado que el del ejemplo número 1, se le propone al usuario una entrada de datos para
que pueda introducir los datos (nombre, apellidos y mail de una persona) y almacenarlos en el sistema de
almacenamiento localStorage:
Formulario de llamada a las funciones JavaScript
La ejecución de las tres funciones se realiza con un formulario con tres botones:
Una pequeña particularidad en este script es que las funciones escribirLocalStorage y
eliminarLocalStorage están en la sección HTML <head> ... </head>, mientras que la función de lectura
no se llama explícitamente y se ubica en la sección HTML <body> ... </body> en el mismo formulario.
Ahora, estudiemos en detalle cada una de estas funciones.
Función escribirLocalStorage
En la función escribirLocalStorage, el código empieza comprobando la posibilidad de utilizar el
localStorage en el navegador:
Observe que el código es ligeramente diferente al ya visto en el ejemplo número 1. Se hace una comprobación
adicional sobre la compatibilidad con JSON.
Encontrará una definición completa de JSON en el sitio oficial: http://www.json.org/
Ahora veamos la secuencia de código para la creación de un objeto JavaScript datosContactoPersona
construido a partir de tres campos de entrada de datos ( <input tipo="text" ... >):
Los objetos JavaScript no se pueden guardar como tal en un sistema de almacenamiento localStorage porque
solo se pueden tener en cuenta cadenas de caracteres.
Conviene transformar nuestro objeto datosContactoPersona en una cadena de caracteres antes del
almacenamiento. Esta operación se llama serialización JSON.
En los lenguajes Web, como JavaScript o PHP, la serialización consiste en transformar una variable compuesta (como
una tabla o un objeto) en una cadena de caracteres.
El código para realizar esta operación es el siguiente:
El método setItem se usa una única vez, los tres datos se añaden a una cadena de caracteres única
(identidad). La serialización queda asegurada con el método stringify.
Los navegadores recientes (incluido Microsoft Internet Explorer desde su versión 8) soportan la función
JSON.stringify.
Para que sirva de ejemplo, consideremos los siguientes datos:
l Nombre: Ángel
l Apellido: Sánchez
l Mail: [email protected]
la serialización daría como resultado:
{
"nombre":"Ángel",
"apellido":"Sánchez",
"mail":"[email protected]"
}
Función eliminarLocalStorage
En esta función, el código también empieza comprobando la posibilidad de utilizar el localStorage y JSON en el
navegador.
La eliminación del item identidad, guardado con la función escribirLocalStorage, se realiza como sigue:
También se hace un borrado de los campos de visualización:
Lectura de los datos desde localStorage
La sintaxis:
document.getElementById(’botonLectura’).onclick = function() {
/* ... */
}
asociada al botón identificado por botonLectura, se ejecuta una función (sin nombre en este caso), al hacer clic
en el botón.
En el código de la función, encontrará la comprobación habitual de la posibilidad de utilizar el localStorage y
JSON en el navegador.
Posteriormente, se hace la deserialización del objeto JSON almacenado en el sistema de almacenamiento
localStorage como sigue:
JSON.parse() realiza un procesamiento inverso al de la función JSON.stringify(). El método espera como
argumento una cadena de caracteres JSON (identidad en nuestro caso) y la transforma en un objeto JavaScript.
Esta transformación se llama deserialización.
También se hace una actualización de los campos de visualización:
Empecemos introduciendo los tres campos de entrada de datos como está previsto y validemos con un clic en el
botón ’ Escritura en localStorage ’:
A continuación, borremos los campos de entrada de datos:
En los dos capítulos anteriores, hemos visto cómo almacenar datos en el puesto cliente, a través de cookies y objetos
de Web Storage (sessionStorage y localStorage).
Estas soluciones son satisfactorias para la persistencia de datos a pequeña escala (grabación de argumentos útiles
durante la navegación entre las páginas de un mismo sitio Web, almacenamiento de las preferencias de usuario...).
También es posible recurrir a objetos de Web Storage para realizar una entrada de datos en modo no conectado, con
una sincronización con el servidor cuando se restablece la conexión.
Es preferible la solución de persistencia con un almacenamiento de datos centralizado en un servidor remoto (si es
preciso, con un complemento en Web Storage). La aplicación es evidentemente más compleja. Este es el objetivo de
este capítulo.
El objetivo, por tanto, va a ser poder acceder a los datos almacenados en un sistema gestor de bases de datos
(SGBD) MySQL, con los protocolos HTTP y SOAP, a través de una librería de funciones PHP NuSOAP.
En los dos ejemplos que se van a comentar, se ha hecho una elección arbitraria a nivel del SGBD, MySQL. Para la
librería NuSOAP, la observación es la misma. No obstante, la programación es muy genérica y no tendrá dificultades
para hacer una aplicación personal en sus propios proyectos, incluyendo diferentes SGBD.
Se van a presentar dos ejemplos completos de aplicación.
Para estos ejemplos, se utilizará una tabla llamada coches, con tres campos:
l codigo_coche de cuatro caracteres (código del coche).
l nombre_coche de 20 caracteres (nombre del coche).
l velocidad_maxima número en entero (velocidad máxima que puede alcanzar el coche, en un circuito, claro).
En sus propios ejemplos, no podrá utilizar la base de datos que se usa en los ejemplos del libro. El identificador y la
contraseña están ocultos en las reproducciones de los códigos "fuente" que siguen a continuación.
Por tanto, tendrá que disponer de un SGBD MySQL al que pueda acceder. La obtención o reserva de un acceso a un
servidor de este tipo queda fuera del marco de este libro.
Por lo tanto, para que pueda comprobar los ejemplos, tendrá que desarrollar una tabla llamada coches en su
servidor MySQL e introducir el identificador y la contraseña de conexión en los scripts.
Para facilitar el despliegue, se proporciona un script SQL de creación de la tabla coches. Tendrá que ejecutarlo en la
ventana SQL de su interfaz de administración MySQL (PHPMyAdmin, normalmente).
También se proporciona un conjunto de datos de prueba para la explotación de los ejemplos. Puede ejecutar el
siguiente script para rellenar su tabla coches:
Los dos scripts SQL, así como todos los scripts de los ejemplos de este libro, se pueden descargar gratuitamente
desde la página Información.
1. Ejemplo 1: Acceso Ajax sobre BDD MySQL (lista de los coches)
En un primer ejemplo, se recupera la lista de todos los registros de una tabla MySQL llamada coches.
l un script HTML (que contiene las secuencias de código JavaScript), llamado cliente_ws_01.htm,
l un script PHP llamado servidor_ws_01.php,
l un script PHP nusoap.php,
l una tabla MySQL llamada coches (mencionada anteriormente).
Para poder utilizar estos scripts en sus propios ejemplos, los archivos cliente_ws_01.htm,
servidor_ws_01.php y nusoap.php se deberán ubicar en su cliente FTP habitual (Mozilla Filezilla, por
ejemplo), en un directorio (por ejemplo, de nombre js_nusoap) de su servidor Web.
De nuevo, la obtención o reserva de un acceso a un espacio de publicación Web está fuera del marco de este libro.
La primera miniaplicación que se va a presentar también es un buen ejemplo de lo que se llama comúnmente Ajax
(Asynchronous JavaScript and XML).
Ajax agrupa un conjunto de tecnologías (JavaScript, XML, CSS, XML, DOM y XMLHttpRequest), que permiten construir
aplicaciones Web dinámicas que usen bases de datos y tengan "interfaces de usuario" ricas (RIA).
DOM y JavaScript sirven para modificar la información presentada en el navegador.
El objeto XMLHttpRequest se usa para asegurar los intercambios de datos con el servidor Web de modo
asíncrono.
XML estructura los flujos de datos entre el servidor Web y el navegador. Se pueden utilizar otras tecnologías, como
JSON en lugar de XML, para codificar los flujos de datos entre el servidor Web y el navegador.
Normalmente, Ajax es compatible con los principales navegadores, como Microsoft Internet Explorer, Mozilla Firefox,
Google Chrome, Konqueror e incluso Opera.
En nuestro ejemplo, se van a utilizar la gran mayoría de las tecnologías agrupadas en Ajax:
l un script cliente (HTML + JavaScript) preparará un mensaje SOAP/XMLHttpRequest, con destino una aplicación de
servidor escrita en PHP,
l el script servidor accederá a una base de datos almacenada en un SGBD MySQL,
l con una librería dedicada (NuSOAP), la respuesta (los registros correspondientes a una extracción SQL), es decir, un
flujo XML, se enviará a la aplicación cliente,
l la aplicación cliente, con métodos JavaScript de procesamiento del DOM, recuperará los datos para la visualización.
Este ejemplo basado en Ajax es, por tanto, relativamente completo; solo falta tratar el CSS (dar formato, con una
hoja de estilo, a los datos recuperados por el script cliente) y JSON (en nuestro caso, se ha seleccionado el formato
XML para la estructura del mensaje de retorno del servidor). Tendremos la ocasión de descubrir el formato JSON en
una serie de ejemplos, que se presentarán en el próximo capítulo.
SOAP es un protocolo orientado a objetos construido sobre XML que permite la transmisión de mensajes entre
aplicaciones remotas. Con este protocolo, un objeto puede invocar métodos de objetos físicamente situados en otros
servidores. La transferencia de mensajes SOAP se hace habitualmente con el protocolo HTTP.
Pasemos ahora al estudio detallado de estos diferentes scripts.
Puede obtener esta librería PHP descargándola desde el sitio web http://sourceforge.net/projects/nusoap/
Para nuestros dos ejemplos, solo es necesario el script nusoap.php. Por tanto, será necesario extraerlo del
paquete (archivo comprimido) obtenido o buscarlos en los scripts que acompañan este libro, disponibles en el sitio
Web de Ediciones ENI.
El script
nusoap.php se deberá situar en el mismo directorio que los scripts cliente_ws_01.htm y
servidor_ws_01.php (por ejemplo, js_nusoap).
El comentario del contenido del archivo nusoap.php no está previsto en el marco de este libro. Sin embargo, debe
saber que este archivo, de unas 6.000 líneas de código, contiene más de cien funciones.
Script HTML cliente_ws_01.htm
</script>
Pasemos ahora a lo más importante, el estudio detallado de las funciones JavaScript, que permiten la recuperación
de los datos y su procesamiento.
Función llamadaServidorRemoto
El objetivo de la primera función, llamada llamadaServidorRemoto, es:
l preparar una consulta SOAP, que se enviará al servidor remoto (servidor Apache en nuestro caso),
l esperar el procesamiento en el lado servidor,
l recuperar la respuesta del servidor remoto (respuesta en formato XML en nuestro caso),
l deserializar la respuesta XML,
El código completo de esta función es el siguiente:
/* Función llamadaServidorRemoto */
function llamadaServidorRemoto()
{
/*
Aplicación del método overrideMimeType
para indicar una respuesta del servidor SOAP
en formato texto o XML
*/
if (httpRequest.overrideMimeType)
{
httpRequest.overrideMimeType("text/xml");
}
/*
Envío de la consulta SOAP al servidor
con un timeout de 60000 ms (es decir 60 segundos)
NB: La consulta será errónea una vez alcanzado el plazo de espera
*/
httpRequest.send(mensajeSOAP);
valTimeout = setTimeout("timeout(httpRequest);", 60000);
/*
Parseo y copia de la respuesta en la capa HTML resultado,
proporcionada por el servidor SOAP
*/
httpRequest.onreadystatechange = parsearDOM;
}
La primera parte (la más compleja), consiste en preparar el mensaje SOAP, que se va a enviar al servidor remoto.
Sin ser exhaustivos sobre los diferentes elementos que hay que integrar en este envelope SOAP (término utilizado
para hacer referencia al mensaje), observemos los dos puntos en los que debe intervenir en caso de reutilizar el
código de esta función en sus desarrollos personales.
En primer lugar, en el script que se ha presentado, listarCoches es un método integrado en el script
servidor_ws_01.php, que estudiaremos más tarde.
Posteriormente, aunque no sea obligatorio, también puede personalizar el nombre de dominio en esta misma línea
de código:
xmlns:ns1="http://angel.sanchez.online.es"
Para el resto de los elementos que forman el envelope SOAP, diríjase a la Wikipedia
(http://es.wikipedia.org/wiki/SOAP) o incluso a la página en español del W3C sobre este tema en concreto
(http://www.w3c.es/Traducciones/es/TR/2003/RECsoap12part020030624/).
Una vez que el envelope SOAP está preparado, conviene instanciar un objeto XMLHttpRequest, que permitirá la
comunicación con el servidor remoto.
De nuevo, para obtener una explicación más completa de la noción de XMLHttpRequest, puede dirigirse a la
Wikipedia (http://es.wikipedia.org/wiki/XMLHttpRequest).
En resumen, XMLHttpRequest es un objeto ActiveX o JavaScript que permite obtener datos en formato XML,
/*
Instanciación de un objeto de tipo XMLHttpRequest
NB: XMLHttpRequest es un objeto ActiveX o JavaScript
que permite obtener datos en formato XML, JSON,
pero también HTML, incluso texto simple
con consultas HTTP.
*/
if (window.XMLHttpRequest)
{
// Código para IE7+, Firefox, Chrome, Opera, Safari
httpRequest = new XMLHttpRequest();
}
else
{
// Código para IE6, IE5
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
Posteriormente, se envía una consulta de conexión al servidor:
El método open del objeto httpRequest instanciado anteriormente se utiliza con tres argumentos:
l POST
l url
l true
El argumento POST sirve para indicar que la URL que se pasa al servidor, no tiene argumentos (en caso contrario,
se usaría el argumento GET). Es necesario indicar que, en materia de seguridad, el paso de argumentos a un
servidor utilizando la URL es una técnica poco fiable.
El argumento url contiene la URL del script servidor solicitado (servidor_ws_01.php, en nuestro caso). El valor
se ha configurado al inicio del script:
El tercer argumento indica que nuestra consulta es asíncrona. Si el valor fuera true, la ejecución de la función
JavaScript esperaría la llegada de la respuesta del servidor. Esta es la primera A de AJAX.
La secuencia de código siguiente sirve para indicar que la respuesta que se espera del servidor es de tipo texto o
XML (XML en nuestro caso, como veremos más adelante):
/*
Aplicación del método overrideMimeType,
para indicar una respuesta del servidor SOAP
en formato texto o XML
*/
if (httpRequest.overrideMimeType)
{
httpRequest.overrideMimeType("text/xml");
}
Solo falta añadir a nuestro mensaje SOAP una indicación respecto al Content-Type:
/*
Preparación del encabezado del mensaje SOAP
(Content-Type con valor text/xml)
NB: Cf https://en.wikipedia.org/wiki/
List_of_HTTP_header_fields
para el resto de los argumentos posibles
*/
httpRequest.setRequestHeader("Content-Type", "text/xml");
Como se indica en el comentario del script, si lo desea encontrará una explicación detallada de la noción de Content
Type en el sitio de Wikipedia (https://en.wikipedia.org/wiki/List_of_HTTP_header_fields ).
Es ahora cuando la consulta se puede enviar al servidor y también se puede hacer una gestión de timeout:
/*
Envío de la consulta SOAP al servidor
con un timeout de 60000 ms (es decir 60 segundos)
NB: La consulta será errónea una vez alcanzado el plazo de espera
*/
httpRequest.send(mensajeSOAP);
valTimeout = setTimeout("timeout(httpRequest);", 60000);
Esta función termina llamando a la función parserDOM como sigue:
/*
Parseo y copia de la respuesta en la capa HTML resultado,
proporcionada por el servidor SOAP
*/
httpRequest.onreadystatechange=parserDOM;
Recordemos que el evento onreadystatechange permite ejecutar un procesamiento (la función parserDOM en
nuestro caso) en cada cambio de valor del indicador readyState asociado al objeto httpRequest. Para que
sirva como ejemplo, los valores de este indicador pueden ser:
l 0: La consulta no se ha inicializado,
l 1: La conexión con el servidor se ha establecido,
l 2: La consulta se ha recibido por el servidor,
l 3: El procesamiento está en curso en el servidor,
l 4: La consulta ha terminado.
Función parserDOM
Esta función se llama por la función anterior (llamadaServidorRemoto).
En el código de esta función, vamos a implementar por primera vez en este libro una instrucción particular, el
try ... catch.
El bloque try (siempre presente por definición) puede tener muchas instrucciones. Para el procesamiento de las
excepciones, puede haber varios catch consecutivos (incluso ninguno). También es posible prever, en último lugar,
después de la serie catch, un último bloque llamado finally, en el que se integrarán instrucciones
sistemáticamente ejecutadas antes de la ejecución de las siguientes instrucciones del programa.
Antes de pasar a estudiar detalladamente la función parserSOAP, veamos un ejemplo completo de la aplicación de
try ... catch:
Este ejemplo empieza con una función (comprobarDia) que devuelve el nombre del día, correspondiente a un
número de día, que se pasa como argumento (o un mensaje de error si el número no es válido):
/*
Declaración de una tabla de nombres de días de la semana
*/
var tablaDias = new Array("Lunes", "Martes", "Miércoles",
"Jueves", "Viernes", "Sábado", "Domingo");
Ahora se llama a esta función como sigue:
Se declara una variable numDia y se inicializa con el valor 8, lo que nos debería dar un problema, porque solo
existen 7 días en la semana.
En el bloque try, se efectúan dos intentos de recuperación del nombre del día de la semana.
En el primer caso (alert(comprobarDia(numDia));) el resultado mostrará el mensaje " Error en el
número del día", previsto en el else de la función comprobarDia.
En el segundo caso, se ha cometido un error de programación, porque se llama a una función que no existe, de
nombre verificacionDia. Por tanto, el catch va a cumplir su función y mostrará un mensaje de error
relacionado con esta anomalía (ReferenceError: verificacionDia is not defined).
/* Función parsearDOM */
function parsearDOM()
{
try
{
/* Prueba si la consulta ha terminado y satisfactoriamente */
if (httpRequest.readyState == 4)
{
/* Prueba estado OK para la consulta http */
if (httpRequest.status == 200)
{
/* Establece el timeout */
clearTimeout(valTimeout);
/* Recuperación de la respuesta */
var text = httpRequest.responseText;
// alert("texto: " + text);
/*
Elección del parser para descodificar el flujo XML enviado
por el servidor
*/
if (window.DOMParser)
{
/* Parser para IE7 y versiones posteriores,
Firefox,Chrome, Opera, Safari
*/
parsear = new DOMParser();
/* Recuperación del flujo a parsear */
xmlDoc = parsear.parseFromString(text, "text/xml");
}
else
{
/* Parsear para IE6 y versiones anteriores */
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
/*
La recuperación del flujo deberá ser completa antes
del inicio del parseo
*/
xmlDoc.async = "false";
/* Recuperación del flujo a parsear */
xmlDoc.loadXML(text);
}
/* Parseo
NB: El servidor SOAP envía los valores leídos en la
tabla MySQL coches en un flujo XML, con etiqueta
<item> ... </item>
*/
var html = "";
// alert("Número de campos en el flujo XML: "
// +xmlDoc.getElementsByTagNamed("item").length);
for (i=0; i<xmlDoc.getElementsByTagName("item")
l una primera verificación comprueba si la consulta ha terminado (httpRequest.readyState == 4),
l una segunda prueba verifica el estado de la respuesta.
El atributo readyState del objeto httpRequest puede tomar los siguientes valores:
l 0: Consulta no inicializada,
l 2: Consulta cargada,
l 3: Consulta en proceso de interacción,
l 4: Consulta terminada.
Normalmente, solo se debe aceptar el valor 4 para el atributo readyState.
La segunda comprobación se hace sobre el código de estado ( status) de la respuesta http proporcionada por el
servidor. Los valores posibles de este código están en el sitio del W3C ( http://www.w3.org/Protocols/rfc2616/rfc2616
sec10.html). En nuestro caso, solo se acepta el caso de un estado " 200 OK.".
Posteriormente, se aplica un timeout con el método clearTimeout. El argumento valTimeout es una
variable declarada al inicio de script e inicializada a null:
/* Establece el timeout */
clearTimeout(valTimeout);
La siguiente secuencia es la recuperación de la respuesta enviada por el servidor:
/* Recuperación de la respuesta */
var text = httpRequest.responseText;
La respuesta se almacena en una variable text (declarada para la ocasión) para recuperar el valor del atributo
responseText del objeto httpRequest.
Para que sirva como ejemplo (por supuesto, depende de los datos almacenados en la tabla MySQL coches),
cuando se ejecuta, la respuesta del servidor es:
l V001, Porsche 930 y 290 para el primer registro,
l V002, Porsche 964 y 300 para el segundo registro,
l V003, Ferrari 430 y 320 para el tercer registro.
La elección del nombre de la etiqueta viene impuesta por la librería NuSOAP, de la que hablaremos más adelante.
Por supuesto, sería posible encontrar, mediante un procesamiento de cadenas muy sofisticado, los valores de los
campos. No obstante, como la respuesta del servidor SOAP se formaliza en un flujo XML, va a ser posible
automatizar la recuperación de los valores de los campos con un dispositivo dedicado, que explota el modelo DOM
de este flujo.
Para esta operación de transformación, hay que tener en cuenta el navegador. Para los navegadores recientes y
para Microsoft Internet Explorer versiones 7 y posteriores, será necesario recurrir al objeto DOMParser, integrado
de manera nativa. Para las versiones antiguas de Microsoft Internet Explorer, se deberá utilizar un objeto ActiveX
Microsoft.XMLDOM.
En cada caso, el flujo XML se almacena en un objeto llamado xmlDoc, que se deberá parsear.
También hay una pequeña particularidad para los navegadores antiguos (IE6 y versiones anteriores). El parseo no
debe empezar antes de que el flujo XML esté totalmente disponible ( xmlDoc.async = "false";).
Llegamos a una etapa crucial del procesamiento, el parseo:
/*
Parseo */
/* NB: El servidor SOAP envía los valores leídos
El resultado del parseo se almacena en una variable llamada html. Un bucle for recorre el flujo y genera
progresivamente el resultado.
En nuestro ejemplo, con tres coches caracterizados cada uno por tres campos ( codigo_coche, nombre_coche y
velocidad_maxima), la instrucción:
xmlDoc.getElementsByTagName("item").length
dará como resultado 9.
El código:
xmlDoc.getElementsByTagName("item")[i].childNodes[0].nodeValue
representa el valor del hijo directo de cada ítem.
Una comprobación (con una operación de módulo) permite personalizar cada línea integrada en la variable html.
Concretamente, durante la primera vuelta del bucle for (i que vale 0), se utiliza "Código: " como prefijo.
Posteriormente, este resultado (la variable html) se envía a pantalla dentro de una capa HTML como sigue:
Teniendo en cuenta los datos integrados en el flujo XML, la visualización será la siguiente:
Código: V001
Nombre: Porsche 930 Turbo
Velocidad máxima: 290
Código: V002
Nombre: Porsche 964 Turbo
Velocidad máxima: 300
Código: V003
Nombre: Ferrari 430
Velocidad máxima: 320
Script PHP servidor_ws_01.php
Solo falta estudiar el código del script del lado servidor, que se ocupa de recuperar los datos en una tabla
(coches), alojada en una base de datos MySQL y que transmite un flujo XML al script cliente_ws_01.htm,
cuyo código acabamos de estudiar.
Evidentemente, con este script no se pretende formarle en el desarrollo de aplicaciones utilizando el lenguaje de
programación PHP, en el que está escrito.
Sin embargo, se ha hecho un esfuerzo particular, fundamentalmente introduciendo comentarios, para que este
script sea comprensible por principiantes en PHP. Se resaltarán los puntos que necesitarán una modificación para su
posterior reutilización en un proyecto personal.
A continuación, ofrecemos la transcripción completa del código de este script. Más adelante, se darán explicaciones
más detalladas.
<?php
/*
NOMBRE DEL SCRIPT: server_ws_01.php
REALIZACIÓN INFORMÁTICA: Christian VIGOUROUX
FECHA DE CREACIÓN: 01/01/2014
FECHA DE ÚLTIMA MODIFICACIÓN: 01/01/2014
OBJETO: Listado de coches de deporte con un WebService
(retorno de campos en formato XML)
*/
// Método listarCoches
function listarCoches()
{
}
}
Seguramente, una primera lectura del script le habrá tranquilizado respecto a la sintaxis propia de PHP. Hay muchas
similitudes con JavaScript, fundamentalmente a nivel de las estructuras de control (while { ... }, if
(condición) { ... }, ...).
Para la nomenclatura de las variables en memoria, observe algunas particularidades:
l los nombres de las variables deben empezar por un $,
l no es necesario declarar (antes del uso) las variables.
Debe saber también que, en general, el código PHP, como el JavaScript, se inserta en las secuencias de código
HTML. Para pasar alternativamente de un código HTML a un código PHP dentro de un mismo script (que no es el
caso en nuestro ejemplo), hay que utilizar:
l <?php para indicar el inicio de una secuencia PHP,
l ?> para indicar el final de una secuencia PHP (pasando a HTML o incluso a JavaScript).
La extensión del nombre del script está normalizada (controlada por una directiva del servidor Apache) y es en
general .php e incluso .php, seguida del número de la versión de PHP utilizada (PHP 5, en nuestro caso).
Revisemos las principales instrucciones de este script y, en particular, las modificaciones que debería realizar para
reutilizarlo.
La primera secuencia de código sirve para integrar en el script PHP la librería de funciones/métodos nusoap.php
(este script está en el mismo directorio que el script servidor_ws_01.php).
Posteriormente, se instancia un objeto de nombre $servidor_soap a partir de la clase NuSOAP soap_server.
La secuencia siguiente declara un método de nombre listarCoches. Este método ya lo conocemos; lo habíamos
visto en la construcción del mensaje SOAP en el script cliente_ws_01.htm.
En el marco de la reutilización del código de este script servidor, el nombre de este método podría ser diferente.
Pasemos ahora a la descripción del método listarCoches.
Encontrará una sintaxis idéntica a la de JavaScript para describir las funciones, es decir:
function nombreFunción(argumentos) {
contenido de la función
}
function nombreFunción(argumentos)
{
contenido de la función
}
En nuestro caso particular, la función listarCoches no recibe argumento(s) del script cliente
(cliente_ws_01.htm).
A continuación, se almacena una consulta SQL en una variable en memoria, de nombre $consulta_sql. Esta
consulta se enviará naturalmente al motor SQL del SGBD MySQL más adelante.
En el siguiente párrafo, los argumentos de conexión al servidor MySQL se graban en variables en memoria. Para una
aplicación personal, en este script debe rellenar estas variables con los valores proporcionados por su host MySQL.
En la reproducción del script, se ha ocultado el argumento $contraseña.
La siguiente secuencia es relativa a la conexión con el sistema de gestión de base de datos MySQL (se llama
sql.esee.es en nuestro caso, que es el nombre del calculador MySQL puesto a disposición por el editor Free
para los host gratuitos).
$conexion_mysql = @mysql_connect($servidor_mysql,
$usuario_mysql, $contraseña_mysql)
Si la conexión falla, se envía una respuesta al script cliente:
En caso contrario, solo falta conectarse a la base de datos (se llama angel sanchez, en nuestro caso) donde
reside la tabla coches. Recordemos que la conexión anterior solo se dirige al SGBD; por tanto, falta la conexión a la
base de datos como sigue:
Como para la conexión al SGBD, la conexión a la base se comprueba y se envía si es preciso un mensaje de error al
script cliente:
Habrá observado que el retorno de error está programado como el anterior. El servidor se encarga de gestionar la
naturaleza del error con mysql_error().
La siguiente secuencia es la más interesante. Trata el caso de una conexión exitosa, al mismo tiempo, al SGBD y a la
base de datos.
En primer lugar, la consulta SQL se envía al motor SQL de MySQL:
El resultado es una estructura matricial con los registros en filas y los campos en columnas. Se almacena en una
tabla de nombre $resultado_sql.
Si no hay registros (@mysql_num_rows($resultado-_sql)<1), se debe indicarlo a la aplicación cliente. Esto
se hace como sigue:
Falta tratar en el último else el caso más interesante: cuando se encuentran datos (uno o varios registros).
Se implementa una estructura iterativa (while) para recorrer la estructura matricial $resultado_sql. El bucle se
ejecuta mientras haya registros (@mysql_num_rows($resultado_sql)).
Para cada registro, hay que extraer el valor para cada uno de los campos ( codigo_coche, nombre_coche y
velocidad_maxima, en lo que nos afecta), como se hace, por ejemplo, para el código del coche:
En esta sintaxis, $codigo_coche es una variable temporal para grabar la información; mysql_result, la
función de extracción; $resultado_sql, la matriz explorada; $i, el número del registro tratado (la numeración
empieza por 0), y para terminar "codigo_coche", que designa el nombre del campo implicado.
Esta tabla $respuesta (caso del campo $codigo_coche), se alimenta como sigue:
$respuesta[$num_element] = $codigo_coche;
Al final del procesamiento, la tabla $respuesta se reenvía a la aplicación cliente:
return $respuesta;
Resultado de la ejecución
Con los scripts de este ejemplo publicados en un espacio Web, accesible con la URL
http://angel.sanchez.online.es/js_nusoap/, la visualización obtenida cuando se ejecuta el script cliente_ws_01.htm
es la siguiente:
2. Ejemplo 2: Acceso MySQL vía Ajax
La principal diferencia en este segundo ejemplo respecto al anterior es que la extracción de los datos desde la tabla
MySQL coches no se efectúa sobre todos los registros, sino sobre un registro en particular, al que se habrá
enviado codigo_coche desde la aplicación cliente.
Las piezas de Ajax empleadas son exactamente las mismas que en el ejemplo 1 (la respuesta siempre se enviará
por el servidor como un flujo XML).
Por tanto, el ejemplo es la ocasión de ver cómo pasar un argumento (el código del coche) desde una aplicación
cliente a una aplicación servidor.
En el comentario de los scripts que forman este ejemplo, nos centraremos solo en los aspectos que no hemos visto
en ejemplo anterior; por tanto, principalmente, el paso de argumento.
Este script PHP (librería de funciones) ya se ha visto en el ejemplo 1.
Script HTML cliente_ws_02.htm
Este script cliente escrito en HTML/JavaScript es estructuralmente muy parecido al script cliente_ws_01.htm
que hemos visto en el ejemplo anterior.
Integra principalmente dos funciones JavaScript ya vistas en el ejemplo 1:
l llamadaServidorRemoto
l parserDOM
Una nueva función, controlarEleccionLista, comprueba la entrada realizada del código del coche, cuyo
datos asociados queremos buscar en la tabla MySQL coches, desde una lista desplegable que finalmente ejecuta
la búsqueda con una llamada a la función llamadaServidorRemoto.
<!-- Formulario de entrada de datos del código del coche por el que pregunta -->
<form name="formulario">
<!-- Lista desplegable de opciones -->
Código del coche:
<select id="lista"
onchange="controlarEleccionLista(document.getElementById(’lista’),
’Seleccione un código’)">
<option value="CODIGO" selected>Código de coche</option>
<option value="V001">V001</option>
<option value="V002">V002</option>
<option value="V003">V003</option>
</select>
</form>
Cada vez que cambia el código de coche en la lista desplegable llamada
lista, se ejecuta la función
controlarEleccionLista. El argumento getElementById(’lista’) se pasa a esta función, así como un
mensaje que alerta al usuario de la necesidad de hacer una selección.
Nuestra aplicación podría mejorarse integrando una lista desplegable de los códigos de los coches, alimentada por
una búsqueda en el servidor remoto. Para no complicar demasiado la explicación, esta elección técnica no se ha
realizado.
No hay sorpresas respecto a estas variables; son idénticas a las vistas en el ejemplo 1. La única diferencia está en
el valor de la variable url; el script servidor que se va a solicitar es, esta vez, servidor_ws_02.php.
Pasemos al estudio detallado de las funciones JavaScript que recuperan los datos y su procesamiento.
Función controlarEleccionLista
Esta función no estaba presente en el ejemplo 1. Por tanto, se reproduce íntegramente a continuación:
Se trata de un código sin muchas sorpresas. Se hace una comprobación para verificar que se haya seleccionado un
dato de la lista desplegable, de identificador lista (el valor por defecto es el asociado al identificador CODIGO). Si
no se ha seleccionado ningún código de coche, el foco se sitúa en la lista y se muestra un mensaje de alerta
(mensajeAviso). En caso contrario, se realiza la llamada al servidor remoto con la función
llamadaServidorRemoto pasando el código del coche seleccionado (lista.value).
Función llamadaServidorRemoto
El código es prácticamente idéntico al estudiado en el primer ejemplo. La única diferencia está en la construcción del
mensaje SOAP, que se envía al servidor remoto. Esta vez debe tener un argumento, el código del coche, cuyos
datos queremos buscar en la tabla MySQL coches.
Finalmente, las únicas líneas diferentes son:
mensajeSOAP += ’<ns1:buscarCoche
xmlns:ns1="http://angel.sanchez.online.es">’;
mensajeSOAP += ’<type xsi:type="xsd:string">’ + codigo_coche + ’</type>’;
mensajeSOAP += ’</ns1:buscarCoche>’;
El método del script servidor que se va a solicitar se llama buscarCoche (listarCoches en el ejemplo 1).
Observe también la integración en el mensaje SOAP del argumento codigo_coche:
* Función llamadaServidorRemoto */
function llamadaServidorRemoto(codigo_coche)
Funciones parserDOM y timeout
En lo que respecta a estas funciones, no hay ningún cambio respecto a lo que se ha visto en el ejemplo 1.
El script servidor escrito en PHP y que usa la librería de funciones NuSOAP no es muy diferente al visto en el ejemplo
1.
Por tanto, los comentarios se van a centrar en las diferencias.
Se declara el método buscarCoche, pasando el argumento evidentemente:
// Método buscarCoche
// Argumentos pasados por el cliente:
// - $codigo_coche: Código del coche de deporte
// del que se van a listar las características
function buscarCoche($codigo_coche)
A continuación, se hace una comprobación para verificar que se haya pasado un argumento correctamente (en caso
de que no se haya pasado, se envía un mensaje de error a la aplicación cliente):
}
else
{
// ...
En realidad, en nuestra aplicación, esta prueba es un poco inútil, en la medida en que la elección del código del
coche se ha realizado en el script cliente, a través de una lista desplegable.
La consulta SQL también se modifica un poco, integra el argumento $codigo_coche en la cláusula SQL where:
Está prácticamente terminado. Faltan algunas pequeñas diferencias a nivel de la preparación de la respuesta que
se envía a la aplicación cliente.
En caso (poco probable en nuestro ejemplo) de que el coche no se encuentre, tenemos:
y en caso favorable:
Resultado de la ejecución
Con los scripts de este ejemplo publicados en un espacio Web accesible en la URL
http://angel.sanchez.online.es/js_nusoap/, la visualización obtenida cuando se ejecuta el script cliente_ws_02.htm
es la siguiente:
En el capítulo anterior, hemos visto cómo implementar una solución de almacenamiento remoto basado en las
siguientes tecnologías:
l HTML/JavaScript.
l Ajax con XMLHttpRequest (objeto JavaScript o ActiveX, que permite recuperar desde un servidor remoto los datos en
formato XML, JSON, pero también HTML e incluso texto simple con consultas HTTP).
l Protocolo SOAP, que encapsula un encabezado y los datos en formato XML.
l PHP (lenguaje orientado a servidor) para consultar a la base de datos.
l NuSOAP (librería PHP dedicada a la preparación de mensajes SOAP).
l MySQL (servidor de dase de datos).
l Parser DOM para descodificar el mensaje SOAP recibido del servidor.
Las herramientas utilizadas son relativamente genéricas y se pueden extrapolar con facilidad utilizando, por ejemplo,
otro SGBD en el servidor (PosgreSQL, Microsoft SQL Server...) u otro lenguaje de programación (PHP, Microsoft
ASP.NET...).
Sin duda, la principal dificultad sería encontrar, en nuestro caso, una alternativa a la librería NuSOAP.
En este capítulo, vamos a desarrollar de nuevo el ejemplo del capítulo anterior, pero utilizando el formato de datos
XML con otro formato: JSON (JavaScript Object Notation).
JSON es un formato ligero de intercambio de datos. Tiene la ventaja de ser independiente de los lenguajes de
programación y presenta la particularidad de ser reconocido de manera nativa por JavaScript. En las aplicaciones de
intercambio de datos clienteservidor, se utiliza de manera frecuente, como alternativa a XML. La ventaja es que la
codificación del mensaje del lado servidor es fácil de realizar y el lado cliente no necesita recurrir a un parser DOM.
Aunque vamos a descubrir JSON a través de varias miniaplicaciones en este capítulo, veamos de forma general este
formato con un ejemplo.
A continuación hay un mismo conjunto de datos, en formatos JSON y XML:
Formato JSON:
[
{
"menú": "Archivo",
"comandos":
[
{"nombre": "Nuevo", "accion":"crearDocumento"},
{"nombre": "Abrir", "accion": "abrirDocumento"},
{"nombre": "Cerrar", "accion": "cerrarDocumento"}
]
}
]
Formato XML:
Se van a presentar cinco ejemplos completos de aplicación.
Para las necesidades de estos ejemplos, vamos a reutilizar la tabla MySQL coches que hemos visto en el capítulo
anterior.
Recordemos simplemente la estructura de esta tabla:
l codigo_coche, de cuatro caracteres (código del coche).
l nombre_coche, de 20 caracteres (etiqueta del coche).
l velocidad_maxima es un número entero (velocidad máxima que el coche puede alcanzar, en un circuito, por
supuesto).
1. Ejemplo 1: Presentación del sistema de notación JSON
Comentario del script JSON_01.htm
En este primer ejemplo, nos centramos en estudiar el sistema de notación propio de JSON y el modo de acceso a las
propiedades de los objetos.
Todo el código JavaScript comentado que se muestra a continuación se ha situado en la sección HTML <body> del
script (llamado JSON_01.htm). Por tanto, este código está dentro de:
El script empieza definiendo tres objetos (coche), caracterizados por las propiedades habituales (cf. capítulo
anterior): código, nombre y velocidad máxima:
También creamos un objeto compuesto (ensamblado de objetos) de nombre alemanes, que agrupa los objetos
coche1 y coche2, que efectivamente son coches alemanes, como sigue:
Veamos ahora cómo utilizar estos objetos para mostrar, por ejemplo, sus propiedades:
La notación no puede ser más simple. Es suficiente con indicar el nombre del objeto como prefijo y después indicar
(tras un punto) la propiedad deseada como sufijo.
La visualización en pantalla da el siguiente resultado:
El Porsche 930 Turbo > 290Km/h
El Porsche 964 Turbo > 300Km/h
Modifiquemos ahora uno de los valores de las propiedades, la velocidad máxima del coche1 (290 inicialmente) para
asignarle un valor más real (260) y mostremos el resultado:
La visualización es la siguiente:
El Porsche 930 Turbo > 260Km/h
En nuestra secuencia de código, se proponen dos sintaxis de visualización para la propiedad velocidad_maxima
del coche2:
La sintaxis "objeto" (para el nombre):
alemanes.aleman2.nombre
La sintaxis "tabla asociativa" (para el nombre):
alemanes["aleman2"]["nombre"]
El resultado en pantalla es el siguiente:
Mostrar el objeto alemanes:
El Porsche 964 Turbo > 300Km/h (sintaxis 1)
El Porsche 964 Turbo > 300Km/h (sintaxis 2)
Terminemos nuestro ejemplo estudiando la posibilidad de construir objetos JSON a partir de tablas:
En la secuencia de código, se crea una primera tabla nombres, con las tres etiquetas vistas anteriormente.
Una segunda tabla velocidades_maximas agrupa los tres valores de velocidad. Evidentemente, la información
Para terminar, tenemos un objeto JSON llamado coches, con las propiedades nom y vel, que son propiedades
compuestas basadas en las dos tablas nombres y velocidades_maximas.
Veamos ahora cómo se utiliza:
La notación también es muy intuitiva. Es suficiente con indicar el nombre del objeto JSON como un prefijo y,
después, un punto que indique el nombre de la tabla implicada, con el rango del valor deseado entre [].
Observe que, en las tablas, el primer elemento tiene el valor de rango 0.
En nuestro caso, obtenemos la siguiente visualización:
Visualización (utilizando las tablas) de las propiedades del segundo coche:
Porsche 964 Turbo > 300 Km/h
Resultado de la ejecución
Se han indicado resultados parciales en el comentario del script JSON_01.htm. Terminemos con el resultado de la
ejecución, tal y como se presenta en nuestro navegador habitual (Chrome):
2. Ejemplo 2: Lectura de un archivo JSON con XMLHttpRequest
En este segundo ejemplo, vamos a ver cómo acceder al contenido de un archivo de datos JSON desde un script
JavaScript, y esto a través de un objeto XMLHttpRequest.
Se ha utilizado el objeto XMLHttpRequest del capítulo anterior.
Para facilitar la comprensión de la aplicación, retomamos nuestro ejemplo basado en nuestros tres coches de
deporte:
{
"coche1":{
"codigo":"V001",
"nombre":"Porsche 930 Turbo",
"velocidad_maxima":290
},
"coche2":{
"codigo":"V002",
"nombre":"Porsche 964 Turbo",
"velocidad_maxima":300
},
"coche3":{
"codigo":"V003",
"nombre":"Ferrari 430",
"velocidad_maxima":320
}
}
El nombre de este archivo, situado en el sitio Web en el mismo directorio que el script JavaScript, es coches.json.
Estudiemos ahora paso a paso el script HTML/JavaScript.
En la sección HTML <body>, encontramos principalmente esto:
Se crea una capa HTML, identificada con capaResultado, para recibir los datos extraídos del archivo JSON
coches.json.
Pasemos ahora a lo fundamental, el estudio de la función ajaxJSON.
Como en los ejemplos del capítulo anterior, se va a usar un objeto XMLHttpRequest:
Para las versiones antiguas del navegador Microsoft Internet Explorer (versiones 6 y anteriores), se usa un objeto
ActiveX en lugar de XMLHttpRequest.
Pasemos ahora a la apertura del archivo coches.json y a la definición de su tipo:
El argumento true del método open sirve para indicar que el flujo debe estar totalmente disponible antes de que
sea tratado por la aplicación cliente. Se utiliza el método GET porque la aplicación cliente no envía el argumento.
Veremos más adelante un ejemplo de búsqueda de datos en una tabla MySQL, con una selección en el script cliente,
donde utilizaremos el método POST.
El método setRequestHeader indica que nuestro flujo de datos está en formato JSON.
Ahora llegamos al procesamiento del flujo, cuando está totalmente disponible. La secuencia de código se presenta a
continuación de manera íntegra, junto con una explicación detallada:
/* Visualización de control */
// alert("readystate: "+ httpRequest.readyState);
// alert("status: "+ httpRequest.status);
// alert("responseText: " + httpRequest.responseText);
Como habíamos visto en el capítulo anterior, en el procesamiento de flujos XML, se hacen comprobaciones de las
propiedades readyState y status del objeto XMLHttpRequest (llamado httpRequest en nuestro caso).
Posteriormente, hay una visualización de control (comentada en el script anterior). Para que sirva de ejemplo, la
instrucción:
daría como resultado la siguiente visualización:
responseText: {
"coche1":{
"codigo":"V001",
"nombre":"Porsche 930 Turbo",
"velocidad_maxima":290
},
Una vez que se ha recuperado el flujo JSON, hay que convertirlo en objetos JavaScript. Esta pesada operación se
puede realizar con un método nativo de JavaScript, JSON.parse. Es suficiente con pasarlo como el flujo, es decir,
httpRequest.responseText.
Ahora falta reiniciar (borrar) el contenido de la capa de visualización y explorar los objetos JavaScript con un bucle
for:
El script de la función ajaxJSON termina con:
El método send del objeto httpRequest tiene como argumento null, lo que significa que el cliente no ha
transmitido ninguna información al servidor. Más adelante veremos un ejemplo de tipo POST con transmisión de un
argumento. En nuestro caso (gestión del flujo JSON en modo asíncrono), el método send se debe ubicar al final del
script.
Resultado de la ejecución
La ejecución del script JSON_02.htm da el siguiente resultado en nuestro navegador habitual (Chrome):
3. Ejemplo 3: Lectura de un archivo JSON con XMLHttpRequest y un script servidor en
PHP
Comentario de los scripts JSON_03.htm y servidorJSON.php
El tercer ejemplo presenta muchas similitudes con el ejemplo 2.
El script cliente es casi idéntico. Simplemente se ha llamado JSON_03.htm.
El archivo de datos JSON que contiene las descripciones de los coches también se reutiliza (sin cambiar el nombre).
La diferencia en este nuevo ejemplo es que el flujo JSON se lee por una aplicación del lado servidor escrita en PHP.
Veamos en detalle algunas modificaciones respecto a la aplicación anterior.
En el script JSON_02.htm (ejemplo 2), teníamos esta apertura de archivo:
En el script JSON_03.htm, se hace referencia al script servidor PHP de nombre servidorJSON.php:
<?php
?>
Después de haber definido el tipo del flujo (configuración de tipo header), se lee el archivo JSON coches.json y
se asigna, sin transformación, a una variable de texto llamada datosJSON.
Esta variable se envía finalmente a la aplicación cliente (JSON_03.htm).
Hemos visto en el script cliente JSON_02.htm (el desarrollo es idéntico para JSON_03.htm) cómo se tiene en
cuenta este contenido.
A este nivel de la exposición de los ejemplos, se podría preguntar sobre el interés de encargar la lectura del archivo
JSON coches.json a un script servidor escrito en PHP. En los siguientes ejemplos vamos a ver (pero usted ya lo
sabe desde el capítulo anterior) cómo utilizar el script servidor PHP para extraer datos desde una tabla de datos
MySQL y aplicar a la extracción el formato JSON.
Resultado de la ejecución
Con los scripts de este ejemplo publicados en un espacio Web accesible con la URL
http://angel.sanchez.online.es/js_json/JSON_03/, la visualización obtenida cuando se ejecuta el script
JSON_03.htm es la siguiente:
4. Ejemplo 4: Lectura de una tabla MySQL con XMLHttpRequest (servidor PHP y flujo
JSON)
Comentario de los scripts JSON_04.htm y servidorJSON.php
En el ejemplo 1 del capítulo anterior, habíamos dado prioridad a las tecnologías SOAP y XML, mientras que esta vez
a los datos se les aplicará en formato JSON y serán trazados en consecuencia por el script cliente JSON_04.htm.
Empecemos por descifrar el script de servidor escrito en PHP, llamado servidorJSON.php.
Script servidor PHP servidorJSON.php
El código fuente de este script es relativamente nuevo, aunque tiene algunas similitudes con el que hemos visto en
el ejemplo 1 del capítulo anterior. A continuación se reproduce completamente y después se comentará en detalle:
<?php
}
else
{
}
else
{
}
else
{
while
($registro = mysql_fetch_assoc($resultado_sql))
{
// Inserción de los 3 campos (codigo_coche,
// nombre_coche y velocidad_maxima)
// del registro actual
// en la tabla $registros (que contendrá,
// al final, todos los datos)
$registros[] = $registro;
}
?>
La consulta SQL configurada posteriormente permitirá la extracción de los tres registros de la tabla MySQL coches,
que se ordenarán utilizando los valores del campo codigo_coche:
$consulta_sql = "select
codigo_coche,
nombre_coche,
velocidad_maxima
from coches
order by codigo_coche;";
Ahora vienen los argumentos de conexión al sistema de gestión de base de datos MySQL y a la base de datos de
nombre json. Observe que nuestro ejemplo ha sido desplegado en un servidor local (EasyPHP), para poder
disponer de una versión del lenguaje PHP (5.2 mínimo) que soporte la función json_encode. Estos argumentos de
conexión son:
Como en el ejemplo 1 del capítulo anterior, se realizan comprobaciones respecto a la conexión al SGBD y a la base
de datos. En nuestro script minimalista, los mensajes de error que se envían a la aplicación cliente no se han
especificado, sino que solo se ejecuta un sencillo echo ""; en caso de error.
Centrémonos en lo esencial, la recuperación de los datos de la tabla MySQL coches, la descodificación en un flujo
JSON y el reenvío del flujo a la aplicación cliente:
while
($registro = mysql_fetch_assoc($resultado_sql))
{
// Inserción de los 3 campos (codigo_coche,
// nombre_coche y velocidad_maxima)
// del registro actual
// en la tabla $registros (que contendrá,
// al final, todos los datos)
$registros[] = $registro;
}
La estructura iterativa while recorre el conjunto de registros correspondiente a la consulta SQL
($consulta_sql). Para cada registro leído, se insertan los valores de los campos en una tabla de nombre
$registro. Esta tabla se asigna, a su vez, a otra tabla (que se convierte de esta manera en una especie de tabla
de dos dimensiones), de nombre $registros.
Para terminar, el flujo JSON se envía a la aplicación cliente.
Script cliente HTML/JavaScript JSON_04.htm
Este script es muy parecido al del ejemplo 3 de este mismo capítulo. Solo la visualización de los datos se modifica
ligeramente:
Cuando se ejecuta este script, el flujo JSON recuperado es:
En caso de que el módulo PHP de su servidor Web (Apache en la mayoría de los casos) no soporte la función
json_encode, no todo está perdido. Tendrá que construir el flujo JSON con el código PHP.
Resultado de la ejecución
El host Free (utilizado para los ejemplos del capítulo anterior) no ofrece la función json_encode, por lo que los
scripts de este ejemplo se han desplegado en una intranet de tipo EasyPHP (versión 12.1).
Con la URL http://122.1.0.0/js_json/JSON_04/JSON_04.htm, obtenemos:
5. Ejemplo 5: Recodificación del ejemplo 4 con una lista desplegable
Este quinto ejemplo va a ser muy parecido al ejemplo 2 del capítulo anterior. El usuario podrá, usando una lista
desplegable, elegir el coche de deporte cuyas características quiera obtener.
Esta posibilidad tiene algunos impactos tanto en el script cliente (JSON_05.htm) como en el script servidor
(servidorJSON.php).
Empecemos esta vez descifrando el script cliente.
Script cliente HTML/JavaScript JSON_05.htm
En la sección HTML <body> tenemos la lista desplegable y la capa de visualización del resultado:
<!-- Formulario de entrada de datos del código del coche por el que se pregunta -->
<form name="formulario">
<!-- Lista desplegable de opciones -->
Código del coche:
<select
id="lista"
onchange="controlarEleccionLista(document.getElementById(’lista’),
’Por favor, seleccione un código’)">
<option value="CODIGO" selected> Código del coche </option>
<option value="V001"> V001 </option>
<option value="V002"> V002 </option>
<option value="V003"> V003 </option>
</select>
</form>
La única diferencia es, evidentemente, el nombre de la función que se llama, es decir ajaxJSON:
Detengámonos también un poco en la función ajaxJSON.
Hay algunas diferencias respecto al script del ejemplo 1 de este mismo capítulo:
El método open se utiliza con el argumento POST (en lugar de GET) porque se va a pasar un argumento al script
servidorJSON.php.
Con el argumento POST, el envío de los argumentos se hace a través del cuerpo de la consulta, mientras que con el
argumento GET el envío de los argumentos se hace en la URL en sí misma (con la forma:
http://misitio/miscriptservidor?argumento1=valor1&argumento2=valor2, por ejemplo).
El tipo de flujo hacia el servidor también es diferente:
Observe que application/x-www-form-urlencoded es el valor que es necesario conservar para el envío de
argumentos desde un formulario HTML (lista desplegable en nuestro caso). Los valores de argumentos se
codificarán (por ejemplo, sustitución de los espacios por %20).
Falta ver cómo enviar el argumento (código del coche) al servidor, con el método send del objeto httpRequest:
httpRequest.send(argumento);
Script servidor PHP servidorJSON.php
El script servidor es muy parecido al visto en el ejemplo 1.
Veamos algunas modificaciones añadidas:
Una variable $codigo recupera el valor del argumento codigo, que se pasa por el script cliente. Los valores
posibles son, en nuestro caso, V001, V002 y V003.
La consulta SQL se ha completado añadiendo una cláusula SQL de selección con este código:
where codigo_coche=’$codigo’
Como nuestro host habitual (Free) no ofrece la función json_encode, los scripts de este ejemplo se han
desplegado en una intranet de tipo EasyPHP (versión 12.1).
Con la URL http://122.1.0.0/js_json/JSON_05/JSON_05.htm, obtenemos el siguiente resultado:
El API HTML 5 de geolocalización ofrece la posibilidad al usuario de la aplicación de conocer su posición geográfica
(latitud y longitud).
Para realizar esta localización espacial, no es necesario recurrir a ninguna librería adicional porque esta funcionalidad
es nativa y, por tanto, está integrada en los navegadores recientes, incluidos los smartphones (iPhone, Android...).
Entre las principales aplicaciones que utilizan los mecanismos de geolocalización, encontramos Google Maps, Google
Street e incluso Google Earth. En realidad, se trata de un API que puede utilizar en sus propios desarrollos.
Los ejemplos que se presentan en la segunda parte de este capítulo usan justamente los API de Google.
Por tanto, al final de este capítulo sabrá utilizar un mapa de Google Maps con gran precisión (centrado, zoom y
anotación, pasando por los diferentes modos de visualización...) y podrá desarrollar aplicaciones basadas en la
geolocalización (localización de puntos de interés en un mapa, trayectos, distancias, cálculo de velocidad,
geomarketing, aplicaciones de comunidad basadas en la geolocalización, uso de overlays, como, por ejemplo, las
indicaciones meteorológicas...).
Para terminar, hay que observar que el uso de determinados API de Google no es gratuito. Además, Google, aunque
tiene una presencia dominante, no goza del monopolio absoluto en materia de geolocalización.
Para que sirva de ejemplo, el cliente Orange tiene su propio API de localización. Sin hacer una búsqueda exhaustiva,
también podemos citar los siguientes API:
l INSITEO: http://www.insiteo.com/joomla/index.php
l MAXMIND: http://www.maxmind.com/es/home
l HOSTIP.INFO: http://www.hostip.info/
l MICHELIN: http://dev.viamichelin.com/
1. Ejemplo 1: Visualización del mapa del centro de España
En este primer ejemplo vamos a implementar las funcionalidades básicas del API de geolocalización que se incluyen
de manera nativa en HTML 5 y que, en consecuencia, son soportadas por los navegadores recientes (incluidos los
smartphones).
El objetivo va ser muy simple: mostrar en pantalla un mapa de Google Maps que presente la región correspondiente
al centro de España, con un centrado del mapa en la ciudad de Madrid.
Como se trata de nuestro primer ejemplo de cartografía, el script HTML/JavaScript se reproduce de forma íntegra (no
se hará sistemáticamente en el resto de los ejemplos):
<!--
NOMBRE DEL SCRIPT: GEO_01.htm
REALIZACIÓN INFORMÁTICA: Christian VIGOUROUX
FECHA DE CREACIÓN: 01/01/2014
FECHA DE ÚLTIMA MODIFICACIÓN: 01/01/2014
OBJETIVO: Gestión Google Map - Mapa del centro de España
(centrado en Madrid) -->
</script>
</head>
</script>
</body>
</html>
Sección HTML <body>
Empezamos el comentario por la sección HTML <body>.
Esta sección empieza con la ejecución de la función inicializarMapa:
No nos detenemos en el resto de la sección. Observe simplemente un conjunto de etiquetas <noscript> ...
</noscript>, no muy útiles ahora, porque todos los navegadores soportan el JavaScript.
Sección HTML <head>
Esta sección empieza con la etiqueta meta habitual, que define el tipo de contenido y el conjunto de caracteres.
A continuación, tenemos una segunda etiqueta meta específica de nuestro procesamiento:
Esta etiqueta indica al navegador el comportamiento que debe tener durante la visualización de la página. En
nuestro caso, la página se mostrará al 100 % con el zoom autorizado.
Posteriormente, se integra una hoja de estilos CSS, que sirve para definir el marging, el padding (margen adicional
entre el contenido y el borde) y la altura para los elementos HTML html, body y #mi Mapa.
Este libro no explica las hojas de estilo CSS, aunque haya algunos ejemplos que las usen. Se puede formar de
manera eficaz en CSS leyendo los libros XHTML y CSS Los nuevos estándares de código fuente [segunda edición]
de Luc VAN LANCKER, o HTML5, CSS3 y JavaScript Desarrolle sites para terminales móviles, de Olivier HENEBELLE,
publicados en Ediciones ENI.
Estudiemos ahora la función JavaScript inicializarMapa.
El argumento sensor="false" indica que la aplicación no usa la localización GPS (Global Positioning System).
Fuente Wikipedia: el Global Positioning System (GPS) permite determinar en todo el mundo la posición de un objeto,
una persona o un vehículo con una precisión hasta de centímetros (si se utiliza GPS diferencial), aunque lo habitual
son unos pocos metros de precisión. El sistema fue desarrollado, instalado y empleado por el Departamento de Defensa
de los Estados Unidos. El sistema GPS está constituido por 24 satélites y utiliza la triangulación para determinar en todo
el globo la posición con una precisión de más o menos metros.
Observe que, desde la versión 3 del API Google Maps, ya no es necesario pedir a Google un código para poder
utilizar un mapa en sus aplicaciones Web. Puede consultar las condiciones de uso en la siguiente dirección:
https://developers.google.com/maps/documentation/javascript/tutorial?hl=es . La gestión de las claves de Google están
fuera del ámbito de este libro.
Aunque los navegadores recientes soportan el API de geolocalización, puede ser interesante comprobar su
disponibilidad:
Pasemos ahora a la definición de la posición de centrado del mapa. Se ha decidido centrar el mapa alrededor de la
ciudad de Madrid, que tiene la posición 40.416875 de latitud y 3.703308 de longitud.
Hay muchos sitios Web que dan esta información para la gran mayoría de las ciudades españolas y del mundo.
A continuación, se indica la información adicional (options) necesaria para la correcta visualización del mapa:
En nuestro caso, se elige un factor de zoom de 8; el mapa está evidentemente centrado en la posición de Madrid y
la visualización es en modo ”mapa de carreteras” (ROADMAP).
Hay otros modos de visualización disponibles:
l google.maps.mapTypeId.SATELLITE: Modo Satélite
l google.maps.mapTypeId.HYBRID: Modo Mixto (Plano/Satélite)
l google.maps.mapTypeId.TERRAIN: Modo Relieve
Terminamos asignando el mapa creado a la capa HTML prevista para su visualización:
Encontramos en esta instanciación la capa HTML mi Mapa y las opciones de visualización optionsGoogleMap.
Observe que, con este script minimalista, el mapa se muestra con un determinado número de dispositivos: zoom
aumentar/reducir, desplazamiento horizontal/vertical, icono de modo Google Street View.
Fuente Google: Google Maps con Street View permite explorar los lugares de todo el mundo, aprovechando las
imágenes de 360 grados de sus calles. Puede explorar lugares destacados, descubrir maravillas de la naturaleza,
seguir una ruta turística, entrar en restaurantes...
Resultado de la ejecución
La ejecución del script GEO_01.htm genera esta visualización:
Este segundo ejemplo es muy parecido al anterior. Su valor añadido va a ser la ubicación, en la posición geográfica
de Madrid, de un marcador.
Las explicaciones básicas de la implementación del mapa no se darán de nuevo.
Una marca es un icono (es posible modificar la imagen) sobre el que el usuario podrá pulsar para obtener
información contextual (como una ventana de tipo popup).
Sección HTML <body>
En cambio, respecto a la ejecución de la función inicializarMapa, procedemos de manera diferente, a través
del gestor de eventos de Google Maps. Volveremos a este punto más tarde.
Sección HTML <head>
Las etiquetas meta y la hoja de estilos CSS integrada son idénticas a las vistas en el ejemplo 1.
También encontrará que la llamada al API Google Maps es idéntica.
Pasemos al estudio de la función inicializarMapa.
La definición de la posición de centrado, las opciones y la ubicación del mapa en la capa HTML mi Mapa no cambian
respecto al ejemplo anterior.
Solo falta ver la gestión del marcador. El código íntegro de esta parte se reproduce a continuación:
Empecemos por la ubicación del marcador que indica la ciudad de Madrid:
La marca se ubica con el objeto Marker del API Google Maps.
El argumento de su constructor tiene una tabla de opciones:
l position: posición de la marca en el mapa,
l map: mapa en el que se mostrará la marca,
A continuación, hay un texto explicativo para una visualización posterior en una ventana popup:
Este texto se muestra en una ventana (llamada ventanaMadrid), que tiene como constructor:
El constructor del objeto InfoWindow tiene como argumento el comentario, almacenado en la variable
comentariosMadrid.
Una vez que se ha definido la ventana, hay que programar su visualización, que solo será efectiva si el usuario hace
clic en el marcador. Esto se administra por el gestor de eventos de Google Maps:
Un último punto relativo a este ejemplo es la llamada a la función inicializarMapa:
Observe que esta llamada condicionada a un evento se realiza en la sección HTML <head> después de la
descripción de la función inicializarMapa.
Se ha visto una alternativa en el ejemplo 1: <body onload="inicializarMapa()">
La ejecución del script GEO_02.htm muestra lo siguiente:
3. Ejemplo 3: Visualización del mapa del centro de España (marcador y círculos de
población)
En este nuevo ejemplo, retomamos el marco de los dos ejemplos anteriores. En este caso, vamos a establecer
círculos, cuyo radio será proporcional a la población que vive en las principales ciudades del noroeste de la
Comunidad de Madrid. Solo se comentará esta parte aquí.
Sección HTML <body>
Ninguna novedad respecto al ejemplo 2.
Sección HTML <head>
En la función inicializarMapa, además de la ubicación de un marcador en la ciudad de Madrid, hay un segundo
marcador en Las Rozas. Este marcador está personalizado por un cambio de icono.
La ruta de acceso a la imagen que sirve de nuevo icono de marcado es lo primero que se define:
A continuación, se añade un argumento adicional (icon) en la instanciación del marcador:
icon: imagenMarcaLasRozas
Pasemos ahora al corazón del procesamiento, la implantación de círculos que representan la población de las
ciudades de Madrid, Las Rozas, Pozuelo y Torrelodones.
La secuencia empieza declarando una tabla en memoria (asociativa), en la que se almacena la posición geográfica
de las cuatro ciudades, así como su población:
Para que sirva de ejemplo, para la ciudad de Madrid, los datos almacenados en la tabla asociativa
listaCiudades son:
/* Argumentos de Madrid */
listaCiudades[’Madrid’] = {
posicion: new google.maps.LatLng(40.416875, -3.703308),
poblacion: 207178
};
Falta recorrer la tabla listaCiudades para trazar un círculo, con radio proporcional a la población de cada una de
las ciudades:
opcionesCirculo es una tabla que agrupa todas las opciones que definen el círculo que se ha de trazar para
cada ciudad. Las opciones definidas en nuestro ejemplo son:
l el color del borde del círculo (strokecolor),
l la opacidad del borde del círculo (strokeOpacity),
l el grosor del trazo del borde del círculo (strokeWeight),
l el color del interior del círculo (fillColor),
l la opacidad del color del interior del círculo (fillOpacity),
l el mapa en el que se ubica el círculo (map),
l la posición del centro del círculo (center),
l el radio del círculo (radius).
Para terminar, el círculo se dibuja con las opciones definidas:
Resultado de la ejecución
La siguiente visualización se obtiene cuando se ejecuta el script GEO_03.htm:
En este cuarto ejemplo, vamos a ver cómo añadir a un mapa una capa informativa con datos meteorológicos, en
tiempo real en nuestro caso.
Sección HTML <body>
No hay ninguna novedad respecto al ejemplo 3; por tanto, encontrará la capa HTML de visualización del mapa
llamada mi Mapa.
Sección HTML <head>
Esta sección empieza definiendo algunos estilos CSS útiles para la presentación de las secciones HTML html y
body:
En esta llamada no se indica la localización de la posición del usuario y con el argumento libraries=weather
indicamos el uso de la librería Google, que permitirá recuperar la información meteorológica.
Vemos cómo integrar la capa de información (layer) mencionada.
Empecemos anunciando las temperaturas. El objeto utilizado es WeatherLayer. Es suficiente con instanciar un
objeto y configurar la propiedad temperatureUnits como sigue:
WeatherLayer es una clase de la librería google.maps.weather. La elección de la unidad para las
temperaturas ha sido CELSIUS.
A continuación, esta capa se debe ubicar en el mapa:
En lo que respecta a la capa de visualización de las nubes y del sol, el desarrollo es prácticamente idéntico.
Esta vez, el objeto utilizado es CloudLayer (sin argumentos):
Resultado de la ejecución
La ejecución del script GEO_04.htm muestra lo siguiente:
5. Ejemplo 5: Visualización del mapa de Madrid (capa panorámica)
En este nuevo ejemplo, vamos a estudiar una capa informativa particularmente interesante cuando visitamos, por
ejemplo, una ciudad con nuestro smartphone favorito. Va a ser posible acceder a la información mostrada en una
miniventana situada en los puntos de interés.
Sección HTML <body>
No hay ninguna novedad respecto al ejemplo 4.
Sección HTML <head>
Antes de descifrar nuestra habitual función inicializarMapa, es necesario ver el contenido de una hoja de
estilos CSS integrada:
El estilo #marcoFoto de esta hoja CSS sirve para formatear los marcos en los que se presentarán las fotos de los
puntos de interés.
La llamada al API Google Maps también es un poco diferente respecto a lo visto en los cuatro ejemplos anteriores:
La función inicializarMapa empieza como de costumbre, definiendo la posición de centrado del mapa (siempre
Madrid), las opciones de visualización y la ubicación del mapa en la capa HTML llamada mi Mapa. La única diferencia
es el factor de zoom, fijado a 16 en este ejemplo.
Como para las capas situadas en el mapa del ejemplo 4, aquí tenemos una capa llamada PanoramioLayer:
Este no está totalmente terminado; falta definir el marco de visualización de las fotos e indicar la posición de las
fotos en su marco;
El marco de las fotos se basa en el estilo #marcoFoto descrito en la hoja de estilos CSS integrado. Las fotos se
sitúan en la esquina superior derecha de estos marcos.
Terminamos asociando una acción (visualización de la información adicional) al evento click en cada una de estas
fotos:
Sin entrar detalladamente, diremos que en esta secuencia:
l se define una función que se ejecuta durante un clic en las fotos,
l se crea una capa HTML llamada div,
l se asocia un enlace hipertexto a la foto.
El argumento foto de la función representa la foto en la que el usuario habrá hecho clic. A esta foto se puede
acceder desde el sitio Web Panoramio ( http://www.panoramio.com) con un enlace hipertexto.
Resultado de la ejecución
La visualización generada por el script GEO_05.htm da el siguiente resultado:
Terminamos aquí nuestra serie de ejemplos sobre geolocalización. Podríamos ir incluso más lejos, porque Google
Maps ofrece más posibilidades.
En este sexto ejemplo, vamos a implementar Google Street View, que permite visitar virtualmente las calles de una
ciudad a partir de un mapa Google Maps.
Sección HTML <body>
Una vez más, ninguna novedad respecto al ejemplo 4.
Sección HTML <head>
La sección empieza con etiquetas meta que ya conocemos:
La llamada al API Google Maps también se ha visto como (ejemplos 1 a 4):
La función inicializarMapa empieza configurando el centrado del mapa (en la ciudad de Madrid).
Las opciones del mapa son las ya vistas:
l un zoom a 16,
l el centrado,
l el modo de visualización ROADMAP.
A continuación, el mapa se asigna a la capa HTML habitual, miMapa.
Lo que sigue es el establecimiento del dispositivo Street View:
El argumento pov es una tabla de opciones con:
l heading: ángulo de rotación de la cámara en grados (0 = posición Norte) en el sentido de las agujas del reloj (90
= posición Este); el valor por defecto es 0.
l pitch: inclinación de la cámara (90 grados = inclinación hacia arriba, 90 grados = inclinación hacia abajo); el valor
Resultado de la ejecución
La ejecución del script GEO_06.htm genera esta visualización:
<canvas>, nuevo elemento en HTML 5, se usa para realizar gráficos simples, incluso animaciones (sin alcanzar el
grado de sofisticación de Adobe Flash).
Inicialmente, <canvas> fue implementado en Apple Mac OS X (Dashboard); después se soportó en el navegador
Safari y, para terminar, en Mozilla Firefox (Gecko 1.8).
En los ejemplos de este capítulo, se va a utilizar el elemento <canvas> en el diseño de un conjunto de tipo
TicTacToe (también llamado Morpion).
La serie de ejemplos (basados todos en el TicTacToe), le permitirá adquirir conocimientos básicos sobre lo que se
puede hacer con <canvas>.
En la red, puede encontrar muchos tutoriales más completos sobre <canvas>, como el de la fundación Mozilla
(https://developer.mozilla.org/es/docs/Web/HTML/Canvas ).
1. Ejemplo 1: Dibujar un cuadrado sencillo
En este primer ejemplo, vamos a dibujar un cuadrado muy sencillo. Será la base de la futura matriz de TicTacToe.
Sección HTML <head>
Esta sección no tiene nada específico. Hay una simple etiqueta meta y el título del script.
</head>
Sección HTML <body>
El código de la sección <body> se reproduce completamente a continuación:
/*
Representación en el canvas
*/
/* Representación efectiva */
contextoCanvas.stroke();
</script>
Estudiemos ahora las diferentes secuencias de este script (el nivel de detalle será menor en los siguientes
ejemplos).
El código de la sección <body> se reproduce completamente a continuación.
El script empieza estableciendo el canvas:
El elemento <canvas> se define por un identificador (id="matrizMorpion") y se dimensiona en longitud
(width="1000") y en altura (height="800"). Los valores se expresan en píxeles.
El texto ("Atención, su navegador...") presente entre la etiqueta <canvas> y la etiqueta </canvas>
se mostrará en caso de que el navegador no soporte el elemento <canvas>.
La secuencia siguiente:
define la ubicación ocupada por el <canvas>, es decir, un rectángulo de 1.000 píxeles de longitud por 800 píxeles
de altura.
A continuación, se define el contexto del <canvas>:
Recordemos que un contexto 2D proporciona un conjunto de objetos, métodos y propiedades que permitirán la
manipulación de los diseños en 2D.
Ahora podemos pasar a lo más importante. Se trata del dibujo de un simple rectángulo de color negro (sin relleno).
Este cuadrado se replicará varias veces en el nuestro segundo ejemplo para construir una matriz de TicTacToe.
A continuación, es necesario indicar el inicio de una línea punteada:
Lo que viene a continuación, exige un poco de paciencia. Se trata de la definición de las coordenadas de los cuatro
lados de nuestro cuadrado:
A partir de un punto de inicio (10, 10), se dibujan los cuatro lados.
La representación efectiva del cuadrado se ejecuta por:
/* Representación efectiva */
contextoCanvas.stroke();
Ejecución del script
La ejecución del script MORPION_01.htm da la siguiente visualización:
2. Ejemplo 2: Dibujar una matriz de TicTacToe
Ahora hay que reproducir el procesamiento visto en el primer ejemplo para obtener una verdadera matriz de
TicTacToe.
Sección HTML <body>
Esta vez, empezamos la explicación estudiando la sección <body>.
Después de la definición del <canvas> (ya estudiado en el ejemplo anterior), el dibujo de la matriz (5 líneas * 5
columnas) se obtiene como sigue:
/* Representación de la matriz */
/* NB: La función representarMatriz tiene 3 argumentos: */
/* - Argumento 1: xInicio */
/* - Argumento 2: yInicio */
/* - Argumento 3: longitudLado */
for (linea = 1; linea <= 5; linea++)
{
/* Representación de los 5 cuadrados
de la línea numeroLinea de la matriz */
for (columna = 1; columna <= 5; columna++)
{
representarMatriz(columna * 100, linea * 100, 100);
}
}
</script>
Hay dos bucles for anidados para asegurar el dibujo de la matriz del TicTacToe. El primero gestiona las cinco líneas
de la matriz, mientras que el segundo, el más interno, dibuja las cinco celdas de la línea actual.
Se llama a la función representarMatriz para asegurar el dibujo efectivo de las celdas. A esta función se le
pasan tres argumentos (expresados en píxeles):
l argumento n.°1 (columna*100): coordenada x de la celda que se ha de dibujar,
l argumento n.°2 (línea*100): coordenada y de la celda que se ha de dibujar,
l argumento n.°3 (100): longitud del lado.
Sección HTML <head>
Esta sección contiene principalmente el código de la función representarMatriz:
/* Función representarMatriz */
function representarMatriz(x, y, lado)
{
/*
Representación en el canvas
*/
/*
Definición de las propiedades de los trazos */
contextoCanvas.strokeStyle = "black";
contextoCanvas.lineWidth = 1;
/* Representación efectiva */
contextoCanvas.stroke();
El código es similar al visto en el ejemplo 1.
Se declaran las tres variables xInicio, yInicio y longitudLado y reciben los valores que se pasan como
argumentos por el script que llama (cf. sección <body>).
Ejecución del script
Cuando se ejecuta el script MORPION_02.htm, da el siguiente resultado:
El objetivo aquí es darle las bases técnicas para que pueda colocar las marcas en la matriz del TicTacToe.
Sección HTML <body>
Se ha elegido dibujar dos marcas en la matriz del TicTacToe:
l un cuadrado verde en la línea 1, columna 2, para el jugador n.°1 ;
l un círculo rojo en la línea 2, columna 2, para el jugador n.°2.
El código situado al final de la sección <body> es el más sencillo posible. De momento, no se trata del conjunto
definitivo, que permite a los dos jugadores actuar sucesivamente para situar sus marcas (damas) en la matriz con
objeto de obtener cuatro marcas alineadas, por ejemplo.
Estudiemos este código paso a paso.
Para dibujar el cuadrado verde (corresponde, por ejemplo, a la marca del jugador n.°1), se declaran tres variables
locales:
l x: posición horizontal (en píxeles) en el <canvas>,
l y: posición vertical (en píxeles) en el <canvas>,
l lado: longitud del lado, en píxeles, del cuadrado.
No se le habrá escapado que los valores de x e y se han determinado (para facilitar la colocación de las marcas) a
partir de variables linea y columna, correspondientes a la posición deseada de la marca en la matriz.
El método fillRect asegura el dibujo del cuadrado:
en el color definido por:
Para dibujar el círculo rojo (corresponde, por ejemplo, a la marca del jugador n.°2), también se declaran tres
variables locales:
l xCentroCirculo: posición horizontal (en píxeles) del centro del círculo en el <canvas>,
l yCentroCirculo: posición vertical (en píxeles) del centro del círculo en el <canvas>,
l radioCirculo: radio del círculo (en píxeles).
El dibujo del círculo empieza por el método ya visto al dibujar la matriz del TicTacToe:
contextoCanvas.beginPath();
El dibujo del círculo se hace a través del método arc como sigue:
El relleno del círculo (en rojo), se hace como sigue:
contextoCanvas.fillStyle = "red";
contextoCanvas.fill();
Ejecución del script
La ejecución del script MORPION_03.htm da la siguiente visualización:
El conjunto del TicTacToe no se ha programado completamente en este capítulo. En él (por qué no usted mismo) se
pueden hacer muchas mejoras para obtener una buena aplicación, fundamentalmente:
l la posibilidad para los jugadores de seleccionar las celdas validadas con el ratón,
l un algoritmo que permita conceder puntos, por ejemplo, cuando cuatro marcas idénticas están alineadas vertical,
horizontal o diagonalmente,
l un sistema de contador de puntos,
l la grabación de los marcadores,
l la interrupción y el reinicio de una partida,
l ...
Estas optimizaciones se pueden llevar a cabo fácilmente y sería una buena ocasión para repasar las técnicas
estudiadas en los capítulos anteriores de este libro (algoritmia, gestión de eventos, almacenamiento local o remoto
en base de datos...).
Es recomendable consultar la multitud de ejemplos disponibles en Internet. Con ellos aprenderá a utilizar las
funcionalidades avanzadas de <canvas>, en particular para gestionar:
l los gráficos, paths, líneas y los estilos asociados,
l las formas (cuadrados, rectángulos, arcos, círculos, curvas (incluida la curva de Bézier o de segundo grado)),
l las imágenes,
l los textos (fuentes, colores, alineaciones...),
l los efectos (sombreado, degradado, transparencia, repetición...),
y encontrará los criterios de elección de un framework (librería) para facilitarle el trabajo durante sus
implementaciones más ambiciosas.
Existen múltiples soluciones que permiten elaborar gráficos de gestión (histogramas, representaciones en sectores,
nube de puntos...), disponibles en las páginas Web.
Estas herramientas son a menudo librerías escritas en PHP e incluso en Java. Algunos ejemplos son:
l JpGraph: http://jpgraph.net/
l JFreeChart : http://www.jfree.org/jfreechart/
l GraphoViz: http://www.graphviz.org/
l Highcharts JS: http://www.highcharts.com/
Por su parte, Google ha desarrollado una serie de API que permiten diseñar, de manera sencilla, gráficos de gestión
interesantes. Estos API se agrupan en la denominada Google Charts.
No se pretende reproducir todos los ejemplos propuestos por Google para ilustrar las diferentes y abundantes
posibilidades que ofrecen estos API. Nos conformamos aquí con proponer algunos ejemplos significativos.
Los ejemplos ofrecidos por Google están disponibles en la dirección: https://developers.google.com/chart/?hl=es
1. Ejemplo 1: Dibujar un histograma
El objetivo de este gráfico es sencillo. Se trata de asegurar la presentación como un histograma (barras verticales)
de la producción de un producto LAMBDA (expresado en toneladas) en tres países (Italia, Francia y España), para
los años 2010, 2011 y 2012.
Sobre el histograma, se dibujará una "línea punteada" con la media de la producción por año.
Sección HTML <body>
El código situado en esta sección será casi idéntico para todos los ejemplos de este capítulo. Aquí se reproduce
íntegramente:
</script>
</body>
Se diseña una capa ( chart_div) en este código para la visualización del gráfico (a través de la función
dibujarGrafico, integrada en la sección <head>):
Sección HTML <head>
Como para la sección anterior, el código fuente de esta sección se reproduce completamente a continuación:
/* Función dibujarGrafico */
function dibujarGrafico()
{
/* Instanciación de la gráfica */
var chart = new google.visualization.
ComboChart(document.getElementById(’chart_div’));
/* Diseño de la gráfica */
chart.draw(datos, opciones);
</script>
</head>
La primera secuencia específica de este ejemplo es la carga del API Google Charts:
Después se carga el módulo visualization (en versión 1) con el paquete dedicado a los gráficos básicos,
corechart:
Pasemos ahora al estudio de la única función ( dibujarGrafico) encargada de dibujar el gráfico.
La función empieza almacenando los datos que se han de representar gráficamente en una tabla en memoria:
Los nombres de los países y las referencias a los años servirán naturalmente de leyenda.
Hay opciones disponibles para afinar la presentación del gráfico. Puede encontrar el detalle de estas opciones en la
dirección de internet mencionada en el script.
Las opciones que se mantienen son:
var opciones =
{
title: ’Producción anual del producto LAMBDA por país’,
vAxis: {title: "Toneladas"},
hAxis: {title: "Años"},
seriesType: "bars",
series: {3: {type: "line"}}
};
Solo falta instanciar el gráfico y garantizar su representación, basándose en los datos almacenados en la tabla
datos y en opciones:
La representación efectiva se ejecuta finalmente con la siguiente sentencia:
El método setOnLoadCallback es una solución más eficaz que la llamada a la función dibujarGrafico
por un <body onload=’dibujarGrafico()’>.
Ejecución del script
Cuando se ejecuta el script COMBO.htm, obtenemos el siguiente resultado:
Vamos a tomar como ejemplo un grupo de clasificación para el mundial que se jugó en Brasil en el año 2014. Como
ejemplo, supongamos que en este grupo se enfrentaron los equipos nacionales de España, Suiza, Ecuador y
Honduras. El gráfico de sectores desarrollado muestra la probabilidad, acordada con algunos compañeros de
trabajo, de que cada uno de los equipos terminara primero de grupo.
Sección HTML <body>
El código fuente de esta sección no tiene ninguna particularidad y no se reproduce aquí.
Sección HTML <head>
Esta sección empieza como en el ejemplo anterior, con la carga del API Google Charts y del módulo
visualization (con el paquete corechart).
Detengámonos ahora en el código de la función dibujarGrafico:
/* Función dibujarGrafico */
function dibujarGrafico()
{
};
Los datos que se han de representar gráficamente se almacenan en una tabla llamada datos. El primer campo es
el nombre del país y el segundo, la probabilidad de terminar primero.
Ahora vienen las opciones de visualización.
En nuestro caso, se prevé la elección del color (colors) para cada uno de los sectores, el rojo para Suiza, el verde
para Ecuador, etc.
El argumento slices permite destacar los diferentes sectores del gráfico. Para que sirva de ejemplo, España, gran
favorita del grupo, tiene un sector con un valor de offset más grande que sus rivales.
La función termina como en el ejemplo 1, es decir, instanciando y representando el gráfico.
La visualización del gráfico en la capa HTML chart_div también se hace como en el ejemplo anterior, después del
terminar la función dibujarGrafico como sigue:
Cuando se ejecuta el script PIE.htm, obtenemos el siguiente resultado:
3. Ejemplo 3: Representación de un mapa
El objetivo de este ejemplo es representar en un mapa del mundo la posición geográfica de los cuatro países con
los que hemos trabajado en ejemplo anterior.
Sección HTML <body>
Una vez más, el código fuente de esta sección no tiene ninguna particularidad.
Sección HTML <head>
Esta sección comienza como en el ejemplo anterior, es decir, cargando el API Google Charts y el módulo
visualization. Hay una pequeña modificación porque se sustituye el paquete corechart por geochart.
En la función dibujarGrafico, encontrará el almacenamiento de los datos que se han de representar
gráficamente en una tabla:
La primera columna representa el nombre del país. Observe que es obligatorio utilizar la nomenclatura internacional
(ISO) a la hora asignar el nombre a los países; por tanto, Switzerland en lugar de Suiza, para que el país se puede
localizar correctamente en el mapa.
El valor de la segunda columna (llamada aquí Indicador) define la densidad del color que representa cada país.
La opción que se ha tomado ha sido seleccionar un valor común (500) para que los cuatro países se representen
con el mismo color verde (el color por defecto). Jugar con el valor de esta segunda columna habría sido interesante,
por ejemplo, si se hubiera querido comparar la población de cada país.
Ahora vienen las opciones habituales:
El argumento region sirve para indicar, en nuestro caso, que se quiere un mapa del mundo (también es posible
una visualización por continente, por país...).
El color de fondo (backgroundColor) del mapa es LightBlue. Esto colorea lógicamente los mares y océanos
en azul claro.
La opción fill da el color elegido (el verde) para identificar los países en el mapa. Los otros países aparecerán en
amarillo (opción datalessRegion).
Para terminar, no se ha previsto presentar una leyenda en el mapa.
Ejecución del script
4. Ejemplo 4: Representación de un indicador
La presentación de eventos o indicadores es un gran clásico. En este ejemplo, vamos a mostrar la velocidad en un
instante t de un coche en un gráfico de tipo contador de velocidad.
Sección HTML <body>
Una vez más, el código fuente de esta sección no tiene ninguna particularidad.
Sección HTML <head>
Esta sección empieza como en el ejemplo anterior, es decir, cargando el API Google Charts y el módulo
visualization (con el paquete gauge).
La función dibujarGrafico empieza como de costumbre, con el almacenamiento de los datos que se han de
La tabla tiene dos campos (columnas), Nombre y Valor, con un único registro.
La mención Km/h aparecerá en el contador de velocidad, así como la velocidad (210), por supuesto.
Las opciones de visualización son muchas. En nuestro caso, hemos elegido las siguientes:
Los argumentos width y height (expresados en píxeles) definen la longitud y la altura del indicador (contador de
velocidad).
Una parte del marcador del contador tendrá una zona amarilla entre 160 (yellowFrom) y 240 (yellowTo) Km/h,
y una segunda parte, una zona roja entre 240 ( redFrom) Km/h y 320 (redTo) Km/h.
Para terminar, el intervalo de la graduación del contador va de 0 Km/h (min) a 320 Km/h (max).
La función termina como en el ejemplo 1, instanciando y trazando el gráfico.
Ejecución del script
5. Ejemplo 5: Representación de un timeline
La ubicación de eventos en un eje temporal (timeline) es una presentación gráfica muy habitual.
Fijemos como objetivo representar gráficamente en un timeline los primeros presidentes del gobierno español en
democracia (Adolfo Suárez González, Leopoldo CalvoSotelo y Felipe González Márquez), haciendo referencia a la
duración de su mandato.
Sección HTML <body>
El código fuente de esta sección no tiene ninguna particularidad respecto a los ejemplos anteriores.
Sección HTML <head>
Como en el ejemplo anterior, esta sección empieza cargando el API Google Charts y el módulo visualization. El
paquete timeline sustituye al paquete gauge.
La definición de los datos que se han de representar gráficamente se hace en dos fases en la función
dibujarGrafico.
Empecemos por la descripción de la estructura de la tabla de datos:
El primer campo de tipo string servirá para almacenar el nombre y el apellido del presidente del gobierno.
El segundo campo, también de tipo string, permitirá almacenar la duración del mandato (los mandatos).
Los campos 3 y 4 sirven para configurar la longitud de la barra horizontal correspondiente a cada presidente.
Ahora mostramos los datos:
/* Líneas de datos */
datosTabla.addRows([
[’Adolfo Suárez González’, ’(1977-1981)’, new Date(1977, 3, 30),
new Date(1981, 2, 25)],
[’Leopoldo Calvo-Sotelo’, ’(1981-1982)’, new Date(1981, 2, 25),
new Date(1982, 12, 2)],
[’Felipe González Márquez’, ’(1982-1996)’, new Date(1982, 12, 2),
new Date(1996, 4, 4)]
]);
Observe el formato particular para las fechas de inicio y fin del mandato (año, mes y día).
Ahora vemos las opciones:
La opción colors indica el color reservado para cada presidente, azul (blue) para Adolfo Suárez González, por
ejemplo. Los nombres de los colores se pueden sustituir por los códigos hexadecimales asociados.
Puede consultar el resto de las abundantes opciones en la dirección:
https://developers.google.com/chart/interactive/docs/gallery/gauge
Como en todos los ejemplos de este capítulo, la función dibujarGrafico termina instanciando y trazando el
gráfico.
La ejecución de la visualización del gráfico en la capa HTML chart_div también se hace después del final de la
función dibujarGrafico.
Ejecución del script
El script TIMELINE.htm muestra lo siguiente:
En un desarrollo Web, como en cualquier aplicación informática, puede ser interesante generar sobre la marcha
documentos en formato PDF. Esto se usará mucho, por ejemplo, en un sitio web de compras, en el que el usuario
podrá recibir un factura, una confirmación de su pedido, etc.
Este formato de archivo es muy compacto y susceptible de utilizarse como elemento adjunto en un mail.
Para generar documentos en este formato, hay muchas soluciones, principalmente en JavaScript. Vamos a ver dos de
ellas a través de ejemplos concretos.
Debe saber que las librerías dedicadas en PHP también existen, principalmente FPDF (http://www.fpdf.org/) y son
conocidas por su simplicidad de utilización y eficacia.
1. Solución pdf24.org
El API pdf24 (propuesto en el sitio web http://es.pdf24.org/) es una solución relativamente sencilla. Es más que
suficiente para la creación de documentos PDF sencillos.
El API (librería que se debe instalar en su sitio web) está disponible para su descarga gratuita y se describe en la
dirección http://es.pdf24.org/JavaScriptpdfapi.html.
Estudiemos en detalle un script JavaScript de ejemplo. La mayor parte del código útil está en la sección HTML
<body>. El código se reproduce íntegramente a continuación. Se aportan comentarios detallados.
Sección HTML <head>
Es necesario instalar en su sitio web la librería pdf24.js. En la sección HTML <head>, esta librería se llama como
sigue:
Sección HTML <body>
/*
Creación del archivo PDF y configuración básica
*/
/* Instanciación de un nuevo documento */
var archivoPDF = new PDF24Doc();
/* Definición del juego de caracteres */
archivoPDF.setCharset("UTF-8");
/* Nombre del archivo (con el sufijo pdf que añade el API) */
archivoPDF.setFilename("test");
/* Definición del formato de la página (A4 en formato vertical) */
archivoPDF.setPageSize(210, 297);
El código empieza instanciando un nuevo documento PDF llamado archivoPDF mediante el constructor
PDF24Doc.
El juego de caracteres UTF-8 se asigna posteriormente.
El método setFilename del objeto archivoPDF permite asignarle un nombre. Observe que la extensión pdf se
añade automáticamente. El método setPageSize sirve para indicar el formato de la página (formato A4 en modo
vertical en nuestro caso).
Pasemos a la definición del contenido del documento en sí mismo:
/*
Creación del contenido del documento PDF
Instanciando un objeto PDF24Element, se crea el contenido del archivo, llamado contenidoPDF.
Tiene a su disposición varios métodos para asignar el contenido a esta variable contenidoPDF, principalmente:
l setTitle para definir un título al documento,
l setURL para que podamos hacer clic en el título del documento y acceder a la URL que se pasa como argumento,
l setAuthor para firmar el documento,
l setDateTime para poner fecha al documento,
l setBody para definir el contenido del documento.
En el ejemplo habrá observado que es posible realizar formateos sofisticados, integrando en el texto etiquetas HTML.
Falta asignar el elemento (es decir, la variable contenidoPDF) al objeto archivoPDF como sigue:
/*
Añadir el contenido en el documento PDF
*/
archivoPDF.addElement(contenidoPDF);
Por supuesto, es posible asignar a un mismo objeto de la clase PDF24Doc diferentes contenidos consecutivamente.
A continuación, aunque no es obligatorio, es posible programar el envío del archivo PDF (test.pdf en nuestro
caso) usando mensajería electrónica a un destinatario dado. Esto se tiene en cuenta en nuestro script:
/*
Configuración del envío del archivo PDF por mail
Como puede observar, esta secuencia de código no presenta ninguna dificultad particular; los nombres de los
métodos utilizados por el desarrollador de este API son muy explícitos.
En nuestro caso, el destinatario [email protected] recibirá un mensaje firmado por
[email protected] con el texto "Archivo creado por pdf24" como asunto y el texto
" El archivo PDF se adjunta a este mensaje. Cortesía de www.pdf24.org.". El archivo
test.pdf se envía como elemento adjunto en este mensaje.
El envío del mensaje es una secuencia de código opcional. Si no está, el API generará en su navegador una nueva
pestaña invitándole a:
l descargar el archivo PDF,
l enviar el archivo PDF a un destinatario, usando el correo electrónico (se le pedirá la dirección de correo del
destinatario),
l enviar el archivo PDF a un destinatario usando el fax (se le pedirá el número de fax del destinatario).
El script termina creando el documento con el método create aplicado al objeto archivoPDF:
/*
Creación del archivo PDF
*/
archivoPDF.create();
Ejecución del script
El script PDF_01.htm muestra lo siguiente:
2. Soluciones alternativas
Existen muchos API que generan documentos PDF. Su estudio está fuera del objetivo de este libro. Sin embargo,
puede considerar:
l El API jsPDF (http://parall.ax/products/jspdf ),
l El API de Adobe (http://www.adobe.com/devnet/acrobat/javascript.html ).
El API JavaScript de Adobe Systems es muy completo.
Recuerde que la empresa Adobe Systems es la creadora del formato de archivo PDF (Portable Document Format).
Fuente Wikipedia : Portable Document Format, normalmente conocido como PDF, es un lenguaje descriptivo de
páginas creado por la empresa Adobe Systems, cuya característica principal es conservar el formato de un
archivo tipos de letra, imágenes, objetos gráficos, etc. de una manera inalterada respecto al formato original
establecido por el autor del documento, independientemente del software, sistema operativo y ordenador
utilizados para imprimir o visualizar el documento.
El código QR (Quick Response) es un tipo de código de barras en dos dimensiones. Se compone de una yuxtaposición
de cuadrados negros (sobre fondo blanco).
Cada vez más, los códigos QR se están convirtiendo en verdaderas herramientas de marketing avanzadas con
integración del color o un logo. Es el caso de los siguientes ejemplos:
Este tipo de código se puede leer por muchos dispositivos de lectura:
l lector de código de barras compatible con códigos QR,
l teléfonos móviles (con sistema operativo iOS, Android...),
l webcam.
La lectura de un código QR, fundamentalmente a través de aplicaciones para smartphones, se relaciona
generalmente con:
l un acceso a un sitio Web, usando una URL,
l una consulta de un vídeo en línea (YouTube, Dailymotion...),
l un acceso a un punto geográfico en un mapa Google Maps o incluso Bing Maps,
l la adición de un mapa de visita virtual tipo vCard en una agenda electrónica,
l la adición de un evento en una aplicación de tipo agenda electrónica,
l una numeración telefónica,
l la visualización de texto donde el código QR puede «abarcar» un contenido textual (de pequeño tamaño),
l las aplicaciones de telepago (actualmente en fase experimental),
l ...
Como en el caso de los API de generación de documentos en formato PDF (véase el capítulo anterior), existen muchos
API que permiten la creación de códigos QR.
Vamos a ver, usando dos ejemplos, algunas de las posibilidades de los códigos QR:
l Ejemplo 1: Código QR que guarda el número de teléfono correspondiente a una llamada telefónica,
l Ejemplo 2: Código QR que guarda la URL de un sitio Web.
1. Ejemplo 1: Código QR que incluye un número de teléfono
Comentario del script
Para este primer ejemplo, vamos a utilizar el generador de códigos QR de la empresa IWWWIT: http://qrcode
generator.iwwwit.com/generateurqrcode.php
El inconveniente de la solución es que hay que transmitir (publicar en el sentido HTML del término) los argumentos
del código QR que se va a crear a un script PHP alojado por la empresa IWWWIT. Esto penaliza la integración de
esta solución en su propio desarrollo Web. Se trata de la elección técnica de la mayoría de las empresas que
ofrecen este tipo de dispositivo.
El código del script es muy simple. Es suficiente con transmitir, con un formulario dentro de la sección HTML <body>,
un conjunto de argumentos con destino a un script PHP puesto a nuestra disposición. Una vez que se tiene en
cuenta la información por este script, genera el código QR en una página Web (es justamente esto lo que resulta un
poco molesto desde el punto de vista de usabilidad).
A continuación se muestra el código del formulario:
Observe que la información (excepto el número de teléfono, que se le pedirá) se envía al script del servidor en modo
oculto (type="hidden").
Los valores de los atributos name e id se fijan por el script del servidor. No cambie tampoco la cláusula value del
botón de envío.
Ejecución del script
A continuación, como ejemplo, se muestra la interfaz de entrada de datos del número de teléfono:
El resultado se proporciona sin retraso alguno por la aplicación servidor como sigue:
2. Ejemplo 2: Código QR que incluye una URL
l el tamaño del código QR (dimensión del cuadrado expresado en píxeles),
l el texto de la URL.
Los argumentos se envían al API a través de una URL (y no con un formulario, como en el ejemplo 1).
La ventaja de la solución Google está en la manera en que se presenta el resultado, que se puede devolver
directamente a la página Web que ha servido para introducir los argumentos.
Estudiemos rápidamente el código del script.
Sección HTML <body>
Principalmente, esta sección incluye el formulario de entrada de datos de los dos argumentos mencionados con
antelación:
El formulario se sigue por:
Sección HTML <head>
Después de la etiqueta meta habitual ( [<meta
HTTP-equiv="Content-Type"] [content="text/html;
charset=utf-8" />]) y del título de la página Web, esta sección contiene la función generarQRCode.
/* Función generarQRCode */
function generarQRCode()
{
Tres de los cuatro argumentos que se envían con la URL al API Google son obligatorios:
l el argumento chs, que indica el tamaño del código QR (longitud x altura),
l el argumento cht, que indica que el API Google Charts debe generar un código QR (valor del argumento qr),
l el argumento chl, que contiene la URL a la que el código QR dará acceso.
El argumento choe es opcional. Sirve para indicar la codificación de los datos en el código QR (valores que hay que
elegir entre UTF-8 (valor por defecto), Shift_JIS e ISO-8859-1.
El script de la función termina visualizando el código QR (véase la imagen anunciada en la sección HTML) como sigue:
Ejecución del script