split() y join()JavaScript (abreviado JS) es un lenguaje de programación interpretado, de alto nivel y tipado dinámico. Nació en 1995 para añadir interactividad a las páginas web, pero hoy se usa tanto en el frontend (navegador) como en el backend (servidor con Node.js), en aplicaciones móviles, scripts de automatización y mucho más.
Características clave:
var nombre = "Ana"; // Ámbito de función (evitar en código moderno)
let edad = 25; // Ámbito de bloque, reasignable
const PI = 3.1416; // Ámbito de bloque, NO reasignable
Regla general: usa
constpor defecto;letsolo cuando necesites reasignar. Evitavar.
// Primitivos
let texto = "Hola mundo"; // String
let numero = 42; // Number
let decimal = 3.14; // Number (no hay tipo Float separado)
let activo = true; // Boolean
let nulo = null; // Null (ausencia intencional de valor)
let indefinido; // undefined (variable declarada sin valor)
let id = Symbol("id"); // Symbol (identificador único)
let grande = 9007199254740993n; // BigInt
// Compuestos
let array = [1, 2, 3];
let objeto = { nombre: "Ana", edad: 25 };
let funcion = function() {};
// Aritméticos
5 + 3 // 8
10 - 4 // 6
3 * 7 // 21
9 / 2 // 4.5
9 % 2 // 1 (módulo / resto)
2 ** 3 // 8 (potencia)
// Comparación — SIEMPRE usa === y !== (compara valor Y tipo)
5 === "5" // false ✅ recomendado
5 == "5" // true ❌ hace coerción de tipos
// Lógicos
true && false // false (AND)
true || false // true (OR)
!true // false (NOT)
// Asignación
let x = 10;
x += 5; // x = 15
x -= 3; // x = 12
x *= 2; // x = 24
// if / else if / else
if (edad >= 18) {
console.log("Mayor de edad");
} else if (edad >= 12) {
console.log("Adolescente");
} else {
console.log("Niño");
}
// Operador ternario
const mensaje = edad >= 18 ? "Mayor" : "Menor";
// switch
switch (dia) {
case "lunes":
console.log("Inicio de semana");
break;
case "viernes":
console.log("¡Por fin viernes!");
break;
default:
console.log("Día entre semana");
}
// Nullish coalescing (??) — devuelve el valor derecho si el izquierdo es null/undefined
const nombre = usuario.nombre ?? "Anónimo";
// Optional chaining (?.) — accede a propiedades sin lanzar error si es null/undefined
const ciudad = usuario?.direccion?.ciudad;
// for clásico
for (let i = 0; i < 5; i++) {
console.log(i);
}
// for...of (iterar valores de un iterable: arrays, strings…)
const frutas = ["manzana", "pera", "uva"];
for (const fruta of frutas) {
console.log(fruta);
}
// for...in (iterar claves de un objeto)
const persona = { nombre: "Ana", edad: 25 };
for (const clave in persona) {
console.log(clave, persona[clave]);
}
// while
let contador = 0;
while (contador < 3) {
console.log(contador);
contador++;
}
// Métodos de array (preferibles en código funcional)
frutas.forEach(f => console.log(f));
const mayusculas = frutas.map(f => f.toUpperCase());
const largas = frutas.filter(f => f.length > 4);
// Declaración clásica (hoisting: se puede llamar antes de definirla)
function saludar(nombre) {
return `Hola, ${nombre}!`;
}
// Expresión de función
const despedir = function(nombre) {
return `Adiós, ${nombre}`;
};
// Arrow function (sintaxis moderna, más concisa)
const sumar = (a, b) => a + b;
const cuadrado = n => n * n; // Paréntesis opcionales con un solo parámetro
// Parámetros por defecto
function conectar(host = "localhost", puerto = 3000) {
console.log(`Conectando a ${host}:${puerto}`);
}
// Rest parameters (recoge argumentos variables en un array)
function suma(...numeros) {
return numeros.reduce((acc, n) => acc + n, 0);
}
suma(1, 2, 3, 4); // 10
// Desestructuración de arrays
const [primero, segundo, ...resto] = [10, 20, 30, 40];
// primero = 10, segundo = 20, resto = [30, 40]
// Desestructuración de objetos
const { nombre, edad, ciudad = "Madrid" } = persona;
// Spread operator (expandir elementos)
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
const obj1 = { a: 1 };
const obj2 = { ...obj1, b: 2 }; // { a: 1, b: 2 }
// Muy útil para clonar sin mutar el original
const copia = { ...persona, edad: 26 };
class Animal {
#nombre; // Campo privado (ES2022)
constructor(nombre, sonido) {
this.#nombre = nombre;
this.sonido = sonido;
}
hablar() {
return `${this.#nombre} dice: ${this.sonido}`;
}
get nombre() {
return this.#nombre;
}
}
class Perro extends Animal {
constructor(nombre) {
super(nombre, "¡Guau!");
}
buscarPalo() {
return `${this.nombre} ha encontrado el palo 🐕`;
}
}
const rex = new Perro("Rex");
console.log(rex.hablar()); // Rex dice: ¡Guau!
console.log(rex.buscarPalo()); // Rex ha encontrado el palo 🐕
// math.js — exportar
export const PI = 3.14159;
export function sumar(a, b) { return a + b; }
export default class Calculadora { /* ... */ }
// main.js — importar
import Calculadora, { PI, sumar } from "./math.js";
import * as Math from "./math.js"; // Importar todo bajo un namespace
JavaScript es multiparadigma: se puede programar de varias formas según el problema.
El más básico. Das instrucciones paso a paso que modifican el estado del programa.
let resultado = 0;
for (let i = 1; i <= 5; i++) {
resultado += i;
}
console.log(resultado); // 15
Organiza el código en objetos con propiedades (datos) y métodos (comportamiento). Soporta los pilares clásicos:
#extends + super()class CuentaBancaria {
#saldo = 0;
depositar(cantidad) { this.#saldo += cantidad; }
retirar(cantidad) {
if (cantidad > this.#saldo) throw new Error("Saldo insuficiente");
this.#saldo -= cantidad;
}
get saldo() { return this.#saldo; }
}
Trata la computación como evaluación de funciones matemáticas. Principios clave:
// Funciones puras
const doble = n => n * 2;
const esPar = n => n % 2 === 0;
const sumarUno = n => n + 1;
// Operaciones funcionales sobre arrays (no mutan el original)
const numeros = [1, 2, 3, 4, 5, 6];
const resultado = numeros
.filter(esPar) // [2, 4, 6]
.map(doble) // [4, 8, 12]
.reduce((acc, n) => acc + n, 0); // 24
// Composición de funciones
const componer = (...fns) => x => fns.reduceRight((v, f) => f(v), x);
const procesarNumero = componer(sumarUno, doble, esPar);
Muy presente en el navegador y en Node.js. El código reacciona a eventos (clicks, peticiones HTTP, mensajes…).
// Navegador
document.getElementById("boton").addEventListener("click", (event) => {
console.log("Botón pulsado:", event.target);
});
// Node.js (EventEmitter)
const EventEmitter = require("events");
const emisor = new EventEmitter();
emisor.on("datos", (info) => console.log("Recibido:", info));
emisor.emit("datos", { usuario: "Ana" });
JavaScript es un lenguaje monohilo: ejecuta una sola tarea a la vez. Sin embargo, muchas operaciones del mundo real llevan tiempo: consultar una base de datos, llamar a una API externa, leer un fichero del disco... Si JavaScript se bloqueara esperando cada una de estas operaciones, la aplicación quedaría congelada.
Para resolver esto, JavaScript incorpora un modelo de ejecución asíncrono: puede iniciar una operación lenta y, mientras espera el resultado, seguir ejecutando otro código. Cuando la operación termina, JavaScript vuelve a ella para procesar el resultado.
Promise)Una promesa es un objeto que representa el resultado eventual (o el fallo) de una operación asíncrona.
| Estado | Descripción |
|---|---|
pending |
La operación aún no ha terminado |
fulfilled |
La operación terminó con éxito |
rejected |
La operación terminó con un error |
const miPromesa = new Promise((resolve, reject) => {
const exito = true;
if (exito) {
resolve("Datos recibidos correctamente");
} else {
reject("Ha ocurrido un error");
}
});
miPromesa
.then(resultado => console.log(resultado))
.catch(error => console.error(error))
.finally(() => console.log("Operación finalizada"));
async / awaitSintaxis moderna y legible para trabajar con promesas:
async function obtenerDatos() {
try {
const respuesta = await fetch("https://api.ejemplo.com/datos");
const datos = await respuesta.json();
console.log(datos);
} catch (error) {
console.error("Error al obtener datos:", error);
}
}
obtenerDatos();
Promise.all y Promise.race// Promise.all — espera a que TODAS se resuelvan (o falla si una falla)
const [usuarios, productos] = await Promise.all([
fetch("/api/usuarios").then(r => r.json()),
fetch("/api/productos").then(r => r.json()),
]);
// Promise.race — devuelve la primera que se resuelva
const resultado = await Promise.race([
fetch("/api/rapida"),
new Promise((_, reject) => setTimeout(() => reject("Timeout"), 5000))
]);
// ❌ Callbacks anidados ("callback hell")
getData(function(a) {
getMoreData(a, function(b) {
getEvenMoreData(b, function(c) {
console.log(c);
});
});
});
// ✅ Promesas encadenadas
getData()
.then(a => getMoreData(a))
.then(b => getEvenMoreData(b))
.then(c => console.log(c))
.catch(err => console.error(err));
// ✅✅ async/await (más legible)
async function proceso() {
const a = await getData();
const b = await getMoreData(a);
const c = await getEvenMoreData(b);
console.log(c);
}
split() y join()split(separador)Divide una cadena en un array de subcadenas:
"hola upm".split(' '); // ["hola", "upm"]
"a,b,c".split(','); // ["a", "b", "c"]
"abc".split(''); // ["a", "b", "c"]
join(separador)Une los elementos de un array en una cadena:
["hola", "upm"].join(''); // "holaupm"
["hola", "upm"].join(' '); // "hola upm"
["hola", "upm"].join('-'); // "hola-upm"
// Invertir una cadena
"JavaScript".split('').reverse().join('');
// → "tpircSavaJ"
// Eliminar espacios duplicados
"hola mundo".split(' ').filter(Boolean).join(' ');
// → "hola mundo"
// CSV ↔ array
const csv = "Madrid,Barcelona,Valencia";
const ciudades = csv.split(',');
const nuevo = ciudades.join(' | '); // "Madrid | Barcelona | Valencia"
Node.js es un entorno de ejecución de JavaScript fuera del navegador, construido sobre el motor V8 de Chrome. Permite usar JavaScript en el servidor para crear APIs, scripts de automatización, herramientas CLI, etc.
Navegador Node.js
────────────── ──────────────────
JS + DOM API JS + APIs del sistema
window, document fs, http, path, os…
Limitado al sandbox Acceso total al SO
Descarga el instalador desde nodejs.org o usa un gestor de versiones:
# Con nvm (Node Version Manager) — recomendado
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
nvm install --lts # Instala la versión LTS más reciente
nvm use --lts
# Comprobar versiones
node --version # v22.x.x
npm --version # 10.x.x
// Módulo fs (sistema de ficheros)
const fs = require("fs");
const contenido = fs.readFileSync("archivo.txt", "utf8");
// Con promesas (fs/promises)
import { readFile, writeFile } from "fs/promises";
const texto = await readFile("archivo.txt", "utf8");
// Módulo http (servidor HTTP básico)
const http = require("http");
const servidor = http.createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("¡Hola desde Node.js!");
});
servidor.listen(3000, () => console.log("Servidor en http://localhost:3000"));
// Módulo path
const path = require("path");
const ruta = path.join(__dirname, "src", "index.js");
// Módulo os
const os = require("os");
console.log(os.platform(), os.cpus().length);
npm install express
import express from "express";
const app = express();
app.use(express.json()); // Parsear JSON en el body
app.get("/usuarios", (req, res) => {
res.json([{ id: 1, nombre: "Ana" }]);
});
app.post("/usuarios", (req, res) => {
const { nombre } = req.body;
res.status(201).json({ id: 2, nombre });
});
app.listen(3000, () => console.log("API lista en http://localhost:3000"));
Un gestor de paquetes permite instalar, actualizar y gestionar las dependencias de tu proyecto (librerías de terceros).
package.json — el corazón del proyecto{
"name": "mi-proyecto",
"version": "1.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"test": "jest"
},
"dependencies": {
"react": "^18.3.0",
"axios": "^1.7.0"
},
"devDependencies": {
"vite": "^5.0.0",
"jest": "^29.0.0"
}
}
dependencies → librerías necesarias en producción.devDependencies → herramientas solo para desarrollo (bundlers, linters, testers…).Viene incluido con Node.js. Es el gestor más extendido.
# Inicializar un proyecto
npm init -y
# Instalar una dependencia
npm install react
npm install react --save-dev # Solo desarrollo
npm install # Instalar todo lo de package.json
# Actualizar / desinstalar
npm update axios
npm uninstall lodash
# Ejecutar scripts definidos en package.json
npm run dev
npm run build
npm test
# Ver paquetes instalados globalmente
npm list -g --depth=0
Alternativa a npm mucho más rápida y eficiente en disco. Usa un almacén global con hardlinks en lugar de copiar paquetes en cada proyecto.
# Instalar pnpm
npm install -g pnpm
# Uso (la API es casi idéntica a npm)
pnpm init
pnpm install react
pnpm add axios
pnpm add -D vite # Dependencia de desarrollo
pnpm remove lodash
pnpm run dev
Otra alternativa popular, especialmente en proyectos React/monorepos.
# Instalar yarn
npm install -g yarn
# Uso
yarn init
yarn add react
yarn add --dev eslint
yarn remove lodash
yarn dev # Equivale a npm run dev
| Característica | npm | pnpm | yarn |
|---|---|---|---|
| Velocidad | Buena | ⚡ Muy alta | Alta |
| Espacio en disco | Alto | ⚡ Muy bajo | Medio |
| Compatibilidad | Universal | Alta | Alta |
| Monorepos | Básico | Excelente | Bueno (workspaces) |
| Incluido con Node | ✅ Sí | ❌ (instalar aparte) | ❌ (instalar aparte) |
La librería de UI más popular, creada por Meta. Basada en componentes reutilizables y un DOM virtual para actualizaciones eficientes.
# Crear proyecto con Vite (recomendado)
pnpm create vite mi-app --template react
cd mi-app && pnpm install && pnpm dev
# O con Create React App (más pesado, menos usado hoy)
npx create-react-app mi-app
// Componente funcional con hooks
import { useState, useEffect } from "react";
function Contador({ inicio = 0 }) {
const [cuenta, setCuenta] = useState(inicio);
useEffect(() => {
document.title = `Cuenta: ${cuenta}`;
}, [cuenta]); // Se ejecuta cada vez que cambia `cuenta`
return (
<div>
<p>Cuenta: {cuenta}</p>
<button onClick={() => setCuenta(c => c + 1)}>+</button>
<button onClick={() => setCuenta(c => c - 1)}>-</button>
</div>
);
}
export default Contador;
Hooks más comunes:
| Hook | Para qué sirve |
|---|---|
useState |
Estado local del componente |
useEffect |
Efectos secundarios (fetch, timers, DOM…) |
useContext |
Consumir contexto global |
useRef |
Referenciar elementos del DOM |
useMemo |
Memorizar cálculos costosos |
useCallback |
Memorizar funciones |
Framework completo mantenido por Google. Ideal para aplicaciones empresariales grandes. Usa TypeScript por defecto.
npm install -g @angular/cli
ng new mi-app
cd mi-app && ng serve
// Componente Angular
import { Component, OnInit } from "@angular/core";
import { HttpClient } from "@angular/common/http";
@Component({
selector: "app-usuarios",
template: `
<ul>
<li *ngFor="let u of usuarios">{{ u.nombre }}</li>
</ul>
`
})
export class UsuariosComponent implements OnInit {
usuarios: any[] = [];
constructor(private http: HttpClient) {}
ngOnInit() {
this.http.get<any[]>("/api/usuarios").subscribe(data => {
this.usuarios = data;
});
}
}
Framework progresivo: se puede añadir de forma incremental a un proyecto existente. Muy buena curva de aprendizaje.
pnpm create vue@latest mi-app
cd mi-app && pnpm install && pnpm dev
<script setup>
import { ref, onMounted } from "vue";
const usuarios = ref([]);
onMounted(async () => {
const res = await fetch("/api/usuarios");
usuarios.value = await res.json();
});
</script>
<template>
<ul>
<li v-for="u in usuarios" :key="u.id">{{ u.nombre }}</li>
</ul>
</template>
Framework full-stack sobre React. Añade Server-Side Rendering (SSR), generación estática (SSG), routing basado en ficheros, API Routes y más.
npx create-next-app@latest mi-app
cd mi-app && npm run dev
// app/page.jsx — Server Component (se ejecuta en el servidor)
async function Inicio() {
const datos = await fetch("https://api.ejemplo.com/posts").then(r => r.json());
return (
<main>
{datos.map(post => (
<article key={post.id}>
<h2>{post.titulo}</h2>
</article>
))}
</main>
);
}
export default Inicio;
La librería de CSS y componentes UI más usada históricamente. Permite crear interfaces responsivas rápidamente con clases predefinidas.
npm install bootstrap
<!-- En HTML puro -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
<div class="container mt-4">
<div class="row">
<div class="col-md-6">
<div class="card">
<div class="card-body">
<h5 class="card-title">Título</h5>
<button class="btn btn-primary">Acción</button>
</div>
</div>
</div>
</div>
</div>
// En React con react-bootstrap
import { Button, Card } from "react-bootstrap";
import "bootstrap/dist/css/bootstrap.min.css";
function MiTarjeta() {
return (
<Card style={{ width: "18rem" }}>
<Card.Body>
<Card.Title>Título</Card.Title>
<Button variant="primary">Acción</Button>
</Card.Body>
</Card>
);
}
| Librería | Categoría | Para qué sirve |
|---|---|---|
| Axios | HTTP | Peticiones HTTP más cómodas que fetch |
| Lodash | Utilidades | Funciones de manipulación de arrays, objetos, strings |
| date-fns / dayjs | Fechas | Manipulación y formateo de fechas |
| Zod | Validación | Esquemas y validación de tipos en runtime |
| Zustand / Redux | Estado global | Gestión del estado en apps React |
| React Query | Data fetching | Cache y sincronización de datos del servidor |
| Socket.io | Tiempo real | WebSockets simplificados |
| Jest / Vitest | Testing | Tests unitarios y de integración |
| ESLint / Prettier | Calidad código | Linting y formateo automático |
Las aplicaciones modernas de JavaScript necesitan ser transformadas antes de llegar al navegador: transpilar TypeScript/JSX, empaquetar módulos, minificar código, etc.
El bundler más popular actualmente. Extremadamente rápido gracias al uso de ES Modules nativos durante el desarrollo.
# Crear proyecto (elige tu framework en el asistente)
pnpm create vite mi-app
cd mi-app && pnpm install
# Comandos
pnpm dev # Servidor de desarrollo (HMR instantáneo)
pnpm build # Construir para producción (usa Rollup internamente)
pnpm preview # Previsualizar el build de producción
// vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
server: {
port: 4000,
proxy: {
"/api": "http://localhost:3000" // Proxy para el backend
}
}
});
El bundler más veterano y flexible. Tiene una configuración más compleja, pero es muy potente. Next.js lo usa internamente (migrando a Turbopack).
npm install --save-dev webpack webpack-cli
// webpack.config.js (configuración básica)
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
},
module: {
rules: [
{ test: /\.jsx?$/, use: "babel-loader", exclude: /node_modules/ },
{ test: /\.css$/, use: ["style-loader", "css-loader"] },
],
},
};
Superset de JavaScript que añade tipado estático. Detecta errores en tiempo de compilación, no en ejecución.
pnpm add -D typescript
npx tsc --init # Genera tsconfig.json
// Tipos básicos
let nombre: string = "Ana";
let edad: number = 25;
let activo: boolean = true;
let lista: number[] = [1, 2, 3];
// Interfaces y tipos
interface Usuario {
id: number;
nombre: string;
email?: string; // Propiedad opcional
}
type Resultado<T> = {
datos: T;
error: string | null;
exito: boolean;
};
// Función tipada
async function obtenerUsuario(id: number): Promise<Usuario> {
const res = await fetch(`/api/usuarios/${id}`);
return res.json() as Promise<Usuario>;
}
| Concepto | Idea clave |
|---|---|
| JavaScript | Lenguaje interpretado, dinámico y multiparadigma |
let / const |
Variables modernas con ámbito de bloque |
| Arrow functions | Sintaxis concisa para funciones: (a, b) => a + b |
| Desestructuración | Extraer valores de arrays/objetos fácilmente |
| Spread operator | Expandir iterables: [...arr], {...obj} |
| Promesas | Representan el resultado futuro de una operación asíncrona |
async/await |
Sintaxis moderna para consumir promesas de forma legible |
split / join |
Convertir strings ↔ arrays |
| Node.js | JS en el servidor; acceso a ficheros, red, SO… |
| npm / pnpm / yarn | Gestores de paquetes para instalar dependencias |
| React | Librería de UI basada en componentes y hooks |
| Angular | Framework completo para apps empresariales (TypeScript) |
| Vue.js | Framework progresivo con excelente DX |
| Next.js | Full-stack con React: SSR, SSG, routing y API routes |
| Bootstrap | Librería CSS de componentes responsivos listos para usar |
| Vite | Bundler moderno: desarrollo instantáneo, build optimizado |
| TypeScript | JS con tipado estático; detecta errores en compilación |
| Paradigmas | Imperativo, OOP, Funcional y Event-Driven |