Introducción a Javascript
JavaScript (JS) es un lenguaje de programación, un mecanismo con el que podemos
indicarle al navegador qué tareas debe realizar, en qué orden y cuántas veces, entre
otras. Con JS agregamos comportamiento a nuestro sitio, permitiendo al usuario
interactuar con él, rompiendo con la idea de una web estática.
Junto con HTML y CSS es la tercera pieza fundamental del desarrollo web.
ECMAScript es el estándar que a partir del año 2015 a la actualidad se encarga de regir
como debe ser interpretado y funcionar el lenguaje JavaScript. En la actualidad, JS
puede ser interpretado y procesado por una multitud de plataformas, entre las que se
encuentran los navegadores web.
Versiones de ECMAScript
Javascript ha sufrido modificaciones que los navegadores han debido
implementar para proporcionar soporte a cada versión de ECMAScript
cuanto antes. La lista de versiones de ECMAScript es la siguiente:
Características de JavaScript
● Lenguaje del lado del cliente: El código se ejecuta en el cliente
(navegador). No se necesita acceso al servidor.
● Orientado a objetos: Utiliza clases y objetos como estructuras
reutilizables.
● De tipado débil o no tipado: No es necesario especificar el tipo de dato
al declarar una variable.
● De alto nivel: Su sintaxis se encuentra alejada del nivel máquina, más
cercano a un lenguaje de las personas.
Características de JavaScript
● Lenguaje interpretado: El navegador convierte las líneas de código en
el lenguaje de la máquina sin necesidad de realizar un proceso de
compilado.
● Muy utilizado por desarrolladores: Es uno de los lenguajes más
demandados de los últimos años por su versatilidad y su infinita
capacidad para crear plataformas cada vez más atractivas.
● Interactividad con el usuario: Podemos validar el formato de los datos
de un formulario (una dirección de email directamente desde el
navegador del cliente), ahorrando tiempo y recursos del servidor.
Comenzando con JavaScript
El código de nuestro script debe ser incorporado al código HTML, de forma
similar a lo que ocurre con las hojas de estilo CSS. Existen tres formas de
agregar código JavaScript a una página web. Una de ellas es utilizar la
etiqueta <script> en el <head> de nuestro documento (referencia interna):
<html>
<head>
<title>Título de la página</title>
<script>
[Link]("Hola!!!")
</script>
</head>
<body>
<p>Ejemplo de texto.</p>
Desde el inspector del navegador podremos ver que se escribe
</body>
</html>
el texto “Hola!!!” en la consola. Esto se logra a través de la
instrucción [Link]()
La ubicación de la etiqueta <script>
Según cómo esté ubicada la etiqueta <script> el navegador descarga
ejecuta el archivo JavaScript en momentos diferentes:
1. En <head>: antes de empezar a dibujar la página, cuando está en
blanco.
2. En <body>: cuando la página se haya dibujado hasta el <script>.
3. Antes de </body>: cuando la página se haya dibujado en su totalidad.
<script>
1. 2. 3.
La consola de JavaScript
Para acceder a la consola Javascript del navegador pulsamos CTRL+SHIFT+J.
Un clásico ejemplo utilizado cuando se comienza a programar es crear un
programa que muestre por pantalla un texto, generalmente el texto «Hola
Mundo». O mostrar el resultado de alguna operación matemática. A
continuación, el código JS para realizar ambas tareas, y la salida que
podemos ver en la consola del navegador:
[Link]("Hola Mundo");
[Link](2 + 2);
La consola de JavaScript
Podemos mostrar texto, valores numéricos, etc. separados por comas:
[Link]("¡Hola a todos! Observen este número: ", 5 + 18);
En esta consola podemos escribir funciones o sentencias de JavaScript que
se ejecutan en la página que se encuentra en la pestaña actual del
navegador. De esta forma podemos observar los resultados que nos
devuelve en la consola al realizar diferentes acciones.
La consola de JavaScript
JS posee, además de [Link], varias instrucciones similares para
interactuar con el desarrollador:
Incorporando un archivo externo
Podemos vincular al documento HTML un archivo con extensión .js usando
la etiqueta <script>, haciendo referencia al nombre del archivo JavaScript
con el atributo src (source):
<html>
<head>
<title>Título de la página</title>
<script src="[Link]"></script>
</head>
<body>
<p>Ejemplo de texto.</p>
</body>
</html>
Los archivos .js se suelen incorporar en una carpeta llamada “js”.
Comentarios
Los comentarios son utilizados por los programadores para anotaciones. No
son tenidos en cuenta por el navegador.
Comentario de línea // esto es un comentario de línea
/*
Comentario de bloque esto es un comentario de bloque (multilínea)
*/
Son un buen recurso cuando queremos omitir la ejecución de ciertas
instrucciones.
Variables | ¿Qué son?
Es un pequeño espacio en la memoria, donde se guarda un dato. Podemos
imaginarlas como “cajitas” dentro de nuestro programa. Tienen tres
características:
● Nombre: debe ser representativo de la información que contiene. Se utiliza
para diferenciar unas de otras y hacer referencia a ellas.
● Tipo de dato: puede ser número, texto, valores booleanos, etc.
● Contenido: el valor concreto que posee el dato almacenado.
Se llaman variables porque pueden cambiar su valor a lo largo del
programa. Un programa puede tener muchas variables, y cada una de ellas
tendrá un nombre que la identifique, un valor y un tipo de dato.
Variables | ¿Cómo se declaran?
Una variable que se ha declarado con var pero a la que no se le asignó un
valor se dice que está indefinida (no conocemos el tipo de dato):
var num3;
En este caso la variable está “vacía”, no está definido el valor que colocará en
memoria. No se ha asociado ningún contenido a esa variable.
var num4 = 5;
Las sentencias en JS finalizan con “;”. La imagen anterior corresponde a la
declaración de la variable “num4” con un valor numérico entero de “5”.
Variables | ¿Cómo se nombran?
Los nombres de las variables (o identificadores) permiten distinguir una de
otras. Para asignar los nombres de las variables debemos seguir ciertas
reglas:
Un identificador de JavaScript debe comenzar con una letra, un guión bajo (
_ ) o un signo de dólar ( $ ). Los siguientes caracteres también pueden ser
dígitos ( 0 - 9 ). JavaScript distingue entre mayúsculas y minúsculas (es case-
sensitive).
Se recomienda usar la escritura camelCase en el nombre de variables que
tienen más de una palabra.
Variables
Podemos cambiar el valor de una variable durante el flujo del programa:
var IVA= 21;
IVA= 10.5;
[Link](IVA);
El = es el operador de asignación, y permite asignar un valor a una variable.
Ese valor puede ser el resultado de una operación aritmética, que se evalúa y
luego se asigna su resultado a la variable:
var resultado= (1 + 3) * 2;
Luego de ejecutar esa línea, la variable “resultado” contiene el valor “8”.
Constantes
El concepto de constante es similar al de variable, con la salvedad de que la
información que contiene es siempre la misma (no puede variar durante el
flujo del programa). Declaramos las constantes utilizando const. Su sintaxis
es:
const PI= 3.141592;
const IVA= 21;
Si intentamos modificar el valor de una constante, obtenemos un error:
const IVA= 21;
IVA= 10.5;
[Link](IVA);
Tipos de datos
Las variables de JavaScript pueden contener distintos tipos de datos:
numérico, cadena de caracteres, lógicos, indefinido, null, objetos y más. El
tipo de dato es la naturaleza del contenido de la variable o constante.
JavaScript tiene tipado dinámico, es decir que la misma variable se puede
utilizar para contener diferentes tipos de datos:
var x; // ahora x es indefinido (no tiene un valor definido)
x = 5; // ahora es numérico (5)
x = "Juan"; // ahora es una cadena de caracteres o string ("Juan")
JavaScript deduce cuál es el tipo de dato de la variable. El tipo de dato
asociado a esa variable lo determina el dato que se almacena en ella. Y si
luego se le asigna un valor de otro tipo, el tipo de la variable cambia.
Tipos de datos
Los tipos de datos en JavaScript son los siguientes:
Tipos de
datos
primitivos
Tipos de datos
El último estándar ECMAScript define nueve tipos de datos:
• Seis tipos de datos primitivos +info
• Undefined +info
• Boolean +info
• Number +info
• String +info
• BigInt +info
• Symbol +info
• Null (tipo primitivo especial) +info
• Object +info
• Function +info
Identificar el tipo de dato de una variable
Para determinar qué tipo de dato tiene una variable utilizamos typeOf(), que
devuelve el tipo de dato primitivo asociado a una variable:
var s = "Hola, me llamo Juan"; // s, de string
var n = 28; // n, de número
var b = true; // b, de booleano
var u; // u, de undefined
[Link](typeof s);
[Link](typeof n);
[Link](typeof b);
[Link](typeof u);
Las variables numéricas
En JavaScript, los números constituyen un tipo de datos básico (primitivo).
Para crear una variable numérica basta con escribirlas. No obstante, dado
que en Javascript “todo es un objeto”, también podemos declararlas como si
fuesen un objeto:
// Declarados como literales // Declarados como objetos
const n1 = 4; const n1 = new Number(4);
var n2 = 15.8; var n2 = new Number(15.8);
Objeto Number
Number es el objeto primitivo que permite representar y manipular valores
numéricos. El constructor Number contiene constantes y métodos para
trabajar con números. Valores de otro tipo pueden ser convertidos a
números usando la función Number(). Su sintaxis es:
var a = new Number('123'); // a es igual a 123
var b = Number('123'); // b es igual a 123
[Link]("a: ", a);
[Link]("b: ", b);
Creamos el objeto a mediante el constructor y guardamos en b el valor de la cadena ‘123’
en forma de número. Mostramos en consola ambos elementos.
Comprobaciones numéricas
Varias funciones de JS permiten conocer la naturaleza de una variable
numérica (número finito, número entero, número seguro o si no es
representable como un número). Devuelven true o false (un valor booleano).
Las podemos ver en la siguiente tabla:
Comprobaciones numéricas
Veamos dos ejemplos para cada una de estas funciones:
// ¿Número finito?
[Link](42); // true
[Link](Infinity); // false, es infinito
// ¿Número entero?
[Link](5); // true
[Link](4.6); // false, es decimal
// ¿Número seguro?
[Link](1e15); // true
[Link](1e16); // false, es un valor
no seguro
// ¿No es un número?
[Link](NaN); // true
[Link](5); // false, es un número
Conversión numérica
Es posible convertir cadenas de texto en números, para posteriormente
realizar operaciones con ellos. Las funciones de parseo numérico, parseInt()
y parseFloat(), permiten realizar esto:
Conversión numérica
Veamos un ejemplo con parseInt(). Recibe como parámetro un texto que
queremos convertir a número:
[Link]("42"); // 42
[Link]("42€"); // 42
[Link]("Núm. 42"); // NaN
[Link]("A"); // NaN
parseInt() funciona con variables de texto que contienen números o que comienzan por
números. Sin embargo, si la variable de texto comienza por un valor que no es numérico,
parseInt() devuelve un NaN (Not a Number).
Conversión numérica
Si utilizamos parseInt() con dos parámetros, donde el primero es el texto
con el número y el segundo es la base numérica del número, se realiza la
conversión de tipo respetando la base elegida:
[Link]("11101", 2); // 29 en binario
[Link]("31", 8); // 25 en octal
[Link]("FF", 16); // 255 en hexadecimal
Esta modalidad de parseInt() se utiliza para pasar a base decimal un número que se
encuentra en otra base (binario, octal, hexadecimal, etc.) parseFloat() funciona
exactamente igual, pero en lugar de operar con números enteros opera con números en
coma flotante.
Operadores de cadena y números
Los operadores + y += también se pueden utilizar para agregar (concatenar)
cadenas. En este contexto, el operador + se denomina operador de
concatenación.
var txt1 = "Juan"; var txt4 = "Bienvenidos ";
var txt2 = "Pablo"; txt4 += "a Javascript";
var txt3 = txt1 + " " + txt2; [Link](txt4);
[Link](txt3);
Agregar dos números devolverá la suma, pero agregar un número y una cadena devolverá
una cadena.
La función prompt()
La función prompt es un método del objeto Window. Se utiliza para
solicitarle al usuario que ingrese datos por medio del teclado. Recibe dos
parámetros: el mensaje que se muestra en la ventana y el valor inicial del
área de texto. Su sintaxis es: variable = prompt(mensaje, valor inicial)
<script>
var nombre = prompt ("Ingrese su nombre", "")
[Link]( "Hola " + nombre)
</script>
Uso de [Link]()
[Link]() nos permite escribir directamente dentro del propio
documento HTML.
<html>
<head>
<title>Título de la página</title>
<script>
[Link]("Hola mundo (HTML)");
</script>
</head>
<body>
</body>
</html>
Condicionales y Ciclos
Operadores lógicos y
relacionales
Operadores de comparación
Un operador de comparación (o relacional) Operador Descripción
compara sus operandos y devuelve un valor == igual a
lógico en función de si la comparación es
verdadera (true) o falsa (false). Los operandos === igual valor y tipo
pueden ser valores numéricos, de cadena, != no igual a
lógicos u objetos. Las cadenas se comparan
según el orden lexicográfico estándar. En la !== igual valor no tipo
mayoría de los casos, si los dos operadores no > mayor que
son del mismo tipo, JavaScript intenta
convertirlos a un tipo apropiado para la < menor que
comparación. Este comportamiento >= mayor o igual que
generalmente resulta en comparar los
<= menor o igual que
operadores numéricamente.
? operador ternario
Estructuras de control | If / else
Si utilizamos if seguido de un else podemos establecer una acción “A” si se
cumple la condición, y una acción “B”.
Modificamos el ejemplo anterior var nota = 7;
para mostrar también un mensaje [Link]("El examen ha resultado:");
cuando estamos suspendidos, pero // Condición
en este caso, en lugar de mostrar el if (nota < 5) {
mensaje directamente con
[Link] guardamos el texto en
// Acción A (nota es menor que 5)
una nueva variable llamada calificacion = "suspendido";
calificación: } else {
// Acción B: (nota es mayor o igual que 5)
calificacion = "aprobado";
}
[Link]("Estoy", calificacion);
Estructuras de control | Operador ternario
El operador ternario es una alternativa de condicional if/else con una
sintaxis más corta y, en muchos casos, más legible. Los dos scripts siguientes
hacen lo mismo. El primero usa if/else, el segundo el operador ternario:
if (nota < 5) {
calificacion = "suspendido";
} else {
calificacion = "aprobado";
}
[Link]("Estoy", calificacion)
;
// Operador ternario: (condición ? verdadero : falso)
var calificacion = nota < 5 ? "suspendido" : "aprobado";
[Link]("Estoy", calificacion);
Estructuras de control | If múltiple
Para analizar más de 2 condiciones podemos anidar varios if/else uno dentro
de otro, de la siguiente forma:
var nota = 7;
[Link]("He realizado mi examen.");
// Condición
if (nota < 5) {
calificacion = "Insuficiente";
} else if (nota < 6) {
calificación = "Suficiente";
} else if (nota < 8) {
calificacion = "Bien";
} else {
calificacion = "Sobresaliente";
}
[Link]("He obtenido un", calificacion);
Estructuras de control | Switch
La estructura de control switch permite definir
casos específicos a realizar en el caso de que la
variable expuesta como condición sea igual a los
valores que se especifican a continuación
mediante los case.
Con los if múltiples podemos controlar valores
comprendidos en un rango. Con switch esto no es
posible, ya que solo permite valores concretos y
específicos.
Al final de cada caso es necesario indicar un
break para salir del switch. Si no se hace esto, el
programa pasa automáticamente al siguiente
case, aunque no se cumpla la condición
específica.
Estructuras de control | If con && (AND)
Podemos combinar el If con los operadores lógicos && (AND) y || (OR) para
describir condiciones más complejas.
Utilizando && (AND) deben cumplirse todas las condiciones para que la
proposición sea verdadera. Caso contrario, será falsa.
var altura = 0;
var edad = 0;
altura = parseFloat(prompt("Ingrese la altura"));
edad = parseInt(prompt("Ingrese la edad"));
if (altura > 1.30 && edad > 14) {
[Link]("Cumple con los requisitos");
} else{
[Link]("No cumple con los requisitos");
Estructuras de control | If con || (OR)
Utilizando || (OR) basta con que se cumpla una de las condiciones para que
la proposición sea verdadera. En caso de que todas las condiciones sean
falsas, la proposición será falsa.
var color;
color = prompt("Ingrese el color del auto");
if (color == "Rojo" || color == "Verde") {
[Link]("El auto pertenece a la categoría A");
} else{
[Link]("El auto pertenece a la categoría B");
}
Estructuras de control | Bucles e Iteraciones
Una de las principales ventajas de la programación es la posibilidad de crear
bucles y repeticiones para tareas específicas, evitando realizarlas varias veces
de forma manual. Existen muchas formas de realizar bucles, y analizaremos
los más básicos, similares en otros lenguajes de programación:
Estructuras de control | Bucles e Iteraciones
Conceptos básicos sobre bucles:
● Condición: Al igual que en los if, en los bucles se va a evaluar una
condición para saber si se debe repetir el bucle o finalizarlo.
Generalmente, si la condición es verdadera, se repite. Si es falsa, se
finaliza.
● Iteración: Se llama así a cada repetición de un bucle. Por ejemplo, si un
bucle repite una acción 10 veces, se dice que realiza 10 iteraciones.
● Contador: Muchas veces, los bucles tienen una variable que se
denomina contador, porque cuenta el número de repeticiones que ha
hecho, hasta llegar a un número concreto y finalizar. Dicha variable debe
ser inicializada (crearla y darle un valor) antes de comenzar el bucle.
Estructuras de control | Bucles e Iteraciones
● Incremento: Cada vez que un bucle finaliza, se suele realizar el
incremento (o decremento) de una variable, generalmente de la
denominada variable contador.
● Bucle infinito: Se trata de la situación que tiene lugar cuando en un
bucle no se modifica (incrementando o decrementando) la variable
contador, o cuando escribimos una condición que nunca tiene lugar. En
esos casos, el bucle se repite eternamente, sin que el flujo del programa
pueda continuar. Cuando esto ocurre, se suele decir que “el programa
se queda colgado”.
Estructuras de control | While (mientras)
El bucle while se usa cuando el fin de la repetición de ciclos depende de una
condición (*). Analicemos el siguiente ejemplo y todas sus partes, para comprender
qué ocurre en cada iteración del bucle:
i = 0; // Inicialización de la variable contador
// Condición: Mientras la variable contador sea menor de 5
while (i < 5) {
[Link]("Valor de i:", i);
i = i + 1; // Incrementamos el valor de i
}
(*) Es muy importante que esa condición en un momento deje de ser verdadera, para
evitar que ocurra un loop infinito.
Estructuras de control | While (mientras)
En el ejemplo anterior:
● Antes de entrar en el bucle while, se inicializa la variable i a 0.
● Antes de realizar la primera iteración del bucle, comprobamos la
condición.
● Si la condición es verdadera, hacemos lo que está dentro del bucle.
● Mostramos por pantalla el valor de i y luego incrementamos el valor
actual de i en 1.
● Volvemos al inicio del bucle para hacer una nueva iteración.
Comprobamos de nuevo la condición del bucle.
● Cuando la condición sea falsa, salimos del bucle y continuamos el
programa.
Estructuras de control | While (mientras)
Detalle paso a paso de las iteraciones del ejemplo:
Estructuras de control | For (para)
La sintaxis de un bucle for , uno de los más usados, es más compacta y
rápida de escribir que la de un bucle while. Requiere inicializar la variable,
determinar la condición y definir el incremento al comienzo del bucle. Se
suele usar cuando se conoce de antemano cuantas repeticiones se tienen
que hacer.
Ejemplo: Mostrar por pantalla los Ejemplo: Mostrar por pantalla los
números enteros del 1 a 10. múltiplos de 2 hasta 100.
for (var i=1; i<=10; i++) { for (var i=2; i<=100; i+=2) {
[Link](i); [Link](i);
} }
Estructuras de control | For (para)
El bucle for es uno de los más utilizados en la programación. Veamos el
ejemplo anterior utilizando este bucle:
// for (inicialización; condición; incremento)
for (i = 0; i < 5; i++) {
[Link]("Valor de i:", i);
}
En programación es muy habitual empezar a contar desde cero. Mientras
que habitualmente contamos de 1 a 10, en programación de 10 elementos se
cuentan de 0 a 9.
Artículos de interés
● Expresiones y operadores en JavaScript, incluyendo los de asignación, comparación,
aritméticos, bit a bit, lógicos, ternarios, de cadena y otros.
● Tomando decisiones en tu código - condicionales, en [Link]
● ¿Cómo utilizar bucles en JavaScript?
● Bucle For en [Link]
● Bucle While en [Link]
Programación modular con
funciones
Funciones
Las funciones son estructuras esenciales dentro del código. Una función es
un grupo de instrucciones que constituyen una unidad lógica del programa
y resuelven un problema muy concreto. Presentan varias ventajas, entre ellas
las de permitir dividir un problema complejo en partes menores y más
simples, reutilizar código en el mismo o en otro programa, simplificar
la depuración, etcétera.
JavaScript proporciona al usuario una serie de funciones implementadas y
listas para utilizar. Sin embargo, no es difícil encontrar situaciones en las que
necesitamos realizar alguna tarea para la cual no existe una función
disponible, y debemos utilizar los mecanismos que nos proporciona JS para
construir nuestras propias funciones.
Programación modular
La metodología de división por módulos se conoce
habitualmente como “divide y vencerás” y en programación se
llama Desarrollo Top Down.
¿Cuál será la estrategia para resolver problemas? Pensar en el
problema general e ir descomponiéndolo en sub-problemas
(sub-algoritmos). A su vez, estos subproblemas se podrán seguir
dividiendo hasta llegar a un subproblema lo bastante simple como
para poder resolverse de forma sencilla.
Abstracción
Podemos definir la abstracción como el aislamiento de un elemento de su
contexto o del resto de los elementos que lo acompañan. En programación la
abstracción está relacionada con “qué hace”.
Concretamente, la abstracción se produce cuando creamos módulos.
Lo importante, para entender el concepto de abstracción, es comprender que
cada módulo es independiente de los demás módulos (bajo acoplamiento)
y que es ideal que realice una sola tarea (alta cohesión).
Los módulos son independientes entre sí, aunque algunos pueden necesitar
colaborar con otros, o trabajar de forma conjunta.
Funciones
Las funciones nos permiten agrupar líneas de código en tareas con un nombre
(subprograma), para que posteriormente podamos referenciar ese nombre para
realizar dicha tarea. Algunas razones para declarar funciones:
● Simplificación: Cuando un conjunto de instrucciones se va a usar muchas veces, se crea
una función con esas instrucciones y se llama la cantidad de veces que sea necesario,
reduciendo un programa complejo en unidades más simples.
● División: Una función me permite modularizar, es decir, armar módulos. De esta manera un
equipo puede dividir el trabajo en partes. Cada integrante realiza una función, para luego
integrarlas en un programa principal más grande.
● Claridad: Usando funciones un programa gana claridad, aunque esa función solo se llame
una vez.
● Reusabilidad: Una función es reutilizable, sólo es necesario cambiar los valores de entrada.
Funciones
Para usar funciones es necesario hacer dos cosas:
● Declarar la función: crear la función es darle un nombre, definir los datos de entrada
(opcional) e indicar las tareas (instrucciones) que realizará y qué valor retornará
(opcional).
● Ejecutar la función: «Llamar» (invocar) a la función para que realice las tareas del
código que aloja. Se puede invocar una misma función la cantidad de veces que se
necesita desde el programa principal.
// Declaración de la función "saludar" // Ejecución de la función
function saludar() { saludar()
// Contenido de la función Segundo paso:
[Link]("Hola, soy una función") Primer paso: Ejecutarla
} Declarar la función
Funciones
El nombre de la función tiene que ser significativo y describir lo que hace.
Los nombres de las funciones tienen las mismas características que los de
las variables. Idealmente deben ser:
● Nombres simples, claros.
● Representativos de la tarea que realiza la función.
● Verbos en infinitivo (-ar, -er, -ir).
● Si es más de una palabra, utilizar la nomenclatura camelCase.
Es necesario definir los datos de entrada (si existen) e incluir las
instrucciones necesarias para que realice su tarea. Opcionalmente se puede
definir qué valor retornará.
Funciones | Ejemplo
Este código muestra la tabla for (i = 1; i <= 10; i++) {
[Link]("1 x", i, "=", 5 * i)
de multiplicar por 5. }
Este código muestra la tabla // Primera vez
for (i = 1; i <= 10; i++) {[Link]("5 x", i, "=", 5 * i)}
de multiplicar por 5 tres
// Segunda vez
veces. Funciona, pero usa for (i = 1; i <= 10; i++) {[Link]("5 x", i, "=", 5 * i)}
demasiado código, repetido. // Tercera vez
for (i = 1; i <= 10; i++) {[Link]("5 x", i, "=", 5 * i)}
Solución con bucle y //Declaración de la función tablaDelCinco()
function tablaDelCinco(){
función. La función
for (i = 1; i <= 10; i++){[Link]("5 x", i, "=", 5 * i)}
tablaDelCinco() usa un for }
de 10 iteraciones. El otro for //Bucle que ejecuta 3 veces la función tablaDelCinco()
ejecuta la función 3 veces. for (let i = 1; i <= 3; i++) {tablaDelCinco()}
Funciones | Clasificación
Según reciban o no datos, y devuelvan o no valores, las funciones se pueden
clasificar en:
Funciones sin parámetros:
● Que no devuelven valores
● Que devuelven valores
Funciones con parámetros:
● Que no devuelven valores
● Que devuelven valores
Funciones | Parámetros y Argumentos
Los parámetros son las variables que ponemos cuando se define una
función. En la siguiente función tenemos dos parámetros “a” y “b”:
function sumar(a, b){
[Link](a + b)
}
Los argumentos son los valores que se pasan a la función cuando ésta es invocada, “7” y
“4” en el ejemplo:
var suma = sumar(7, 4) //Pedimos valores
Dentro de la función, los argumentos se copian en los parámetros y son usados por ésta
para realizar la tarea.
Funciones | Parámetros y Argumentos
Esta función tiene un sólo parámetro que indica hasta qué valor calculará:
// Declaración //Ejecución
function tablaMultiplicar(hasta) { tablaMultiplicar(4)
for (var i = 1; i <= hasta; i++)
[Link]("1 x", i, "=", 1 * i)
}
En este ejemplo la función muestra un texto concatenado a un argumento pasado por
parámetro:
// Declaración //Ejecución
function saludarDos(miNombre){ saludarDos("Codo a Codo") //Argumento fijo
[Link]("Hola " + miNombre) var nombre= prompt("Ingrese su nombre")
} saludarDos(nombre) //Argumento variable
Funciones | Parámetros múltiples
Cuando se utilizan parámetros múltiples hay que respetar el orden en que
los declaramos y el de los argumentos usados al llamarla. Esta función tiene
dos parámetros: el valor de la tabla a generar y hasta qué valor calculará.
// Declaración
function tablaMultiplicar(tabla, hasta) {
for (var i = 1; i <= hasta; i++)
[Link](tabla + " x " + i + " = ", tabla * i)
}
// Ejecución
tablaMultiplicar(1, 10) // Tabla del 1, calcula desde el 1 hasta el 10
tablaMultiplicar(5, 8) // Tabla del 5, calcula desde el 1 hasta el 8
Funciones | Parámetros múltiples
Ejemplo con tres parámetros. Se evalúa la mayoría de edad de una persona:
// Declaración
function mayoriaEdad(miApellido, miNombre, miEdad){
[Link]("Apellido y nombre: " + miApellido + ", " + miNombre)
if (miEdad >= 18) {
[Link]("Es mayor de edad " + "(" + miEdad + ")")}
else{
[Link]("No es mayor de edad " + "(" + miEdad + ")")}
}
//Ejecución
var ape= prompt("Ingrese su apellido") Esta función recibe tres parámetros y
var nom= prompt("Ingrese su nombre") en función del valor de uno de ellos
var edad= prompt("Ingrese su edad") (miEdad) determina si la persona es
mayoriaEdad(ape, nom, edad) mayor de edad (>=18)
Parámetros predeterminados
function multiplicar(a, b = 1) {
Los parámetros predeterminados de return a * b;
función permiten que los parámetros con }
nombre se inicien con valores [Link](multiplicar(5, 2)); // salida: 10
predeterminados si no se pasa ningún [Link](multiplicar(5)); // salida: 5
valor o undefined.
En JavaScript, los parámetros de función
están predeterminados en undefined. Sin
embargo, a menudo es útil establecer un
valor predeterminado diferente.
Funciones | Devolución de valores
Una función puede devolver información, para ser utilizada o almacenada en
una variable. Se utiliza la palabra clave return, que regresa un valor y finaliza
la ejecución de la función. Si existe código después del return, nunca será
ejecutado. Puede haber más de un return por función.
// Declaración
function sumar(a, b) {
return a + b // Devolvemos la suma de a y b al exterior de la función
}
// Ejecución
var a = 5, b = 5
var resultado = sumar(a, b) // Se guarda 10 en la variable resultado
[Link]("La suma entre "+ a +" y "+ b +" es: "+ resultado)
Funciones | Devolución de valores
Veamos dos funciones que hacen lo mismo, una retorna valores y otra no:
function sumar(num1, num2){ Esta función muestra “La suma es …” en la
var suma = num1 + num2 consola, pero no retorna ningún valor al
[Link]("La suma es " + suma)
}
programa.
sumar(2,5)
function sumarDos(num1, num2){
var suma = num1 + num2
En este caso la función devuelve un valor, y
return suma se almacena en una variable llamada
} resultado que contiene la suma de dos
n1 = 2 valores realizada por la función sumarDos.
n2 = 3
var resultado = sumarDos(n1, n2)
[Link]("El resultado es: " + resultado)
Funciones | Devolución de valores
Otra alternativa es hacer que la función guarde directamente el resultado
que devuelve en una variable:
var suma = function sumarTres(numero1, numero2) { Al retornar un valor, éste se guarda
return numero1 + numero2 en la variable suma.
}
[Link](suma(40, 15))
var numeroMaximo = function (valor1, valor2) { En este caso se piden dos valores
if (valor1 > valor2) { return valor1 } y si la condición no se cumple se
return valor2
}
asume que el valor2 es el
var v1 = parseInt(prompt("Ingrese un número entero")) máximo (no es necesario un else)
var v2 = parseInt(prompt("Ingrese otro número entero"))
[Link]("El número máximo es:", numeroMaximo(v1,v2)
)
Funciones | Función flecha (arrow Function)
En JavaScript existe la forma resumida de escribir las funciones. Se llaman
funciones flecha, en alusión a =>. Permiten definir funciones de manera
más fácil, breve y rápida, aunque están limitadas a funciones más simples.
Para crear estas funciones flecha partiremos del ejemplo:
// Función tradicional // Función Flecha (Arrow)
function cuadrado(x){ var aCuadrado = x => x*x
return x*x [Link](aCuadrado(2))
}
[Link](cuadrado(2))
x es el parámetro. A la derecha de la flecha agregamos el contenido de la
función, que es lo que se va a retornar.
Funciones | Función flecha (arrow Function)
Si existe más de un parámetro, hay que usar paréntesis:
function sumar (num1,num2) { var aSumar = (num1,num2) => num1+num2
return num1+num2 [Link](aSumar(5,7))
}
[Link](sumar(4,6)) Mantenemos los parámetros entre paréntesis y
colocamos a la derecha lo que devolverá la función.
// Función tradicional // Función Arrow
function multiplicar (num1,num2) { var aMultiplicar = (num1,num2) =>
producto= num1*num2 {
return producto producto= num1*num2
} return producto
[Link](multiplicar(2,3)) }
[Link](aMultiplicar(6,7))
Función flecha de varias líneas.
Funciones | Función flecha (arrow Function)
Existen varias formas de declarar una función flecha. Cada paso a lo largo
del camino es una función flecha válida:
function (a){ // Función tradicional
return a + 100
}
// Desglose de la función flecha
// 1. Elimina la palabra "function" y coloca la flecha entre el argumento y las llaves de
apertura.
(a) => { return a + 100 }
// 2. Quita los llaves{} del cuerpo y la palabra "return" (el return está implícito).
(a) => a + 100
// 3. Suprime los paréntesis de los argumentos
a => a + 100
Funciones | Función flecha - Sintaxis básica
//Un parámetro. Con una expresión simple no se necesita return:
param => expression
//Varios parámetros requieren paréntesis. Con una expresión simple no se necesita return:
(param1, paramN) => expression
//Las declaraciones de varias líneas requieren llaves y return:
param => {
let a = 1
return a + b
}
//Varios parámetros requieren paréntesis. Las declaraciones de varias líneas requieren llaves
y return:
(param1, paramN) => {
let a = 1
return a + b
}
Funciones | Función anónima
Las funciones anónimas son un tipo de funciones que se declaran sin
nombre de función y se alojan en el interior de una variable y haciendo
referencia a ella cada vez que queramos utilizarla:
En la consola mostramos el contenido // Función anónima "saludo"
de la variable (sin ejecutarla, no hay const saludo = function () {
paréntesis) y nos devuelve la función en return "Hola"
sí. }
Luego ejecutamos la función
contenida en la variable.
// Función anónima "saludo"
const saludo = function (nombre) {
var mensaje = "Hola " + nombre
Las funciones anónimas también return mensaje
permiten utilizar parámetros }
Scope (alcance)
El scope (alcance) determina la accesibilidad (visibilidad) de las variables.
Define ¿en qué contexto las variables son visibles y cuándo no lo son?. Una
variable que no está “al alcance actual” no está disponible para su uso.
En JavaScript hay dos tipos de alcance:
● Alcance local (por ejemplo, una función)
● Alcance global (entorno completo de JavaScript)
Las variables definidas dentro de una función no son accesibles (visibles)
desde fuera. La función “crea un ámbito cerrado” que impide el acceso a
una variable de su interior desde fuera de ella o desde otras funciones.
Scope (alcance) | Variables locales
En el siguiente ejemplo creamos una variable llamada carName a la cual le
asignamos un valor:
// aca no puedo usar la variable carName Podremos acceder al contenido de la
function myFunction() {
variable carName solamente dentro de la
var carName = "Volvo"
// aca si puedo usar la variable carName función.
}
// aca no puedo usar la variable carName
Este tipo de variables son de alcance local, porque solamente valen en el
ámbito de la función, y no en el ámbito a nivel de programa. Los parámetros
de la función funcionan como variables locales dentro de las mismas.
Scope (alcance) | Variables globales
Una variable declarada fuera de una función se convierte en global. Esto
quiere decir que tiene alcance global: todos los scripts y funciones de una
página web pueden acceder a ella.
var carName2 = "Fiat" En este caso podremos acceder
// aqui si puedo usar carName2 al contenido la variable
function myFunction() { carName tanto desde fuera
// aqui tambien puedo usar la variable carName2 como desde adentro de la
}
función
El alcance determina la accesibilidad de variables, objetos y funciones de
diferentes partes del código.
Scope (alcance) | Variable automáticamente global
Si asignamos un valor a una variable que no ha sido declarada, se convertirá
en una variable global. Este ejemplo declara la variable global carName,
aún cuando su valor se asigna dentro de una función.
myFunction(); En este caso podremos acceder al
// aquí puede se puede usar carName
function myFunction() {
contenido la variable carName tanto
carName = "Volvo" // variable no declarada desde fuera como desde adentro de la
} función por ser automáticamente global.
La vida útil de una variable comienza cuando se declara. Las variables locales
se eliminan cuando se completa la función.
let y var
let declara una variable de alcance local, limitando su alcance (scope) al
bloque, declaración, o expresión donde se está usando. var define una
variable global o local en una función sin importar el ámbito del bloque.
var a = 5
var b = 10
if (a === 5) {
let a = 4 // El alcance es dentro del bloque if
var b = 15 // El alcance es global, sobreescribe a 10
[Link](a) // 4, por alcance a nivel de bloque
[Link](b) // 15, por alcance global
}
[Link](a) // 5, por alcance global
[Link](b) // 15, por alcance global
Callbacks (devolución de llamada)
Las funciones en JavaScript son objetos. Como cualquier otro objeto, se
pueden pasar como parámetro. Por lo tanto, podemos pasar una función
como argumento de otra función. Esto se llama función de devolución de
llamada (callback). Las funciones también se pueden devolver como
resultado de otra función.
function saludar(nombre) {
alert('Hola ' + nombre)
El ejemplo es un callback
} sincrónico, ya que se ejecuta
function procesarEntradaUsuario(callback) { inmediatamente.
var nombre = prompt('Por favor ingresa tu nombre.')
callback(nombre)
}
procesarEntradaUsuario(saludar)
Clausuras (clousure)
Una clausura o cierre se define como una función que «encierra» variables en su propio
ámbito (y que continúan existiendo aún habiendo terminado la función).
Es decir, devolvemos una función en una función externa que hace referencia a las
variables locales de la función externa. Esto es posible si tenemos funciones anidadas en
otra función y devueltas como referencia.
En la función interna, podemos usar las variables de la función externa. Debido al alcance
de las variables locales, las funciones internas pueden acceder a las variables de la función
externa.
Cuando devolvemos la función interna en la función externa, las referencias a las variables
locales de la función externa todavía están referenciadas en la función interna.
Clausuras (clousure)
La función iniciar() crea una variable local llamada nombre y una función
interna llamada mostrarNombre(). Por ser una función interna, esta última
solo está disponible dentro de iniciar(). mostrarNombre() no tiene ninguna
variable propia; pero puede acceder a la variable nombre declarada en la
función iniciar().
function iniciar() {
var nombre = "Codo a Codo" // La variable nombre es una variable local creada por iniciar.
function mostrarNombre() { // La función mostrarNombre es una función interna, una clausura.
alert(nombre); // Usa una variable declarada en la función externa.
}
mostrarNombre()
}
iniciar()
Clausuras | Ejemplo
function creaSumador(x) {
La función creaSumador(x) toma un
return function(y) {
argumento único x y devuelve una nueva return x + y;
función. Esa nueva función toma un único };
}
argumento y, devolviendo la suma de x +
y. var suma5 = creaSumador(5);
var suma10 = creaSumador(10);
creaSumador es una fábrica de función.
suma5 y suma10 son ambos closures. [Link](suma5(2)); // muestra 7
[Link](suma10(2)); // muestra 12
Comparten la misma definición de cuerpo
de función, pero almacenan diferentes
entornos. En el entorno suma5, x es 5. En
lo que respecta a suma10, x es 10.
Artículos de interés
Videos:
● Curso Básico de Javascript - Funciones
● Funciones Arrow (de Flecha) Javascript 2018
● Qué es una función de flecha - JavaScript Arrow Functions
● ¿Qué es un callback en JavaScript?
DOM y Eventos
¿Qué es el DOM?
El DOM (Document Object Model) es una interfaz de programación para los
documentos HTML. Proporciona una representación estructurada del
documento y define de qué manera los programas pueden acceder y modificar
su estructura, estilo y contenido. El DOM representa al documento como un
grupo de nodos y objetos con sus propiedades y métodos. Esencialmente,
conecta las páginas web a scripts o lenguajes de programación, como
JavaScript.
Todo esto permite al desarrollador modificar esta estructura de forma dinámica,
añadiendo o modificando elementos, cambiando sus atributos, etc. Estas tareas
pueden automatizarse y responder a eventos como pulsar un botón, mover el
ratón, hacer clic en un elemento, etc.
DOM | Estructura jerárquica
La estructura del DOM es jerárquica, con elementos que dependen unos de
otros, en forma de árbol. +info
DOM | Manipulando la estructura
El objeto document contiene los atributos y métodos, de la estructura que
representa al documento. JavaScript posee una API que permite su
manipulación.
El DOM posee elementos (element) y
nodos (node). Un elemento
representa una etiqueta HTML y un
nodo es una clase (no un objeto) en la
que se basan muchos otros objetos
del DOM. +info
DOM | Objeto document
JavaScript accede al DOM usando el objeto document mediante sus
atributos y métodos.
Todos los elementos (element) HTML tendrán un tipo de dato específico.
Algunos de ellos son:
DOM | Modificar elementos | Método tradicional
document permite identificar elementos por sus atributos, por ejemplo, su
id o class. La forma tradicional de hacerlo es mediante el método
getElementById() o algunos de los que vemos en la tabla. Devuelven o bien
un elemento, un arreglo con todos los que son de esa clase, o null en caso de
que no exista el elemento buscado.
DOM | Modificar elementos | Método tradicional
Los métodos que comienzan con get devuelven un valor. Los que
comienzan con set modifican o establecen un valor.
El argumento del método getElementById() es el id del elemento, y retorna
el objeto referenciado. El método innerHTML() escribe código HTML en un
elemento. El argumento es una cadena de texto, y si usamos comillas
invertidas ` para definir el string, se respetan los saltos de línea.
getElementsByClassName retorna un array de objetos, ya que pueden
existir múltiples elementos de una clase CSS.
DOM | Modificar elementos | Método tradicional
<!DOCTYPE html>
El código del ejemplo guarda en el <html>
array x todos los elementos (objetos) <body>
<h1>DOM</h1>
de la página HTML que sean de la <p>Solo cambia el primer elemento:</p>
clase “ejemplo”.
<div class="ejemplo">Elemento 1</div>
<div class="ejemplo">Elemento 2</div>
Luego, al elemento x[0] se le <script>
modifica su contenido utilizando el var x =
[Link]("ejemplo")
método innertHTML. El segundo x[0].innerHTML = "Hola UTN!"
</script>
<div> permanece inalterado, porque </body>
es el elemento [1] del arreglo. </html>
DOM | Modificar elementos | Método tradicional
<!DOCTYPE html>
El código del ejemplo espera a que <html>
se dispare el evento “onclick” del <body>
<h1>DOM</h1>
botón, que invoca a la función <p>Cambiar todos los elementos:</p>
<div class="ejemplo">Elemento 1</div>
“cambiarTexto”. <div class="ejemplo">Elemento 2</div>
<div class="ejemplo">Elemento 3</div>
<script>
La función guarda en el array x todos function cambiarTexto() {
los elementos (objetos) de la página var x=[Link]("ejemplo")
for (i = 0; i < [Link]; i++) {
HTML que sean de la clase x[i].innerHTML="UTN! " +(i+1)
}
“ejemplo”, los recorre usando un }
bucle for, y usando su método </script>
<button onclick="cambiarTexto()">
innerHTML les cambia su contenido. Cambiar todos los párrafos</button>
</body>
</html>
DOM | Modificar elementos | Método tradicional
De forma similar funcionan los métodos getElementsByName(name) y
getElementsByTagName(tag), que se encargan de buscar elementos HTML
por su atributo name o por su tag (etiqueta) de elemento HTML,
respectivamente. En el siguiente ejemplo las constantes nicknames y divs
contendrán una lista de objetos:
// Obtiene todos los elementos con atributo name="nickname"
const nicknames = [Link]("nickname")
// Obtiene todos los elementos <div> de la página
const divs = [Link]("div")
DOM | Modificar elementos | Métodos modernos
En los últimos años JS ha añadido dos nuevos métodos de búsqueda de
elementos que son simples de usar, sobre todo si conocemos los selectores
CSS. Son los métodos .querySelector() y .querySelectorAll():
Con estos métodos podemos reemplazar los “métodos tradicionales” e incluso realizar
nuevas intervenciones en el DOM gracias a su flexibilidad.
DOM | Métodos modernos | querySelector()
.querySelector(selector) devuelve el primer elemento que encaja con el
selector CSS suministrado en selector. Al igual que .getElementById(), en
caso de no coincidir con ninguno devuelve null.
const page = [Link]("#page") // <div id="page"></div>
const info = [Link](".main .info") // <div class="info"></div>
En la primera línea incluimos en el argumento un # porque se trata de un id. En la segunda
estamos recuperando el primer elemento con clase info que esté dentro de un elemento
de la clase main. Eso podría realizarse con los métodos tradicionales, pero sería necesario
un código más extenso y complejo. querySelector() simplifica el proceso.
DOM | Métodos modernos | querySelectorAll()
El método .querySelectorAll(selector) es similar a .querySelector(), pero en
caso de que haya más de un elemento que se ajuste a lo indicado por
selector, devuelve un array con todos los elementos que coinciden con él:
// Obtiene todos los elementos con clase "info"
const infos = [Link](".info")
// Obtiene todos los elementos con atributo name="nickname"
const nicknames = [Link]('[name="nickname"]')
// Obtiene todos los elementos <div> de la página HTML
const divs = [Link]("div")
.querySelectorAll() siempre nos devolverá un array con uno o más objetos, o vacío si no encuentra elementos de ese tipo en el
documento.
DOM | Crear elementos HTML
Existen métodos para crear diferentes elementos HTML o nodos, que nos
permiten agregar al documento estructuras dinámicas, mediante bucles o
estructuras definidas:
Métodos Descripción
Element .createElement(tag, options) Crea y devuelve el elemento HTML definido por tag. Ejemplo
Node .createComment(text) Crea y devuelve un nodo de comentarios HTML <!-- text -->.
Node .createTextNode(text) Crea y devuelve un nodo HTML con el texto text. Ejemplo
Node .cloneNode(deep) Clona el nodo HTML y devuelve una copia. deep es false por
defecto. Ejemplo
Boolean .isConnected Indica si el nodo HTML está insertado en el documento. Ejemplo
DOM | .createElement() y .appendChild()
.createElement() podemos crear un elemento HTML en memoria. Este
elemento puede insertarse en el documento HTML con .appendChild(), en
una posición determinada. El ejemplo crea un botón y lo coloca en el body:
<!DOCTYPE html>
<html>
<body>
<p>Creamos un elemento 'button':</p>
<script>
const btn = [Link]("button") //Creamos el boton y lo guardamos en btn
[Link] = "Soy un botón!" // Le ponemos el texto
[Link](btn) // Lo agregamos al <body>
</script>
</body>
</html>
DOM | .createTextNode()
.createTextNode() es un método que crea nodos de texto. Esos elementos
luego pueden ser asignados a un objeto. En el ejemplo se crea un nodo de
texto y se lo asigna a un <h1>, que luego se coloca en el <body>:
<!DOCTYPE html>
<html>
<body>
<p>Creamos un h1 con texto:</p>
<script>
const h1 = [Link]("h1") //Creamos el <h1>
const textNode = [Link]("¡Hola!") //Creamos el texto
[Link](textNode) //Colocamos el texto como hijo del <h1>
[Link](h1) //Y ponemos el <h1> dentro del <body>
</script>
</body>
</html>
DOM | .cloneNode()
.cloneNode() toma un nodo, y devuelve una copia: +info
<!DOCTYPE html>
<html><body>
<button onclick="clonar()">Copiar</button>
<p>Presionando el botón se copia un elemento de una lista a otra.</p>
<ul id="lista1"><li>Café</li><li>Té</li></ul>
<ul id="lista2"><li>Agua</li><li>Leche</li></ul>
<p>Cambiando <b>deep</b> a false sólo se clonan elementos vacíos.</p>
<script>
function clonar() {
const nodo = [Link]("lista2").lastChild //Leemos el nodo a clonar, lo
const clon = [Link](true); //clonamos y guardamos en “clon”
[Link]("lista1").appendChild(clon) //Y lo agregamos en la lista2
}
</script>
</body></html>
DOM | Modificar atributos de un elemento
Los objetos que obtenemos a partir de métodos como .createElement() o
.getElementById(), entre otros, poseen atributos que pueden ser
modificados:
<!DOCTYPE html>
<html>
<body>
<p id="p1">Este texto se va a borrar.</p>
<script>
const p = [Link]("p1")
[Link] = “UTN" // <p id="p1">UTN</p>
[Link] = "dato" // <p id="p1" class="data">UTN</p>
[Link] = "red" // <p id="p1" class="data" style="color:red">UTN</p>
</script>
</body>
</html>
DOM | Reemplazar contenido de un elemento
.textContent e .innerHTML permiten recuperar o modificar el contenido de
texto de un elemento, pero no son equivalentes:
Propiedades Descripción
.textContent Devuelve o asigna el texto del elemento. No atiende la sintaxis HTML. Ejemplo
.innerHTML Devuelve o asigna el contenido HTML del elemento. Ejemplo
const div1 = [Link]("div") // <div></div>
[Link] = "Hola a todos" // <div>Hola a todos</div>
[Link] // "Hola a todos"
const div2 = [Link](".info") // <div class="info"></div>
[Link] = "<strong>Importante</strong>" // Interpreta el HTML
[Link] // "<strong>Importante</strong>"
[Link] // "Importante”
DOM | Insertar una imágen
Las propiedades y métodos vistos permiten, por ejemplo, insertar una
imágen en el documento HTML:
const img = [Link]("img")
[Link] = "[Link]
[Link] = "Logo Javascript"
[Link](img)
.appendChild() es el método que permite agregar un elemento al DOM. En este caso, se
agrega en el <body>. +info
También es posible eliminar elementos, para ello debemos utilizar el método .remove()
+info
DOM | API nativa de Javascript
Entre las herramientas que provee la API de JS se encuentran:
Capítulo del DOM Descripción
Buscar etiquetas Métodos como .getElementById(), .querySelector() o .querySelectorAll(), entre
otras. +info
Crear etiquetas Métodos para crear elementos en la página y trabajar con ellos de forma
dinámica. +info
Insertar etiquetas Métodos para añadir elementos al DOM, como .appendChild(),
.insertAdjacentHTML(), entre otros. +info
Gestión de clases CSS .classList permite manipular clases CSS desde JS, para añadir, modificar o,
eliminar clases SS de un elemento. +info
Navegar entre Métodos y propiedades para «navegar» a través de la jerarquía del DOM, por la
elementos estructura del documento y la posición de los elementos en la misma. +info
DOM | Eventos en JS
Los eventos son acciones que realiza el usuario a las que podemos “atender”
desde JavaScript e indicar qué función o bloque de código se debe ejecutar
como respuesta. Estos eventos permiten interactuar con el usuario, por
ejemplo cuando hace clic en un botón. Existen tres formas de definir eventos
en nuestro código:
Estrategia Ejemplo
A través de un atributo HTML, asociando al mismo una función. <tag onclick="...">
A través de una propiedad de JavaScript, a la que asociamos la [Link] = ...
función.
A través del método addEventListener() , que permite crear un [Link]("click", ...)
“atendedor” de eventos.
DOM | Eventos en JS desde atributos HTML
Probablemente sea la forma más sencilla de atender un evento. Definimos un
evento a través de un atributo HTML, por ejemplo onClick. En el ejemplo, al
hacer click sobre el botón se ejecuta la función flecha enviarMensaje. Esta
función genera un mensaje “Hola!” mediante la función de javaScript alert.
<button onClick="enviaMensaje()">Haz clic!</button>
<script>
const enviarMensaje = () => alert("Hola!")
</script>
DOM | Eventos en JS desde propiedades JS
Otra forma de utilizar eventos es utilizar las propiedades de Javascript. Por
cada evento, existe una propiedad disponible en el elemento en cuestión:
<button>Haz clic!</button>
<script>
const button = [Link]("button")
[Link] = () => alert("Hola!")
</script>
DOM | Eventos con .addEventListener()
.addEventListener() es la forma más elaborada de utilizar eventos: +info
<!DOCTYPE html>
<html><head>
<script>
function modifyText() { // Función que modifica el contenido de #t2
var t2 = [Link]("t2")
[Link] = "Tocado!"
}
function load() { // Función que establece el EventListener()
var el = [Link]("t2")
[Link]("click", modifyText, false)
}
// Al cargar el documento, agregamos el EventListener()
[Link]("DOMContentLoaded", load, false)
</script>
</head>
<body>
<p id="t2">¡Haz click aquí!</p>
</body></html>
Artículos de interés
Material de lectura:
● Eventos en JS: [Link]
● Lista de los tipos de eventos más habituales en Javascript:
[Link]
● addEventListener: [Link]
Videos:
● 10 Fundamentos modernos que debes conocer en JS:
[Link]
● DOM fundamentos: [Link]
● DOM delegación de eventos: [Link]
● Formularios: [Link]
● Callback, Promesas y Async Await: [Link]
● Fetch: [Link]
Fundamentos del asincronismo en Javascript
(Parte I)
¿Qué es el sincrónismo?
En JavaScript, el sincronismo se refiere a la ejecución secuencial de código, donde cada línea de código
espera a que la línea anterior se haya completado antes de ejecutarse.
Este modelo de ejecución es lineal y bloqueante. Significa que si una línea de código toma tiempo para
completarse por algún motivo, toda la ejecución del programa se detiene hasta que esa línea termine.
Dos caractérisicas de este modelo son:
El Bloqueo: El modelo sincrónico puede conducir a problemas de bloqueo de la interfaz de usuario,
especialmente en aplicaciones web donde una tarea larga puede hacer que la página no responda.
La Previsibilidad: el código sincrónico es generalmente más fácil de leer, escribir y depurar debido a su
naturaleza secuencial y predecible.
Ejemplo sincrónico
En este ejemplo, cada operación se completa antes de que la siguiente
comience. Aquí, imprimiremos mensajes en la consola uno tras otro.
[Link]('Primero: Este mensaje se muestra primero.');
[Link]('Segundo: Este mensaje se muestra después, sin demora.');
En este ejemplo, "Primero" se imprime primero, seguido inmediatamente por
"Segundo".
No hay retraso entre las operaciones: todo ocurre en un orden estricto y
secuencial.
Otro ejemplo sincrónico
[Link]('Inicio del proceso');
let suma = 0;
for (let i = 0; i < 1000000; i++) {
suma += i;
}
[Link]('Suma completa: ', suma);
[Link]('Fin del proceso');
En este código, el mensaje "Fin del proceso" no se imprimirá hasta que el
bucle haya terminado de calcular la suma, demostrando el comportamiento
bloqueante y secuencial del código sincrónico.
¿Qué es el asincrónismo?
Es la capacidad de ejecutar ciertas operaciones en segundo plano y continuar
realizando otras tareas sin tener que esperar a que la operación asincrónica
termine.
En JavaScript, esto es esencial debido a que es un lenguaje de programación de
un solo hilo, lo que significa que puede ejecutar un solo bloque de código a la
vez. El asincronismo permite que JavaScript maneje tareas como cargar datos,
procesar archivos grandes, o realizar solicitudes de red sin bloquear la interfaz
de usuario o detener otras operaciones. Utiliza funciones como callbacks,
promesas y async/await para gestionar comportamientos asíncronos,
permitiendo que las aplicaciones sean más rápidas y responsivas.
Asincronismo en JavaScript
Imagina que estás organizando una gran fiesta y has decidido enviar
invitaciones por correo electrónico a todos tus amigos. La tarea de enviar
cada invitación es similar a una operación que lleva tiempo, como cargar
datos o hacer una solicitud a una base de datos.
En este ejemplo, JavaScript actúa como el organizador de la fiesta. Sin
asincronismo, JavaScript tendría que enviar cada invitación uno por uno,
esperando que el correo electrónico de un amigo se envíe antes de poder
empezar a enviar el siguiente. Esto significa que, mientras espera, no podría
hacer nada más, como planificar la música o la comida de la fiesta, lo que no
es eficiente.
Asincronismo en JavaScript
Ahora, gracias al asincronismo en JavaScript, la situación es muy diferente:
Inicio del Proceso: JavaScript comienza el proceso de enviar las invitaciones.
Para cada amigo, inicia el envío de un correo electrónico.
Asincronismo en Acción: Mientras los correos electrónicos se están
enviando (algo que toma tiempo y se hace a través de la red), JavaScript no
necesita esperar que cada uno se complete. En lugar de eso, puede seguir
trabajando en otros preparativos para la fiesta, como elegir la música o
planear los juegos.
Asincronismo en JavaScript
Manejo de Respuestas: Cada vez que una invitación se envía
correctamente, JavaScript recibe una notificación (esto se puede manejar
con promesas o callbacks en un entorno de programación real). Si algún
correo electrónico falla, puede manejar esos casos individualmente, quizás
intentando enviar la invitación nuevamente o eligiendo un método
alternativo de contacto.
Continúa con otras Tareas: Mientras las respuestas de las invitaciones
llegan de manera asincrónica, JavaScript no se ha detenido ni un segundo.
Ha estado libre para hacer todas las otras tareas necesarias, asegurándose
de que la fiesta sea un éxito.
Ejemplo asincrónico
Para el ejemplo asíncrono, usaremos setTimeout para introducir un retraso
antes de imprimir el segundo mensaje, mostrando cómo JavaScript puede
manejar operaciones que no se completan inmediatamente:
[Link]('Primero: Este mensaje se muestra primero.');
setTimeout(() => {
[Link]('Tercero: Este mensaje se muestra después de 2 segundos.');
}, 2000);
[Link]('Segundo: Este mensaje se muestra mientras esperamos el
temporizador.');
¿Qué son las promesas?
Son un mecanismo para manejar operaciones asíncronas. Permiten manejar el
eventual resultado de una operación asincrónica, ya sea un éxito o un fallo.
Las promesas representan un valor que puede no estar disponible aún, pero que
eventualmente se resolverá o rechazará, permitiendo que el código continúe
ejecutándose en paralelo sin bloquear la ejecución principal.
¿Para qué se utilizan las Promesas?
Simplifican el manejo de secuencias de operaciones asíncronas y el manejo del
flujo de ejecución en escenarios donde se depende de datos o eventos que
tardan tiempo en completarse, como:
- Solicitudes de red ([Link]., AJAX/fetch).
- Lecturas de archivos en aplicaciones basadas en [Link].
- Operaciones de bases de datos.
- Operaciones que requieran esperar por un evento o respuesta antes de
continuar.
Características de las promesas:
Asíncronas: Permiten que el código continúe ejecutándose mientras la operación
completa su ejecución.
Evitan el Callback Hell: Proporcionan una alternativa más limpia y manejable a
los callbacks anidados.
Encadenamiento: Las promesas pueden ser encadenadas, lo que permite realizar
varias operaciones asíncronas secuenciales de manera más legible.
Cómo crear una promesa:
const promesa = new Promise((resolve, reject) => { new Promise(executor): El
// Simulamos un valor para que la condición se cumpla (o no)
constructor Promise se
const x = 42;
utiliza para crear una nueva
// Operación asincrónica simulada
setTimeout(() => {
promesa. Recibe una
if (x === 42) { función ejecutora como
resolve("¡Éxito!"); // La promesa se resuelve exitosamente argumento, que a su vez
} else { recibe dos funciones:
reject("Fallo."); // La promesa falla y se rechaza resolve y reject.
}
}, 2000);
});
executor: Es la función que se ejecuta inmediatamente por el constructor Promise, antes
incluso de que el constructor Promise devuelva el objeto promesa recién creado. Esta función
generalmente inicia algún trabajo asíncrono y luego, dependiendo del resultado de ese
trabajo, llama a resolve o a reject.
Funciones dentro del Constructor
const promesa = new Promise((resolve, reject) => {
resolve(value): Esta función
// Simulamos un valor para que la condición se cumpla (o no)
se llama con un valor
const x = 42;
cuando la operación
// Operación asincrónica simulada
asíncrona se completa con
setTimeout(() => {
éxito. Al llamar a resolve, la
if (x === 42) {
promesa pasa de estar en
resolve("¡Éxito!"); // La promesa se resuelve exitosamente estado "pendiente" a
} else { "cumplida".
reject("Fallo."); // La promesa falla y se rechaza El valor pasado a resolve es
} lo que se maneja con el
}, 2000); método .then de la
}); promesa.
reject(reason): Esta función se llama con una razón o error cuando la
operación asíncrona falla o se encuentra con un error. Al llamar a reject, la
promesa pasa de estar en estado "pendiente" a "rechazada". La razón
pasada a reject es lo que se maneja con el método .catch de la promesa.
Métodos de la promesa
[Link]((valor) => {
[Link](valor); // Se ejecuta si la promesa se resuelve exitosamente
}).catch((error) => {
[Link](error); // Se ejecuta si la promesa se rechaza
}).finally(() => {
[Link]('Operación completada.’); // Se ejecuta al finalizar la resolución
});
.then(): Este método se ejecuta si la promesa se resuelve exitosamente. Valor recibe el valor que fue pasado a
resolve cuando la promesa fue cumplida. En este caso, imprime el valor resuelto de la promesa a la consola.
.catch(): Este método gestiona los errores, se ejecuta si la promesa se rechaza. Error recibe el error o la razón
que fue pasada a reject cuando la promesa fue rechazada. En este caso Imprime el error a la consola. Este es
un mecanismo clave para el manejo de errores en el flujo asíncrono.
.finally(): se ejecuta al final del manejo de la promesa, independientemente de si fue resuelta o rechazada. No
recibe ningún argumento, y su propósito es realizar acciones de limpieza o finalización que se deben ejecutar
después de que las promesas se han completado.
Ejemplo de Uso de Promesas con then, catch, y finally
function obtenerDatosDeAPI() {
return new Promise((resolve, reject) => {
// Simulando una llamada a API con setTimeout
setTimeout(() => {
// Supongamos que esta es una operación que puede fallar aleatoriamente
const fallo = [Link]() > 0.5; // 50% de probabilidad de fallo
if (fallo) {
reject("Error: No se pudo obtener los datos.");
} else {
resolve("Datos obtenidos exitosamente.");
}
}, 1000); // Simulamos un retraso de 1 segundo
});
}
Ejemplo de Uso de Promesas con then, catch, y finally
// Usando la función que devuelve la promesa
obtenerDatosDeAPI()
.then(datos => {
// Se ejecuta si la promesa se resuelve exitosamente
[Link](datos);
})
.catch(error => {
// Se ejecuta si la promesa se rechaza
[Link](error);
})
.finally(() => {
// Se ejecuta independientemente del resultado anterior
[Link]("Operación completada.");
});
Fundamentos del asincronismo en Javascript
(Parte II)
Recordemos el concepto de asincronismo
Es la capacidad de ejecutar ciertas operaciones en segundo plano y continuar
realizando otras tareas sin tener que esperar a que la operación asincrónica
termine.
En JavaScript, esto es esencial debido a que es un lenguaje de programación de
un solo hilo, lo que significa que puede ejecutar un solo bloque de código a la
vez. El asincronismo permite que JavaScript maneje tareas como cargar datos,
procesar archivos grandes, o realizar solicitudes de red sin bloquear la interfaz
de usuario o detener otras operaciones. Utiliza funciones como callbacks,
promesas y async/await para gestionar comportamientos asíncronos,
permitiendo que las aplicaciones sean más rápidas y responsivas.
async / await
async y await son extensiones de las promesas en JavaScript que simplifican la forma de trabajar
con operaciones asíncronas. Estos hacen que el código asíncrono sea más fácil de escribir y
entender sin las complejidades habituales asociadas con el manejo de promesas.
La función async
La palabra clave async se utiliza para declarar una función como asíncrona. Declara que una
función puede, en algún momento, esperar a que las promesas se resuelvan sin bloquear la
ejecución de otras operaciones. Aquí están los detalles clave:
Devolución de una promesa: Una función async automáticamente devuelve una promesa. Si la
función retorna algo que no es una promesa, ese valor será automáticamente envuelto en una
promesa.
Sintaxis: Puede ser usada con declaraciones de funciones normales, funciones flecha, y métodos de
clase.
async / await
En el siguiente ejemplo, declaramos una función asincrónica, por lo tanto devolverá
automáticamente una promesa. Esto nos permite utilizar los métodos aplicados a las
promesas cuando sea invocada la función.
async function obtenerDatos() {
return "Datos recibidos";
}
// La función devuelve una promesa
obtenerDatos().then([Link]); // Imprime
"Datos recibidos"
Pero todavía, al no utilizar el await dentro de la función, no tenemos un
asincronismo real en el código.
async / await
async function procesarDatos() {
La palabra clave try {
await // Espera aquí hasta que fetch complete
await sólo puede ser const datos = await
usado dentro de
funciones async y es fetch('[Link]
usado para pausar la // Espera aquí hasta que la conversión a
ejecución de la
función hasta que la
JSON complete
promesa a la que se const json = await [Link]();
llama se resuelva o [Link](json);
rechace. El uso de
await ayuda a que el } catch (error) {
código asíncrono se [Link]("Error al obtener datos:",
lea de manera más
intuitiva, casi como si error);
fuera sincrónico. }
}
async / await
Beneficios del uso de Async/Await
Claridad y Legibilidad: Al eliminar la necesidad de encadenar .then() y .catch(), el
código se vuelve más claro y fácil de seguir.
Error Handling: El manejo de errores se simplifica mediante el uso de bloques
try/catch, que son ya familiares para muchos desarrolladores y aplican de igual manera
en contexto síncrono y asíncrono.
Depuración Simplificada: La depuración de código asíncrono puede ser complicada
debido a las cadenas de promesas. Con async/await, puedes usar puntos de
interrupción de depuración de manera más efectiva, ya que el flujo del código es más
directo y predecible.
async / await
Consideraciones
A pesar de sus ventajas, async/await no reemplaza completamente a las promesas,
especialmente en situaciones donde se requiere manejar múltiples promesas
concurrentes. En esos casos, funciones como [Link]() siguen siendo de gran
utilidad para optimizar el rendimiento al permitir la ejecución paralela.
En conclusión, async/await es una herramienta poderosa en JavaScript que, cuando
se usa adecuadamente, puede hacer que el manejo de la asincronía no sólo sea más
manejable, sino también mucho más elegante y eficiente.
Manejo de Errores con Try/Catch
En síncrono: try/catch permite capturar errores en bloques de código
específicos para evitar que los errores no controlados rompan el flujo de
ejecución.
try {
let resultado = operacionRiesgosa();
[Link](resultado);
} catch (error) {
[Link]("Se capturó un error:", error);
}
Manejo de Errores con Try/Catch
En asíncrono: try/catch dentro de funciones async para manejar errores de
promesas.
async function processData() {
try {
let data = await
fetch('[Link] => [Link]());
[Link](data);
} catch (error) {
[Link]("Error procesando los datos:", error);
}
}
processData();
Manejo de Errores con Try/Catch
En asíncrono: try/catch dentro de funciones async para manejar errores de promesas.
async function processData() {
try {
let data = await
fetch('[Link] =>
[Link]());
[Link](data);
} catch (error) {
[Link]("Error procesando los datos:",
error);
}
}
Callbacks
Un callback es una función que se pasa a otra función como argumento y se ejecuta después
de que una operación específica se completa. En JavaScript, esto es esencial para manejar
operaciones asíncronas, como solicitudes de red o temporizadores, ya que permite que el
programa continúe ejecutándose sin bloqueos mientras espera que se complete la operación.
function mostrarMensaje() {
[Link]("Hola, este mensaje se muestra después de 3
segundos");
}
// setTimeout usa un callback para ejecutar mostrarMensaje
después de 3000 milisegundos
setTimeout(mostrarMensaje, 3000);
Callbacks function procesarElemento(elemento, callback) {
Veamos otro ejemplo:
setTimeout(() => {
La función procesarElemento toma un callback("Elemento procesado: " + elemento);
elemento y un callback como argumentos.
}, 1000);
Usa setTimeout para simular una operación }
asíncrona que tarda 1 segundo.
Después del retraso, llama al callback con un const elementos = [1, 2, 3, 4, 5];
mensaje que incluye el elemento procesado.
Luego de la definición de elementos, usamos [Link](elemento => {
forEach para iterar sobre cada elemento en el procesarElemento(elemento, resultado => {
arreglo elementos.
[Link](resultado);
Para cada elemento, invocamos a });
procesarElemento, pasando el elemento y un
callback que imprime el resultado. });
Este ejemplo demuestra cómo los callbacks pueden ser utilizados para manejar la asincronía en operaciones que implican iterar
sobre un conjunto de datos y procesar cada ítem de manera asíncrona. Esto es común en aplicaciones web donde, por ejemplo,
podrías necesitar cargar o procesar una lista de recursos obtenidos desde un servidor.
Callback Hell
El Callback Hell, o "Pyramid of Doom", es una situación donde múltiples callbacks se anidan
unos dentro de otros. Esto puede ocurrir cuando varias operaciones asíncronas dependen unas
de otras. Esto hace que el código sea difícil de leer y mantener.
Problemas Asociados
Legibilidad Reducida: La profundidad de anidamiento hace que el código sea difícil de seguir.
Gestión de Errores Complicada: Cada nivel de anidación requiere su propio manejo de errores,
lo que puede llevar a código repetitivo y complicado.
Mantenimiento Difícil: Modificar el código en uno de los niveles de anidación puede afectar a
los niveles subsecuentes.
Callback Hell
El Callback Hell, o "Pyramid of Doom", es una situación donde múltiples callbacks se anidan
unos dentro de otros. Esto puede ocurrir cuando varias operaciones asíncronas dependen unas
de otras. Esto hace que el código sea difícil de leer y mantener.
Problemas Asociados:
Legibilidad Reducida: La profundidad de anidamiento hace que el código sea difícil de seguir.
Gestión de Errores Complicada: Cada nivel de anidación requiere su propio manejo de errores,
lo que puede llevar a código repetitivo y complicado.
Mantenimiento Difícil: Modificar el código en uno de los niveles de anidación puede afectar a
los niveles subsecuentes.
Callback Hell
Ejemplo de callback Hell [Link]("Inicio del proceso");
Inicio del Proceso: Se imprime un mensaje
inicial para indicar el comienzo. setTimeout(() => {
Primera Tarea: Se utiliza setTimeout para
[Link]("Primera tarea completada");
simular una tarea que tarda 1 segundo. Una setTimeout(() => {
vez completada, imprime un mensaje.
[Link]("Segunda tarea completada");
Segunda Tarea: Dentro del primer setTimeout(() => {
setTimeout, se inicia otro setTimeout
después de que la primera tarea ha [Link]("Tercera tarea completada");
completado. Esto simula otra tarea que
también tarda 1 segundo.
[Link]("Todos los procesos terminados");
}, 1000); // Tercera tarea tarda 1 segundo
Tercera Tarea: De manera similar, dentro
del segundo setTimeout, se inicia un tercer }, 1000); // Segunda tarea tarda 1 segundo
setTimeout. }, 1000); // Primera tarea tarda 1 segundo
Después de completar esta tarea, imprime
un mensaje final.
Este código ilustra un "Callback Hell" porque las funciones de callback están anidadas dentro de otras funciones de callback, creando un código
que se desplaza hacia la derecha y es difícil de leer y mantener. Esta estructura puede llevar a errores y dificultades al intentar rastrear el flujo de
ejecución del programa, especialmente en aplicaciones más complejas donde las operaciones asíncronas son comunes.
Callback Hell (Solución) function tareaAsincrona(mensaje) {
return new Promise(resolve => {
Función tareaAsincrona: Esta función toma un mensaje setTimeout(() => {
como argumento y retorna una promesa.
[Link](mensaje);
La promesa se resuelve después de un retraso de 1 resolve();
segundo, durante el cual se imprime el mensaje. }, 1000);
});
Encadenamiento de Promesas: Iniciamos el proceso }
con un mensaje. Llamamos a tareaAsincrona para la
primera tarea y esperamos a que se resuelva antes de
llamar a la siguiente tarea.
[Link]("Inicio del proceso");
Utilizamos .then() para encadenar cada tarea tareaAsincrona("Primera tarea completada")
secuencialmente, lo que asegura que cada tarea .then(() => tareaAsincrona("Segunda tarea completada"))
comience sólo después de que la anterior haya .then(() => tareaAsincrona("Tercera tarea completada"))
terminado. Al final, imprimimos un mensaje cuando .then(() => {
todas las tareas han terminado.
[Link]("Todos los procesos terminados");
Manejo de Errores: Usamos .catch() al final del })
encadenamiento para capturar y manejar cualquier .catch(error => {
error que pueda ocurrir durante las operaciones [Link]("Error durante el proceso", error);
asíncronas. });
Callback Hell
Promesas
function tareaAsincrona(mensaje) {
[Link]("Inicio del proceso");
return new Promise(resolve => {
setTimeout(() => { setTimeout(() => {
[Link]("Primera tarea completada"); [Link](mensaje);
setTimeout(() => { resolve();
[Link]("Segunda tarea completada"); }, 1000);
setTimeout(() => { });
[Link]("Tercera tarea completada"); }
[Link]("Todos los procesos
terminados"); [Link]("Inicio del proceso");
}, 1000); // Tercera tarea tarda 1 segundo
}, 1000); // Segunda tarea tarda 1 segundo
}, 1000); // Primera tarea tarda 1 segundo tareaAsincrona("Primera tarea completada")
.then(() => tareaAsincrona("Segunda tarea completada"))
.then(() => tareaAsincrona("Tercera tarea completada"))
Comparando ambos enfoques, las promesas no .then(() => {
solo evitan el anidamiento profundo y mejora la [Link]("Todos los procesos terminados");
})
legibilidad del código, sino que también facilita el .catch(error => {
manejo de errores y el flujo de control en general. [Link]("Error durante el proceso", error);
});