Ir al contenido principal

Estructura de un programa JavaScript

Introducción

Cuando nos adentramos en el mundo de la programación con JavaScript, es fundamental comprender cómo se organiza y estructura un programa. Al igual que un libro tiene capítulos, párrafos y oraciones que siguen reglas gramaticales, un programa de JavaScript tiene su propia organización y sintaxis. Entender estos fundamentos nos permitirá escribir código más claro, eficiente y fácil de mantener. En este artículo, exploraremos la anatomía básica de un programa JavaScript: cómo se organizan las instrucciones, cómo se agrupan en bloques de código y qué reglas debemos seguir para que nuestro código funcione correctamente.

Organización del código

Un programa JavaScript está compuesto por una serie de instrucciones que se ejecutan secuencialmente, de arriba hacia abajo. Estas instrucciones se organizan siguiendo una jerarquía que podemos entender como "capas" de estructura:

1. Instrucciones individuales

La unidad básica de un programa JavaScript es la instrucción (también llamada sentencia o statement). Cada instrucción representa una acción que debe realizar el intérprete de JavaScript.

// Ejemplos de instrucciones individuales
let edad = 25;                    // Declaración de variable
console.log("Hola, mundo!");      // Llamada a función
if (edad >= 18) { /* código */ }  // Estructura de control

Cada instrucción suele terminar con un punto y coma (;), aunque en muchos casos JavaScript puede inferir dónde termina una instrucción incluso sin el punto y coma (hablaremos más sobre esto en otro artículo).

2. Bloques de código

Un bloque de código es un conjunto de instrucciones relacionadas que se agrupan entre llaves {}. Los bloques se utilizan en estructuras de control (como condicionales y bucles), funciones, clases, etc.

// Ejemplo de bloque de código en una estructura condicional
if (edad >= 18) {
    // Este es un bloque de código
    console.log("Eres mayor de edad");
    let mensaje = "Puedes acceder al contenido";
    console.log(mensaje);
}

Los bloques de código crean un contexto de ejecución propio, lo que afecta al ámbito (scope) de las variables declaradas dentro de ellos. Este es un concepto importante que estudiaremos en detalle más adelante.

3. Funciones

Las funciones son bloques de código reutilizables que realizan una tarea específica. Son una de las unidades organizativas más importantes en JavaScript.

// Definición de una función
function calcularArea(base, altura) {
    // Este bloque de código se ejecutará cuando la función sea llamada
    let area = base * altura;
    return area;
}

// Llamada a la función
let areaRectangulo = calcularArea(5, 3);
console.log("El área es: " + areaRectangulo); // Muestra: El área es: 15

Las funciones permiten organizar nuestro código en unidades lógicas que podemos invocar (llamar) cuando las necesitemos, evitando repetir código.

4. Módulos

En aplicaciones más grandes, el código se organiza en módulos que son archivos JavaScript independientes que contienen código relacionado. Los módulos nos permiten separar nuestro programa en componentes más pequeños y manejables.

// archivo: matematicas.js
// Exportamos funciones para que otros módulos puedan usarlas
export function sumar(a, b) {
    return a + b;
}

export function restar(a, b) {
    return a - b;
}
// archivo: principal.js
// Importamos funciones del módulo matemáticas
import { sumar, restar } from './matematicas.js';

let resultado1 = sumar(10, 5);    // 15
let resultado2 = restar(10, 5);   // 5

El sistema de módulos es una característica relativamente reciente de JavaScript (ES6) y exploraremos este tema en profundidad más adelante en el tutorial.

Instrucciones y expresiones

Para comprender mejor la estructura de un programa JavaScript, es importante distinguir entre dos conceptos fundamentales: instrucciones y expresiones.

Expresiones

Una expresión es cualquier unidad de código que produce un valor. Las expresiones se pueden combinar y anidar para formar expresiones más complejas.

Ejemplos de expresiones:

// Expresiones literales
5                      // Valor numérico
"Hola"                 // Cadena de texto
true                   // Valor booleano

// Expresiones que utilizan operadores
3 + 4                  // Expresión aritmética (produce 7)
edad >= 18             // Expresión de comparación (produce true o false)
a && b                 // Expresión lógica

// Llamadas a funciones que devuelven un valor
Math.max(5, 10)        // Produce 10
calcularArea(4, 6)     // Produce 24

// Expresiones de asignación
x = 10                 // Asigna 10 a x y produce 10 como valor

Las expresiones son como "preguntas" que JavaScript responde con un valor. Pueden aparecer en cualquier lugar donde se espere un valor.

Instrucciones

Una instrucción es una "orden" completa que le damos al programa para que realice una acción. Las instrucciones pueden contener expresiones, pero no todas las expresiones son instrucciones.

Ejemplos de instrucciones:

// Declaraciones de variables
let nombre = "Ana";    // Declara una variable y le asigna un valor
const PI = 3.14159;    // Declara una constante

// Instrucciones de control de flujo
if (puntuacion > 90) { console.log("¡Excelente!"); }
for (let i = 0; i < 5; i++) { console.log(i); }
while (condicion) { /* código */ }

// Llamadas a funciones (cuando no usamos el valor devuelto)
console.log("Hola");   // No usamos el valor que devuelve console.log
alert("¡Cuidado!");    // Instrucción que muestra una alerta

// Instrucciones de retorno de funciones
return resultado;      // Devuelve un valor y termina la ejecución de la función

// Instrucciones de importación y exportación
import { Component } from 'biblioteca';
export default clase;

La diferencia clave: las expresiones producen valores, las instrucciones realizan acciones.

Expresiones vs. Instrucciones: Un ejemplo práctico

Observa cómo se combinan expresiones e instrucciones en este fragmento de código:

// Esta es una instrucción completa (declaración de variable)
let resultado = (2 + 3) * (10 - 5); 
// ↑ Nombre   ↑ Expresión de asignación
//            ↑ Expresión aritmética
//               ↑ Sub-expresión  ↑ Sub-expresión

// Esta es otra instrucción (condicional)
if (resultado > 20) {
// ↑ Instrucción de control
//  ↑ Expresión de comparación
    console.log("El resultado es mayor que 20");
//  ↑ Instrucción (llamada a función)
} else {
    console.log("El resultado es 20 o menos");
}

Entender esta distinción es crucial para comprender la sintaxis de JavaScript y cómo estructurar correctamente nuestro código.

Bloques de código y delimitadores

Como hemos visto, los bloques de código son conjuntos de instrucciones agrupadas entre llaves {}. Estos bloques son fundamentales para organizar el código y definir el ámbito de las variables.

Uso de bloques de código

Los bloques se utilizan principalmente en:

  1. Estructuras de control:

    if (condicion) {
        // Bloque ejecutado si la condición es verdadera
    } else {
        // Bloque ejecutado si la condición es falsa
    }
    
  2. Bucles:

    for (let i = 0; i < 5; i++) {
        // Este bloque se ejecutará 5 veces
        console.log("Iteración: " + i);
    }
    
  3. Funciones:

    function saludar(nombre) {
        // Bloque que define el cuerpo de la función
        return "Hola, " + nombre;
    }
    
  4. Clases y objetos:

    class Persona {
        constructor(nombre) {
            this.nombre = nombre;
        }
        
        saludar() {
            return "Hola, soy " + this.nombre;
        }
    }
    
  5. Bloques independientes (menos comunes):

    // Se puede crear un bloque sin asociarlo a una estructura de control
    {
        let temporal = "Esta variable solo existe dentro de este bloque";
        console.log(temporal);
    }
    // temporal no existe fuera del bloque
    

Delimitadores en JavaScript

JavaScript utiliza varios símbolos como delimitadores para definir diferentes estructuras:

  1. Llaves {}: Delimitan bloques de código.

  2. Paréntesis (): Se utilizan para:

    • Agrupar expresiones: let resultado = (a + b) * c;
    • Definir parámetros de funciones: function suma(a, b) { ... }
    • Condiciones en estructuras de control: if (edad >= 18) { ... }
  3. Corchetes []: Se utilizan para:

    • Definir arrays: let numeros = [1, 2, 3, 4];
    • Acceder a elementos de arrays u objetos: numeros[0] o persona["nombre"]
  4. Punto y coma ;: Delimita el final de una instrucción.

  5. Coma ,: Separa elementos en listas:

    • Parámetros de funciones: function(a, b, c) { ... }
    • Elementos de un array: [1, 2, 3, 4]
    • Propiedades en objetos: {nombre: "Ana", edad: 25}

Anidamiento de bloques

Los bloques de código pueden anidarse dentro de otros bloques, creando una estructura jerárquica:

function evaluarCalificacion(puntuacion) {
    if (puntuacion >= 90) {
        if (puntuacion === 100) {
            console.log("¡Puntuación perfecta!");
        } else {
            console.log("¡Excelente!");
        }
    } else if (puntuacion >= 70) {
        console.log("Buen trabajo");
    } else {
        console.log("Necesitas mejorar");
        
        // Sugiere acciones según la puntuación
        if (puntuacion < 50) {
            console.log("Considera tomar clases adicionales");
        }
    }
}

El anidamiento excesivo puede hacer que el código sea difícil de leer y mantener, así que es una buena práctica intentar mantener una estructura lo más plana posible, sin sacrificar la claridad.

Case sensitivity (sensibilidad a mayúsculas/minúsculas)

Un aspecto fundamental de JavaScript es que es sensible a mayúsculas y minúsculas (case sensitive). Esto significa que JavaScript distingue entre letras mayúsculas y minúsculas en todos los identificadores (nombres de variables, funciones, clases, etc.).

Por ejemplo, estas son variables completamente diferentes:

let nombre = "Juan";
let Nombre = "María";
let NOMBRE = "Carlos";

Lo mismo sucede con funciones, clases, y otros identificadores:

function calcular() { /* ... */ }
function Calcular() { /* ... */ } // Diferente función

const usuario = { nombre: "Ana" };
console.log(usuario.nombre); // Funciona: muestra "Ana"
console.log(usuario.Nombre); // Error: undefined (no existe la propiedad "Nombre")

Errores comunes relacionados con la sensibilidad a mayúsculas/minúsculas

Esta característica de JavaScript puede llevar a errores difíciles de detectar, especialmente para principiantes:

// Declaramos una variable
let edadUsuario = 25;

// Intentamos usarla, pero con una mayúscula diferente
if (edadusuario >= 18) { // ¡Error! La variable edadusuario no existe
    console.log("Mayor de edad");
}

// Otro error común: usar la API del DOM incorrectamente
document.getelementbyid("miElemento"); // Incorrecto
document.getElementById("miElemento"); // Correcto (la "g", "e" e "i" son mayúsculas)

Una buena práctica para evitar estos errores es ser consistente con la nomenclatura que utilizamos (algo que veremos en detalle en otro artículo) y utilizar un editor de código con resaltado de sintaxis y autocompletado.

Estructura de un programa completo

Para ilustrar cómo todos estos conceptos se unen en un programa real, veamos un ejemplo completo de una pequeña aplicación JavaScript:

// Importamos funcionalidades (en entorno de módulos)
import { formatearMoneda } from './utilidades.js';

// Declaración de constantes
const TASA_IVA = 0.21;
const DESCUENTO_VIP = 0.1;

// Declaración de variables globales
let carrito = [];
let cliente = {
    nombre: "Ana García",
    esVip: true,
    direccion: "Calle Principal 123"
};

// Declaración de funciones
function agregarProducto(nombre, precio, cantidad = 1) {
    // Creamos un objeto que representa el producto
    const producto = {
        id: generarId(),
        nombre: nombre,
        precio: precio,
        cantidad: cantidad
    };
    
    // Añadimos el producto al carrito
    carrito.push(producto);
    
    // Actualizamos la interfaz
    actualizarVistaCarrito();
    
    // Devolvemos el producto para posible uso posterior
    return producto;
}

function calcularTotal() {
    // Usamos una función de array para sumar todos los subtotales
    let subtotal = carrito.reduce((acumulado, producto) => {
        return acumulado + (producto.precio * producto.cantidad);
    }, 0);
    
    // Calculamos IVA
    let iva = subtotal * TASA_IVA;
    
    // Aplicamos descuento si el cliente es VIP
    let descuento = 0;
    if (cliente.esVip) {
        descuento = subtotal * DESCUENTO_VIP;
    }
    
    // Calculamos total
    let total = subtotal + iva - descuento;
    
    // Devolvemos objeto con todos los valores
    return {
        subtotal: subtotal,
        iva: iva,
        descuento: descuento,
        total: total
    };
}

function generarId() {
    // Genera un ID único basado en la fecha y un número aleatorio
    return Date.now() + Math.floor(Math.random() * 1000);
}

function actualizarVistaCarrito() {
    // Obtenemos elemento del DOM donde mostraremos el carrito
    const elementoCarrito = document.getElementById("lista-carrito");
    
    // Limpiamos contenido actual
    elementoCarrito.innerHTML = "";
    
    // Añadimos cada producto como un elemento de lista
    carrito.forEach(producto => {
        const elemento = document.createElement("li");
        elemento.textContent = `${producto.nombre} - ${producto.cantidad} x ${formatearMoneda(producto.precio)}`;
        elementoCarrito.appendChild(elemento);
    });
    
    // Actualizamos el total
    const totales = calcularTotal();
    document.getElementById("subtotal").textContent = formatearMoneda(totales.subtotal);
    document.getElementById("iva").textContent = formatearMoneda(totales.iva);
    document.getElementById("descuento").textContent = formatearMoneda(totales.descuento);
    document.getElementById("total").textContent = formatearMoneda(totales.total);
}

// Código de inicialización (se ejecuta al cargar)
function inicializar() {
    // Configuramos manejadores de eventos
    document.getElementById("btn-agregar").addEventListener("click", () => {
        const nombre = document.getElementById("producto-nombre").value;
        const precio = parseFloat(document.getElementById("producto-precio").value);
        const cantidad = parseInt(document.getElementById("producto-cantidad").value);
        
        if (nombre && !isNaN(precio) && !isNaN(cantidad)) {
            agregarProducto(nombre, precio, cantidad);
        } else {
            alert("Por favor, completa todos los campos correctamente");
        }
    });
    
    // Otras inicializaciones...
}

// Cuando el DOM esté listo, inicializamos la aplicación
document.addEventListener("DOMContentLoaded", inicializar);

Este ejemplo muestra las diferentes partes de un programa JavaScript:

  1. Importaciones al principio (si usamos módulos)
  2. Constantes y variables globales para datos compartidos
  3. Funciones que encapsulan bloques de lógica reutilizable
  4. Expresiones e instrucciones dentro de esas funciones
  5. Bloques anidados para control de flujo
  6. Código de inicialización que se ejecuta al cargar la página

La estructura exacta variará según el proyecto, pero este patrón es común en muchas aplicaciones JavaScript.

Buenas prácticas de estructuración

Para terminar, repasemos algunas buenas prácticas para estructurar nuestros programas JavaScript:

1. Organización lógica

  • Agrupa el código relacionado
  • Coloca las importaciones al principio
  • Define constantes y configuraciones globales antes de usarlas
  • Separa la lógica en funciones con propósitos claros

2. Modularización

  • Divide programas grandes en varios archivos (módulos)
  • Cada módulo debe tener una responsabilidad clara
  • Utiliza imports/exports para conectar módulos

3. Manejo del ámbito (scope)

  • Minimiza el uso de variables globales
  • Prefiere el ámbito más reducido posible para tus variables
  • Utiliza bloques para limitar el ámbito cuando sea apropiado

4. Claridad del código

  • Utiliza indentación consistente (2 o 4 espacios por nivel)
  • Añade líneas en blanco para separar secciones lógicas
  • Usa comentarios para explicar el "por qué", no el "qué"
  • Mantén las funciones relativamente pequeñas y con un propósito único

5. Nomenclatura clara

  • Usa nombres descriptivos para variables y funciones
  • Sigue convenciones consistentes (camelCase para variables y funciones, PascalCase para clases)
  • Evita abreviaturas confusas o ambiguas

Resumen

En este artículo hemos explorado los fundamentos de la estructura de un programa JavaScript, desde las instrucciones individuales hasta la organización de un programa completo. Hemos aprendido sobre expresiones e instrucciones, bloques de código y delimitadores, y la importancia de la sensibilidad a mayúsculas y minúsculas.

Una buena estructura es la base de un código mantenible, escalable y libre de errores. A medida que avances en tu aprendizaje de JavaScript, estos conceptos fundamentales te ayudarán a organizar tu código de manera efectiva y a comprender mejor cómo funcionan los programas JavaScript.

En el próximo artículo profundizaremos en los comentarios en JavaScript, una herramienta esencial para documentar nuestro código y hacerlo más comprensible para nosotros mismos y para otros desarrolladores.