Introducción a Javascript
JavaScript es un lenguaje de programación de alto nivel, interpretado y orientado a objetos. Fue creado originalmente para agregar interactividad y dinamismo a las páginas web, pero hoy en día se utiliza en una amplia variedad de aplicaciones, desde el desarrollo web hasta la creación de aplicaciones móviles y de escritorio.
Una de sus principales características es la capacidad para interactuar con el HTML y el CSS, permitiendo modificar y manipular elementos de la página de forma dinámica. Esto significa que podemos realizar cambios en tiempo real, responder a eventos como clics de botones o desplazamientos del mouse, y actualizar el contenido de la página sin tener que recargarla.
Además de ser un lenguaje versátil para el desarrollo web, JavaScript también cuenta con una amplia gama de librerías y frameworks que facilitan la creación de aplicaciones complejas. Algunos ejemplos populares incluyen Angular, Vue.js y, particularmente, React, el cual estudiaremos en esta asignatura.
JavaScript es un lenguaje interpretado, lo que significa que no necesita ser compilado antes de su ejecución. Esto permite un desarrollo rápido y ágil, ya que los cambios en el código pueden verse inmediatamente reflejados en la aplicación.
Por último, debemos destacar el hecho de que este intérprete se encuentra integrado en la mayoría de los navegadores web modernos, lo que significa que no es necesario instalar ningún software adicional para comenzar a programar en JavaScript. Todo lo que necesitas es un editor de texto y un navegador web para empezar a escribir y probar tu código, aunque algunos editores de código como Visual Studio Code o Atom ofrecen funcionalidades adicionales que facilitan el desarrollo en este lenguaje.
Sintaxis
Como cualquier lenguaje de programación, JavaScript tiene una serie de reglas y convenciones que debemos seguir para que nuestro código sea válido y funcione correctamente. A continuación, veremos algunos aspectos básicos de su sintaxis.
Variables
En JavaScript, podemos declarar variables utilizando las palabras clave var
y let
. Estas palabras clave tienen algunas diferencias en cuanto a su alcance y mutabilidad:
-
var
: antes de la introducción delet
en JavaScript ES6 - 2015,var
era la única forma de declarar variables. Sin embargo,var
tiene un alcance de función o alcance global, lo que significa que una variable declarada convar
está disponible en toda la función en la que se declara y, si se declara en el ámbito global, está disponible en todo el script. Por supuesto, como toda variable, puede ser reasignada. Por ejemplo:1var name = "Juan";2name = "Pedro"; // Reasignación válida -
let
: tiene un alcance de bloque, lo que significa que una variable declarada conlet
está disponible sólo dentro del bloque en el que se declara, ya sea dentro de un buclefor
, una estructuraif
o la definición de una función. Además,let
permite la reasignación de valor. Por ejemplo:
1let edad = 25;2edad = 30; // Reasignación válida
Constantes
En algunas ocasiones, necesitamos declarar variables cuyo valor no cambiará después de su asignación inicial, las cuales se conocen como constantes.
Para esto, debemos utilizar la palabra clave const
, introducida en ES6 - 2015 al igual que let
. Veremos que comparte algunas características con let
, como el alcance de bloque, pero con la diferencia de que no permite la reasignación de valor. Por ejemplo:
1const PI = 3.1416;2PI = 3.14; // Esto daría un error, ya que no se puede reasignar una constante.
Tipos de datos
JavaScript es un lenguaje de tipado dinámico, lo que significa que no es necesario especificar el tipo de dato al declarar una variable. El tipo de dato se determina automáticamente en tiempo de ejecución según el valor asignado a la variable.
No obstante, podemos distinguir algunos tipos de datos relevantes:
-
Números: representan valores numéricos, ya sean enteros o decimales. Para declarar un número de punto flotante, se utiliza el punto (
.
) como separador decimal.1let edad = 25;2let precio = 9.99; -
Cadenas de texto: representan secuencias de caracteres y se utilizan para almacenar texto. Las cadenas se pueden declarar utilizando comillas simples (
'
) o dobles ("
).1let nombre = "Juan";2let mensaje = 'Hola, ¿cómo estás?'; -
Booleanos: representan valores de verdadero o falso. Son útiles en expresiones condicionales y en la toma de decisiones. Los valores booleanos son
true
yfalse
.1let esMayor = true;2let esMenor = false; -
Arreglos: representan colecciones homogéneas de elementos ordenados secuencialmente. Los elementos de un arreglo se almacenan en posiciones numéricas llamadas índices, comenzando desde 0. Se declaran utilizando corchetes (
[]
) y separando los elementos con comas (,
).1let numeros = [1, 2, 3, 4, 5];2let colores = ["rojo", "verde", "azul"]; -
null
yundefined
:null
se utiliza para indicar la ausencia de valor de manera intencional, mientras queundefined
se utiliza para indicar que una variable no tiene un valor asignado por defecto, ya sea porque no se ha inicializado o porque se ha eliminado su valor.1let valor1 = null; // Se indica que la variable no tiene valor intencionalmente (null)2let valor2; // Variable no inicializada (undefined)
Por último, podemos destacar el tipo de dato object
, que analizaremos con más detalle más adelante.
Operadores
En JavaScript, existen diferentes tipos de operadores que se utilizan para realizar operaciones y manipulaciones en los valores y variables.
-
Operadores aritméticos: se utilizan para realizar operaciones matemáticas básicas, como suma, resta, multiplicación, división y módulo (resto de la división).
1let suma = 5 + 3; // 82let resta = 10 - 2; // 83let multiplicacion = 4 * 6; // 244let division = 15 / 3; // 55let modulo = 10 % 3; // 1 (resto de la división de 10 entre 3) -
Operadores de asignación: se utilizan para asignar valores a variables. El operador de asignación básico es el signo igual (
=
). Además, existen operadores de asignación compuestos que combinan una operación aritmética y una asignación.1let x = 5; // Asignación básica2x += 3; // x = x + 3 (8)3x -= 2; // x = x - 2 (6)4x *= 4; // x = x * 4 (24)5x /= 3; // x = x / 3 (8)6x %= 5; // x = x % 5 (3) -
Operadores de comparación: se utilizan para comparar valores y devuelven un valor booleano según la comparación sea verdadera o falsa. Estos pueden ser de igualdad (
==
), desigualdad (!=
), mayor que (>
), menor que (<
), mayor o igual que (>=
) y menor o igual que (<=
).1let a = 5;2let b = 8;34let igual = a == b; // false5let noIgual = a != b; // true6let mayor = a > b; // false7let menorIgual = a <= b; // trueDebemos tener en cuenta un detalle de suma importancia, en JavaScript, la comparación de igualdad puede realizarse con con operadores distintos y los algoritmos de comparación para cada uno de ellos pueden variar dependiendo del tipo de dato. Fundamentalmente, debemos tener en cuenta que
==
realiza una comparación débil y===
realiza una comparación estricta.Para más detalles sobre este tema, podemos consultar el anexo Comparación de igualdad en JavaScript.
-
Operadores lógicos: se utilizan para combinar o invertir expresiones booleanas.
- Conjunción o AND: se representa con
&&
y devuelvetrue
si ambas expresiones son verdaderas. - Disyunción o OR: se representa con
||
y devuelvetrue
si al menos una de las expresiones es verdadera. - Negación o NOT: se representa con
!
y devuelvetrue
si la expresión es falsa.
1let x = 5;2let y = 10;3let z = 3;45let resultado1 = (x < y) && (z > x); // true6let resultado2 = (x > y) || (z < y); // false7let resultado3 = !(x === y); // true - Conjunción o AND: se representa con
Estructuras de control
JavaScript proporciona varias estructuras de control que nos permiten controlar el flujo de ejecución de un programa y tomar decisiones basadas en ciertas condiciones, o repetir un grupo de instrucciones un número determinado de veces.
Antes de analizar las estructuras de control, es importante recordar que JavaScript establece bloques de código mediante llaves {}
. Esto significa que, si queremos agrupar varias instrucciones debemos hacerlo mediante este mecanismo.
1{2 // Instrucción 13 // Instrucción 24 // Instrucción 35}
Estructura if
La estructura if
permite el control selectivo del flujo de ejecución de un programa. Se evalúa una condición y, si es verdadera, se ejecuta un bloque de código.
1if (condicion) {2 // Bloque de código a ejecutar si la condición es verdadera3}
Además, podemos agregar un bloque de código que se ejecutará si la condición no se cumple utilizando la estructura else
.
1if (condicion) {2 // Bloque de código a ejecutar si la condición es verdadera3} else {4 // Bloque de código a ejecutar si la condición es falsa5}
Asimismo, podemos encadenar múltiples condiciones utilizando la estructura else if
. La estructura else if
establece condiciones que se deben evaluar secuencialmente. Se comprueban las condiciones una tras otra hasta que se encuentra una condición verdadera y se ejecuta el bloque de código correspondiente, o hasta que se llega al bloque else
si ninguna de las condiciones es verdadera.
1if (condicion1) {2 // Código a ejecutar si la condicion1 es verdadera3} else if (condicion2) {4 // Código a ejecutar si la condicion2 es verdadera5} else if (condicion3) {6 // Código a ejecutar si la condicion3 es verdadera7} else {8 // Código a ejecutar si ninguna de las condiciones anteriores es verdadera9}
Estructura switch
La estructura switch
se utiliza para realizar una selección múltiple en función del valor de una expresión. Se comparan diferentes casos y se ejecuta el código correspondiente al caso que coincida o, en su defecto, se puede especificar un caso por defecto.
Para establecer cada caso, se utiliza la palabra clave case
, seguida del valor con el que se compara.
Por último, es importante recordar que, una vez que se ejecuta un caso, se debe utilizar la palabra clave break
para salir de la estructura switch
. De lo contrario, se continuarán evaluando los casos siguientes.
1switch (expresion) {2 case valor1:3 // Código a ejecutar si la expresion coincide con valor14 break;5 case valor2:6 // Código a ejecutar si la expresion coincide con valor27 break;8 default:9 // Código a ejecutar si la expresion no coincide con ninguno de los casos anteriores10 break;11}
Estructura for
La estructura for
se utiliza para repetir un bloque de código un número específico de veces. Se compone de tres partes:
- Inicialización: se ejecuta una vez antes de que comience la iteración. Se utiliza para inicializar la variable de control del bucle.
- Condición: se evalúa antes de cada iteración. Si la condición es verdadera, se ejecuta el bloque de código. Si es falsa, se sale del bucle.
- Incremento: se ejecuta después de cada iteración. Se utiliza para modificar la variable de control del bucle.
1for (inicializacion; condicion; incremento) {2 // Bloque de código a ejecutar en cada iteración3}
Estructura while
La estructura while
se utiliza para repetir un bloque de código mientras se cumpla una determinada condición. La condición se evalúa antes de cada iteración.
1while (condicion) {2 // Bloque de código a ejecutar mientras la condición sea verdadera3}
Funciones
Las funciones son una parte fundamental de cualquier lenguaje de programación, ya que nos permiten encapsular un conjunto de instrucciones y reutilizarlas en diferentes partes de nuestro programa. Las funciones en JavaScript tienen la siguiente sintaxis básica:
1function <nombre de función>(<lista de parámetros>) {2 <bloque de código>3 return <valor>;4}
Analizando la estructura de una función, podemos identificar los siguientes elementos:
function
: es la palabra clave utilizada para declarar una función en JavaScript.<nombre de función>
: el identificador que le damos a una función al momento de definirla. Se utiliza para invocarla posteriormente.<lista de parámetros>
: una función puede recibir cero o más parámetros, los cuales son variables que se utilizan dentro de la función para realizar operaciones. Estos siempre se encuentran entre paréntesis y separados por comas.<bloque de código>
: es el conjunto de instrucciones que se ejecutan al invocar la función. Puede contener cualquier tipo de instrucción válida en JavaScript.return
: la sentenciareturn
se utiliza para devolver un valor desde la función. Es opcional y se puede utilizar para devolver un resultado o finalizar la ejecución de la función.
Veamos un sencillo ejemplo para definición e invocación de una función en JavaScript:
1function sumar(a, b) {2 let resultado = a + b;3 return resultado;4}5
6// Invocamos y almacenamos el resultado de la función en una variable7let suma = sumar(3, 5);8console.log(suma); // Salida: 8
Además de las funciones declaradas mediante la palabra clave function
, JavaScript también admite funciones anónimas (funciones sin nombre) y funciones flecha (arrow functions), que proporcionan una sintaxis más compacta y funcionalidades adicionales.
Las funciones son una parte esencial de JavaScript, ya que permiten organizar y reutilizar el código, mejorar la modularidad y facilitar el mantenimiento de las aplicaciones.
Las funciones anónimas y las funciones flecha son dos formas alternativas de declarar funciones en JavaScript.
Funciones anónimas
Las funciones anónimas son aquellas que no tienen un nombre asignado. Se definen directamente como “expresiones de función” y se utilizan principalmente cuando se requiere una función en un contexto específico, como pasarla como argumento a otra función o asignarla a una variable.
1let saludar = function(nombre) {2 console.log("Hola, " + nombre + "!");3};
Al asignar una función anónima a una variable, podemos invocarla utilizando el nombre de la variable, como si fuera una función normal.
1saludar("Juan"); // Salida: Hola, Juan!
En este caso, se declara una función anónima y se asigna a la variable saludar. Luego, se invoca la función pasando el nombre “Juan” como argumento.
Funciones flecha
Las funciones flecha son una forma abreviada y concisa de definir funciones en JavaScript.
Se denotan con el operador de flecha =>
y no requieren la palabra clave function
. Son ideales para funciones anónimas y para situaciones donde se necesita una sintaxis más corta. Por ejemplo:
1let saludar = (nombre) => {2 console.log("Hola, " + nombre + "!");3};
Si una función flecha tiene un solo parámetro, los paréntesis pueden ser omitidos. Sin embargo, si no hay parámetros o hay más de uno, los paréntesis son obligatorios.
1let saludar = nombre => {2 console.log("Hola, " + nombre + "!");3};
Aún así, es una buena práctica mantener los paréntesis para evitar confusiones y mejorar la legibilidad del código.
Por último, podemos destacar que si la función flecha contiene solo una expresión, el valor de esa expresión se devuelve implícitamente sin necesidad de utilizar la palabra clave return
. Si se necesita más de una expresión o un bloque de código, se deben utilizar las llaves {}
y se debe especificar explícitamente la instrucción return
si se desea devolver un valor.
1let duplicar = (num) => num * 2; // Función flecha de una sola línea2
3let calcularPromedio = (num1, num2) => {4 let suma = num1 + num2;5 let promedio = suma / 2; // Funcion flecha con un bloque de codigo6 return promedio;7};
Objetos
Debemos hacer una aclaración de este tipo de dato, ya que en el futuro estudiaremos el concepto de clases.
Los objetos son estructuras de datos que nos permiten almacenar propiedades y métodos relacionados. Pueden representar entidades del mundo real, como un usuario, un producto o cualquier otra cosa que necesitemos modelar en nuestro programa.
Los objetos pueden definirse de forma literal utilizando llaves ({}
), dentro de las cuales se especifican las propiedades y los métodos del objeto.
-
Propiedades: son asociaciones entre un nombre (también conocido como clave) y un valor. En el paradigma orientado a objetos estos se denominan atributos e indican una característica de la entidad representada. El valor puede ser cualquier tipo de datos válido en JavaScript, como un número, una cadena de texto, un booleano, un arreglo u otro objeto.
-
Métodos: son funciones asociadas con el objeto (contenidas en el ámbito del objeto) y nos permiten realizar operaciones o cálculos relacionados con el objeto. Definen el comportamiento de la entidad representada.
1const persona{2 nombre: "Juan",3 apellido: "Perez",4 edad: 24,5 saludo: function saludar(){6 // Cuerpo de la función7 }8}
Si lo comparamos con otros lenguajes de programación, como Java o Python, veremos que para instanciar un objeto es necesaria una clase que defina su estructura y comportamiento.
Cualquier objeto definido de forma literal será una instancia de la clase Object
, la cual es la clase base de todos los objetos en JavaScript. Podemos notar esto si utilizamos el operador typeof
para conocer el tipo de dato de un objeto.
1let numero = 10;2console.log(typeof numero); // "number"3
4let texto = "Hola";5console.log(typeof texto); // "string"6
7let esVerdadero = true;8console.log(typeof esVerdadero); // "boolean"9
10let persona = { nombre: "Juan", edad: 25 };11console.log(typeof persona); // "object"
En el futuro, veremos que el tipo de dato de un objeto instanciado a partir de una clase definida por el usuario es también object
. Por ejemplo, una clase predefinida en JavaScript es Date
, la cual nos permite trabajar con fechas y horas.
1let fecha = new Date();2console.log(typeof fecha); // "object"
Cabe aclarar que otra manera de crear objetos en JavaScript es utilizando directamente un constructor como Object()
. Esta función crea un nuevo objeto y nos permite asignar propiedades y métodos al objeto de forma dinámica.
1let persona = new Object();
No obstane, la forma más común y recomendada de crear objetos en JavaScript es utilizando la notación de objetos literales o bien, a partir de clases definidas por el usuario.
Más adelante, estudiaremos en detalle el concepto de clases en JavaScript.
Metodos de Arrays
Para concluir con este resumen, es importante mencionar que JavaScript proporciona varios métodos integrados para manipular y transformar arreglos (arrays).
-
push
: Agrega uno o más elementos al final de un arreglo y devuelve la nueva longitud del arreglo.1let numeros = [1, 2, 3, 4, 5];2numeros.push(6);3console.log(numeros); // [1, 2, 3, 4, 5, 6] -
pop
: Elimina el último elemento de un arreglo y lo devuelve.1let numeros = [1, 2, 3, 4, 5];2let ultimo = numeros.pop();3console.log(ultimo); // 54console.log(numeros); // [1, 2, 3, 4] -
unshift
: Agrega uno o más elementos al inicio de un arreglo y devuelve la nueva longitud del arreglo.1let numeros = [2, 3, 4, 5];2numeros.unshift(1);3console.log(numeros); // [1, 2, 3, 4, 5] -
shift
: Elimina el primer elemento de un arreglo y lo devuelve.1let numeros = [1, 2, 3, 4, 5];2let primero = numeros.shift();3console.log(primero); // 14console.log(numeros); // [2, 3, 4, 5] -
concat
: Combina dos o más arreglos y devuelve un nuevo arreglo resultante.1let numeros1 = [1, 2, 3];2let numeros2 = [4, 5, 6];3let numerosCombinados = numeros1.concat(numeros2);4console.log(numerosCombinados); // [1, 2, 3, 4, 5, 6] -
slice
: Devuelve una copia superficial (shallow copy) de una porción de un arreglo en un nuevo arreglo.1let numeros = [1, 2, 3, 4, 5];2let subarreglo = numeros.slice(1, 4);3console.log(subarreglo); // [2, 3, 4] -
splice
: Cambia el contenido de un arreglo eliminando, reemplazando o agregando elementos.1let numeros = [1, 2, 3, 4, 5];2numeros.splice(2, 1); // Elimina un elemento en la posición 23console.log(numeros); // [1, 2, 4, 5]45numeros.splice(2, 0, 3); // Agrega el número 3 en la posición 26console.log(numeros); // [1, 2, 3, 4, 5]78numeros.splice(2, 1, 6); // Reemplaza el número 3 por el número 6 en la posición 29console.log(numeros); // [1, 2, 6, 4, 5] -
forEach
: Ejecuta una función dada una vez por cada elemento del arreglo.1let numeros = [1, 2, 3, 4, 5];2numeros.forEach(function(numero) {3console.log(numero);4}); -
map
: Crea un nuevo arreglo con los resultados de aplicar una función a cada elemento del arreglo.1let numeros = [1, 2, 3, 4, 5];2let cuadrados = numeros.map(function(numero) {3return numero * numero;4});5console.log(cuadrados); // [1, 4, 9, 16, 25] -
filter
: Crea un nuevo arreglo con todos los elementos que pasen una prueba (función de filtrado) específica.1let numeros = [1, 2, 3, 4, 5];2let pares = numeros.filter(function(numero) {3return numero % 2 === 0;4});5console.log(pares); // [2, 4] -
find
: Devuelve el primer elemento en el arreglo que cumple con una condición dada.1let numeros = [1, 2, 3, 4, 5];2let mayorQueTres = numeros.find(function(numero) {3return numero > 3;4});5console.log(mayorQueTres); // 4 -
findIndex
: Devuelve el índice del primer elemento en el arreglo que cumple con una condición dada.1let numeros = [1, 2, 3, 4, 5];2let indiceMayorQueTres = numeros.findIndex(function(numero) {3return numero > 3;4});5console.log(indiceMayorQueTres); // 3 -
reduce
: Aplica una función a un acumulador y a cada elemento del arreglo (de izquierda a derecha) para reducirlo a un solo valor.1let numeros = [1, 2, 3, 4, 5];2let suma = numeros.reduce(function(acumulador, numero) {3return acumulador + numero;4}, 0);5console.log(suma); // 15 -
sort
: Ordena los elementos de un arreglo in situ (modifica el arreglo original) o devuelve un nuevo arreglo ordenado.1let numeros = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5];2numeros.sort();3console.log(numeros); // [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9] -
reverse
: Invierte el orden de los elementos de un arreglo in situ (modifica el arreglo original).1let numeros = [1, 2, 3, 4, 5];2numeros.reverse();3console.log(numeros); // [5, 4, 3, 2, 1]
El término “in situ” se refiere a realizar una operación o modificación directamente en el lugar o en el contexto original, sin crear una copia o un nuevo objeto. En el contexto de los métodos de manipulación de arreglos en JavaScript, “in situ” significa que la operación se realiza directamente en el arreglo original, modificando su contenido sin crear un nuevo arreglo.