Saltar al contenido
schedule 12 min JavaScript

Operadores y condicionales

Ya sabes guardar datos en variables. Pero guardar datos sin poder hacer nada con ellos es como tener un almacén lleno de ingredientes sin saber cocinar. Los operadores transforman datos y los condicionales toman decisiones. Juntos, hacen que tu programa piense. En la sección de Lógica ya practicaste operadores y condicionales con pseudocódigo — ahora vas a escribirlos en JavaScript con sintaxis real.

En esta lección vas a construir un calculador de precios para una tienda online. Cuando la termines, tu programa va a saber calcular descuentos, aplicar impuestos y decidir qué precio mostrar según la cantidad que compre el usuario. Eso es programar de verdad.

Operadores aritméticos

Los básicos de las matemáticas, con un par de extras que en el cole no te enseñaron:

app.js
const precio = 29.99;
const cantidad = 4;
const impuesto = 0.21;

// Operadores básicos
console.log(precio + 10);      // → 39.99 (suma)
console.log(precio - 5);       // → 24.99 (resta)
console.log(precio * cantidad); // → 119.96 (multiplicación)
console.log(119.96 / 4);       // → 29.99 (división)

// Módulo: el resto de la división
console.log(10 % 3); // → 1 (10 / 3 = 3, resto 1)
console.log(7 % 2);  // → 1 (si es 1, el número es impar)
console.log(8 % 2);  // → 0 (si es 0, el número es par)

// Exponenciación
console.log(2 ** 10); // → 1024 (2 elevado a 10)

// Cálculo real: precio con IVA
const precioConIVA = precio * (1 + impuesto);
console.log(precioConIVA); // → 36.2879...

// Redondear a 2 decimales para dinero
const precioFinal = Math.round(precioConIVA * 100) / 100;
console.log(precioFinal); // → 36.29

Operadores de asignación compuesta

Atajos para modificar una variable reutilizando su valor actual:

app.js
let puntos = 100;

puntos += 50;  // puntos = puntos + 50 → 150
puntos -= 20;  // puntos = puntos - 20 → 130
puntos *= 2;   // puntos = puntos * 2 → 260
puntos /= 4;   // puntos = puntos / 4 → 65

console.log(puntos); // → 65

// Incremento y decremento
let vidas = 3;
vidas++;  // vidas = vidas + 1 → 4
vidas--;  // vidas = vidas - 1 → 3

Operadores de comparación

Comparan dos valores y devuelven true o false. Son la base de todas las decisiones en tu código.

app.js
const edad = 25;
const precioProducto = 49.99;

// Comparaciones básicas
console.log(edad > 18);          // → true (mayor que)
console.log(edad < 18);          // → false (menor que)
console.log(edad >= 25);         // → true (mayor o igual)
console.log(precioProducto <= 50); // → true (menor o igual)

=== vs == : usa siempre ===

Esta es una de las reglas más importantes de JavaScript moderno. Existen dos tipos de igualdad:

app.js
// == (igualdad débil): convierte tipos antes de comparar
console.log(5 == "5");     // → true 😱 (convierte "5" a 5)
console.log(0 == false);   // → true 😱 (convierte false a 0)
console.log("" == false);  // → true 😱 (convierte ambos)
console.log(null == undefined); // → true 😱

// === (igualdad estricta): compara valor Y tipo
console.log(5 === "5");     // → false ✅ (diferente tipo)
console.log(0 === false);   // → false ✅ (number vs boolean)
console.log("" === false);  // → false ✅ (string vs boolean)
console.log(null === undefined); // → false ✅

Usa siempre === y !==. El == tiene reglas de conversión de tipos tan confusas que ni los expertos las recuerdan todas. Con === no hay sorpresas: si el tipo es diferente, es false. Punto.

// ❌ Igualdad débil: bugs esperando a pasar
if (cantidad == "0") { /* ... */ }

// ✅ Igualdad estricta: predecible
if (cantidad === 0) { /* ... */ }

// Desigualdad
console.log(5 !== "5"); // → true (diferente tipo)
console.log(5 !== 5);   // → false (mismo valor y tipo)

Operadores lógicos

Combinan condiciones booleanas. Son tres y los vas a usar en cada if que escribas:

&& (AND): ambas condiciones deben ser true

app.js
const edad = 25;
const tieneDNI = true;

// Para entrar al concierto necesitas tener 18+ Y mostrar el DNI
const puedeEntrar = edad >= 18 && tieneDNI;
console.log(puedeEntrar); // → true

// Caso real: descuento solo para suscriptores que compren más de 50€
const esSuscriptor = true;
const totalCompra = 75;
const tieneDescuentoVIP = esSuscriptor && totalCompra > 50;
console.log(tieneDescuentoVIP); // → true

|| (OR): al menos una condición debe ser true

app.js
const esDomingo = true;
const esFestivo = false;

// La tienda cierra si es domingo O festivo
const tiendaCerrada = esDomingo || esFestivo;
console.log(tiendaCerrada); // → true

// Envío gratis si compras más de 50€ O eres suscriptor premium
const totalCompra = 30;
const esPremium = true;
const envioGratis = totalCompra > 50 || esPremium;
console.log(envioGratis); // → true (porque esPremium es true)

! (NOT): invierte el valor

app.js
const estaLogueado = false;

console.log(!estaLogueado);  // → true (invierte false)
console.log(!true);           // → false

// Uso real: mostrar algo solo si el usuario NO está logueado
if (!estaLogueado) {
    console.log("Muestra el botón de iniciar sesión");
}

Short-circuit evaluation (evaluación de cortocircuito)

Los operadores lógicos son inteligentes. Dejan de evaluar en cuanto saben el resultado:

app.js
// && devuelve el primer valor falsy (o el último si todos son truthy)
console.log("Hola" && "Mundo"); // → "Mundo" (ambos truthy, devuelve el último)
console.log(0 && "Mundo");      // → 0 (el primero es falsy, ni mira el segundo)
console.log("" && "Mundo");     // → "" (string vacío es falsy)

// || devuelve el primer valor truthy (o el último si todos son falsy)
console.log("" || "Por defecto");   // → "Por defecto"
console.log(null || "Respaldo");    // → "Respaldo"
console.log("Hola" || "Respaldo"); // → "Hola" (ya encontró un truthy)

// Uso práctico: valores por defecto
const nombreUsuario = "" || "Invitado";
console.log(nombreUsuario); // → "Invitado"

Esto es muy potente y lo vas a ver en código real constantemente. Pero tiene una trampa: || considera 0 y "" como falsy, lo cual a veces no es lo que quieres. Para eso existe el operador nullish coalescing.

Nullish coalescing: ??

El operador ?? es como || pero solo reacciona a null y undefined, no a otros valores falsy como 0 o "":

app.js
// El problema con ||
const descuento = 0; // El usuario tiene 0% de descuento (es válido)
const descuentoFinal = descuento || 10;
console.log(descuentoFinal); // → 10 ❌ (0 es falsy, así que usa 10)

// La solución con ??
const descuentoCorrect = descuento ?? 10;
console.log(descuentoCorrect); // → 0 ✅ (0 no es null ni undefined)

// Más ejemplos
console.log(null ?? "valor por defecto");      // → "valor por defecto"
console.log(undefined ?? "valor por defecto");  // → "valor por defecto"
console.log(0 ?? "valor por defecto");          // → 0 ✅
console.log("" ?? "valor por defecto");         // → "" ✅
console.log(false ?? "valor por defecto");      // → false ✅

Regla práctica: usa ?? cuando quieras un valor por defecto solo si la variable es null o undefined. Usa || cuando quieras un valor por defecto para cualquier valor falsy.

if / else: decisiones en tu código

La estructura de control más fundamental. Evalúa una condición y ejecuta un bloque de código u otro:

app.js
const temperatura = 35;

if (temperatura > 30) {
    console.log("Hace calor. Pide un helado.");
} else if (temperatura > 20) {
    console.log("Temperatura agradable. Perfecto para pasear.");
} else if (temperatura > 10) {
    console.log("Fresquito. Llévate una chaqueta.");
} else {
    console.log("Hace frío. Quédate en casa con chocolate caliente.");
}

Ejemplo real: calculador de descuentos

Vamos a construir algo útil. Un e-commerce que aplica descuentos según la cantidad que compras:

app.js
const precioUnitario = 15.99;
const cantidad = 12;
const esSuscriptor = true;
const codigoCupon = "VERANO25";

// 1. Calcular subtotal
const subtotal = precioUnitario * cantidad;
console.log(`Subtotal: ${subtotal} €`);

// 2. Descuento por volumen
let descuentoVolumen = 0;

if (cantidad >= 50) {
    descuentoVolumen = 0.20; // 20% para pedidos de 50+
} else if (cantidad >= 20) {
    descuentoVolumen = 0.15; // 15% para pedidos de 20-49
} else if (cantidad >= 10) {
    descuentoVolumen = 0.10; // 10% para pedidos de 10-19
} else if (cantidad >= 5) {
    descuentoVolumen = 0.05; // 5% para pedidos de 5-9
}
// Menos de 5: sin descuento por volumen

console.log(`Descuento por volumen: ${descuentoVolumen * 100}%`);

// 3. Descuento por suscriptor
const descuentoSuscriptor = esSuscriptor ? 0.05 : 0;

// 4. Descuento por cupón
let descuentoCupon = 0;

if (codigoCupon === "VERANO25") {
    descuentoCupon = 0.25;
} else if (codigoCupon === "BIENVENIDO10") {
    descuentoCupon = 0.10;
} else if (codigoCupon === "AMIGO15") {
    descuentoCupon = 0.15;
}

// 5. Aplicar el mejor descuento (no se acumulan)
const mejorDescuento = Math.max(descuentoVolumen, descuentoCupon);
const descuentoTotal = mejorDescuento + descuentoSuscriptor;
const ahorro = subtotal * descuentoTotal;
const totalFinal = subtotal - ahorro;

console.log(`Mejor descuento: ${mejorDescuento * 100}%`);
console.log(`Descuento suscriptor: ${descuentoSuscriptor * 100}%`);
console.log(`Ahorro total: ${ahorro.toFixed(2)} €`);
console.log(`Total final: ${totalFinal.toFixed(2)} €`);

Fíjate cómo los if / else if van de mayor a menor. Si la cantidad es 12, la primera condición (>= 50) es falsa, la segunda (>= 20) también, pero la tercera (>= 10) es verdadera, así que entra ahí y se aplica el 10%.

Operador ternario: if/else en una línea

Cuando la condición es simple y solo necesitas elegir entre dos valores, el ternario es más conciso:

app.js
// Sintaxis: condición ? valorSiTrue : valorSiFalse

const edad = 17;
const acceso = edad >= 18 ? "Permitido" : "Denegado";
console.log(acceso); // → "Denegado"

// Ejemplos prácticos
const stock = 0;
const textoStock = stock > 0 ? `${stock} disponibles` : "Agotado";

const itemsCarrito = 3;
const textoCarrito = itemsCarrito === 1 ? "1 artículo" : `${itemsCarrito} artículos`;

const usuario = null;
const saludo = usuario ? `Hola, ${usuario}` : "Hola, invitado";

// En template literals
const precio = 29.99;
const esSuscriptor = true;
const precioFinal = esSuscriptor ? precio * 0.9 : precio;
console.log(`Precio: ${precioFinal.toFixed(2)} € ${esSuscriptor ? "(precio suscriptor)" : ""}`);

El ternario es genial para condiciones simples. Pero si empiezas a anidar ternarios (a ? b : c ? d : e), usa un if/else normal. La legibilidad siempre gana.

switch: múltiples opciones claras

Cuando tienes una variable que puede tener varios valores específicos y quieres hacer algo diferente para cada uno, switch es más legible que una cadena de if/else if:

app.js
const rolUsuario = "editor";

switch (rolUsuario) {
    case "admin":
        console.log("Acceso total. Puedes gestionar usuarios y contenido.");
        break;

    case "editor":
        console.log("Puedes crear y editar contenido.");
        break;

    case "moderador":
        console.log("Puedes moderar comentarios y reportes.");
        break;

    case "suscriptor":
        console.log("Puedes ver contenido premium.");
        break;

    default:
        console.log("Rol no reconocido. Acceso básico.");
}

Cada case termina con break. Si te olvidas del break, JavaScript sigue ejecutando los siguientes case (esto se llama "fall-through" y es casi siempre un bug).

switch con agrupación de casos

A veces varios casos comparten la misma acción. Puedes agruparlos aprovechando el fall-through a propósito:

app.js
const diaSemana = new Date().getDay(); // 0 = domingo, 1 = lunes, ..., 6 = sábado
let horario;

switch (diaSemana) {
    case 1: // Lunes
    case 2: // Martes
    case 3: // Miércoles
    case 4: // Jueves
        horario = "9:00 - 21:00";
        break;

    case 5: // Viernes
        horario = "9:00 - 22:00 (¡horario ampliado!)";
        break;

    case 6: // Sábado
        horario = "10:00 - 22:00";
        break;

    case 0: // Domingo
        horario = "10:00 - 15:00";
        break;

    default:
        horario = "Horario no disponible";
}

console.log(`Horario de hoy: ${horario}`);

Ejemplo completo: calculador de precios por niveles

Vamos a juntar todo en un programa real. Una tienda online de camisetas que calcula el precio según la cantidad, tipo de cliente y método de envío:

index.html
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>ThreadCraft — Calculador de precios</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <header>
        <h1>ThreadCraft</h1>
        <p>Camisetas de diseño a precio justo</p>
    </header>
    <main>
        <div id="resultado"></div>
    </main>
    <script src="app.js"></script>
</body>
</html>
app.js
// ============================================
// Configuración del pedido
// ============================================
const precioBase = 24.99;
const cantidad = 15;
const tipoCliente = "empresa";  // "particular", "empresa", "mayorista"
const metodoEnvio = "express";   // "estandar", "express", "recogida"
const codigoCupon = null;        // null si no hay cupón
const IVA = 0.21;

// ============================================
// 1. Descuento por volumen (if/else if)
// ============================================
let descuentoVolumen;

if (cantidad >= 100) {
    descuentoVolumen = 0.30;
} else if (cantidad >= 50) {
    descuentoVolumen = 0.20;
} else if (cantidad >= 25) {
    descuentoVolumen = 0.15;
} else if (cantidad >= 10) {
    descuentoVolumen = 0.10;
} else {
    descuentoVolumen = 0;
}

// ============================================
// 2. Descuento por tipo de cliente (switch)
// ============================================
let descuentoCliente;

switch (tipoCliente) {
    case "mayorista":
        descuentoCliente = 0.25;
        break;
    case "empresa":
        descuentoCliente = 0.15;
        break;
    case "particular":
        descuentoCliente = 0;
        break;
    default:
        descuentoCliente = 0;
        console.warn(`Tipo de cliente no reconocido: ${tipoCliente}`);
}

// ============================================
// 3. Coste de envío (switch + ternario)
// ============================================
const subtotalBruto = precioBase * cantidad;

let costeEnvio;

switch (metodoEnvio) {
    case "express":
        costeEnvio = subtotalBruto > 100 ? 4.99 : 9.99;
        break;
    case "estandar":
        costeEnvio = subtotalBruto > 50 ? 0 : 4.99; // Gratis a partir de 50€
        break;
    case "recogida":
        costeEnvio = 0;
        break;
    default:
        costeEnvio = 4.99;
}

// ============================================
// 4. Cupón de descuento (?? y ===)
// ============================================
let descuentoCupon = 0;
const cuponActivo = codigoCupon ?? "ninguno";

if (codigoCupon === "PRIMERA10") {
    descuentoCupon = 0.10;
} else if (codigoCupon === "VERANO20") {
    descuentoCupon = 0.20;
} else if (codigoCupon === "VIP30") {
    descuentoCupon = 0.30;
}

// ============================================
// 5. Cálculo final
// ============================================
// Se aplica el mayor descuento entre volumen y cupón (no se acumulan)
const mejorDescuentoProducto = Math.max(descuentoVolumen, descuentoCupon);
// El descuento de cliente SÍ se acumula
const descuentoTotalPorcentaje = mejorDescuentoProducto + descuentoCliente;

const subtotalConDescuento = subtotalBruto * (1 - descuentoTotalPorcentaje);
const importeIVA = subtotalConDescuento * IVA;
const totalFinal = subtotalConDescuento + importeIVA + costeEnvio;

// ============================================
// 6. Clasificación del pedido (ternario anidado... mejor con if)
// ============================================
let categoriaPedido;

if (totalFinal >= 500) {
    categoriaPedido = "Pedido Premium";
} else if (totalFinal >= 200) {
    categoriaPedido = "Pedido Grande";
} else if (totalFinal >= 50) {
    categoriaPedido = "Pedido Mediano";
} else {
    categoriaPedido = "Pedido Pequeño";
}

// ============================================
// 7. Generar resumen en la página
// ============================================
const tieneDescuento = descuentoTotalPorcentaje > 0;
const envioTexto = costeEnvio === 0 ? "GRATIS" : `${costeEnvio.toFixed(2)} €`;

const resumenHTML = `
<div class="order-summary">
    <h2>${categoriaPedido}</h2>

    <div class="line-item">
        <span>Camiseta ThreadCraft x${cantidad}</span>
        <span>${subtotalBruto.toFixed(2)} €</span>
    </div>

    ${tieneDescuento ? `
    <div class="line-item discount">
        <span>Descuento (${Math.round(descuentoTotalPorcentaje * 100)}%)</span>
        <span>-${(subtotalBruto * descuentoTotalPorcentaje).toFixed(2)} €</span>
    </div>
    ` : ""}

    <div class="line-item">
        <span>IVA (21%)</span>
        <span>${importeIVA.toFixed(2)} €</span>
    </div>

    <div class="line-item">
        <span>Envío (${metodoEnvio})</span>
        <span>${envioTexto}</span>
    </div>

    <div class="line-item total">
        <span>Total</span>
        <span>${totalFinal.toFixed(2)} €</span>
    </div>

    <p class="order-meta">
        Cliente: ${tipoCliente} · Cupón: ${cuponActivo}
    </p>
</div>
`;

document.querySelector("#resultado").innerHTML = resumenHTML;

// Log de depuración
console.log("=== Desglose del pedido ===");
console.log(`Precio base: ${precioBase} € x ${cantidad} = ${subtotalBruto.toFixed(2)} €`);
console.log(`Descuento volumen: ${descuentoVolumen * 100}%`);
console.log(`Descuento cliente (${tipoCliente}): ${descuentoCliente * 100}%`);
console.log(`Descuento cupón: ${descuentoCupon * 100}%`);
console.log(`Total descuento aplicado: ${descuentoTotalPorcentaje * 100}%`);
console.log(`Envío: ${envioTexto}`);
console.log(`Total final: ${totalFinal.toFixed(2)} €`);

Este ejemplo usa todo lo que has aprendido en esta lección:

  • Operadores aritméticos: calcular subtotales, descuentos, IVA.
  • Comparaciones con ===: comprobar códigos de cupón.
  • if/else if: descuento por volumen y categoría del pedido.
  • switch: tipo de cliente y método de envío.
  • Ternario: coste de envío condicional y texto "GRATIS".
  • ??: valor por defecto para el cupón.
  • && y booleanos: decidir si mostrar la línea de descuento.
  • Template literals: generar todo el HTML del resumen.

Buenas prácticas con condicionales

Algunos consejos que te van a ahorrar bugs:

// ✅ Condiciones en positivo (más legibles)
if (estaActivo) { /* ... */ }

// ❌ Doble negación (confuso)
if (!noEstaActivo) { /* ... */ }

// ✅ Return temprano para evitar anidación
const calcularDescuento = (cantidad) => {
    if (cantidad <= 0) {
        return 0; // Sale rápido si no hay cantidad
    }

    if (cantidad >= 100) {
        return 0.30;
    }

    if (cantidad >= 50) {
        return 0.20;
    }

    return 0.10;
};

// ✅ Usa objetos en vez de switch cuando solo mapeas valores
const descuentosPorRol = {
    admin: 0.50,
    editor: 0.20,
    suscriptor: 0.10,
    invitado: 0
};

const rolActual = "editor";
const descuento = descuentosPorRol[rolActual] ?? 0;
console.log(descuento); // → 0.20

Resumen

  • Aritméticos: +, -, *, /, %, **.
  • Comparación: siempre === y !==, nunca == y !=.
  • Lógicos: && (AND), || (OR), ! (NOT). Tienen short-circuit evaluation.
  • Nullish coalescing: ?? para valores por defecto que respeten 0 y "".
  • if/else: para decisiones con condiciones complejas.
  • switch: para valores discretos (roles, estados, categorías).
  • Ternario: para condiciones simples de una línea.

En la siguiente lección vamos a aprender sobre funciones — cómo encapsular lógica en bloques reutilizables para no repetirte.

code

Calculador de envíos para una tienda online

Media schedule 20 min

Crea un calculador de costes de envío para una tienda de electrónica. Define estas variables al inicio del script:

  • pesoKg (número): el peso del paquete.
  • destino (string): "nacional", "europa" o "internacional".
  • esUrgente (boolean): si el envío es urgente.
  • cuponEnvio (string o null): código de cupón de envío.

El programa debe calcular:

  • Coste base por destino (usa switch): nacional = 5€, europa = 12€, internacional = 25€.
  • Recargo por peso (usa if/else): hasta 2kg sin recargo, 2-5kg +3€, 5-10kg +7€, más de 10kg +15€.
  • Recargo urgente (usa ternario): +50% del coste base si es urgente.
  • Cupón (usa ?? y ===): "ENVIOGRATIS" = envío gratis, "MITAD" = 50% descuento.
  • Muestra un resumen en la página con el desglose de cada coste.

Prueba con diferentes combinaciones de valores para asegurarte de que funciona correctamente.

lightbulb Pistas

Calcula primero el coste base con switch, luego el recargo por peso con if/else, luego el recargo urgente con un ternario. Suma todo y al final aplica el cupón. Recuerda usar .toFixed(2) para mostrar siempre dos decimales en los precios. El cupón "ENVIOGRATIS" debería poner el total a 0, así que aplícalo al final de todo.

Newsletter

Recibe nuevos cursos, actualizaciones, artículos del blog y promociones en tu correo.