Desarrollo Web

Variables, funciones y scope en JavaScript explicados correctamente

Jairo
6 min de lectura
Variables, funciones y scope en JavaScript explicados correctamente

Antes de empezar: por qué este es el siguiente paso tras HTML y CSS

Tras comprender las bases de HTML y CSS, el paso natural en desarrollo web es dominar variables, funciones y el scope en JavaScript. Las variables permiten guardar y actualizar datos; las funciones encapsulan lógica reutilizable; y el scope define dónde existe cada símbolo en el programa.
Una buena metáfora: el navegador es un pequeño “mundo”; las variables son cajitas con etiquetas, las funciones son recetas y el scope es el mapa que indica dónde se puede usar cada cosa.

Chuleta rápida (sin tablas):

  • Variables → datos (números, texto, arrays, objetos…).
  • Funciones → pasos con nombre que se ejecutan bajo demanda.
  • Scope → quién puede ver cada variable (global, de función, de bloque).

Variables en JavaScript: let, const y por qué evitar var

En código moderno, la elección suele reducirse a let y const:

  • const: para referencias que no se van a reasignar.
  • let: cuando se prevé reasignación del valor.
  • var: desaconsejado por su hoisting y scope de función (no respeta el bloque).

Cuándo usar let y cuándo const (con ejemplos que no fallan y que sí fallan)

Buena práctica: comenzar con const y cambiar a let solo si se necesita reasignar.

// ✅ Reasignación necesaria → let
let contador = 10;
contador = 5; // ok

// ✅ Sin necesidad de reasignar → const
const API_URL = 'https://api.ejemplo.com';
// API_URL = 'https://otra.com'; ❌ Error: no se puede reasignar un const

Ojo con objetos/arrays en const: const bloquea la reasignación de la referencia, pero no impide mutar el contenido.

const lista = [1, 2];
lista.push(3);    // ✅ permitido (mutación)
lista = [1, 2, 3] // ❌ no: reasignación

var: hoisting y scope de función en 2 ejemplos

var se eleva (hoisting) y no respeta el scope de bloque:

// Hoisting: la "declaración" de var sube; el valor no.
console.log(x); // undefined (no error)
var x = 7;

// Bloque ignorado por var:
if (true) {
  var y = 10;
}
console.log(y); // 10 → sale del bloque

Checklist de decisión (sin tablas):

  • ¿Habrá reasignación? → let.
  • ¿No habrá reasignación? → const.
  • ¿Apareció var? → evitar, salvo casos muy específicos y conscientes.

Funciones sin enredos: declaración, expresión y arrow functions

Una función se define con la palabra reservada function, un nombre opcional, una lista de parámetros entre paréntesis y un cuerpo entre llaves {}. También pueden crearse como expresión o mediante arrow functions.

// Declaración con nombre
function saludar(nombre) {
  return `Hola, ${nombre}`;
}

// Expresión asignada a una variable
const despedir = function(nombre) {
  return `Chao, ${nombre}`;
};

// Arrow function (sintaxis breve y this léxico)
const doble = n => n * 2;

Parámetros, retorno y buenas prácticas al nombrar

  • Usar verbos claros: calcularTotal, obtenerUsuario.
  • Preferir parámetros explícitos sobre dependencias globales.
  • Si una función crece demasiado, dividirla en funciones más pequeñas.
function calcularTotal(items, tasa) {
  const subtotal = items.reduce((s, it) => s + it.precio, 0);
  return subtotal * (1 + tasa);
}

Hoisting al llamar funciones: qué pasa bajo el capó

Las declaraciones de función se elevan completas:

console.log(square(3)); // 9
function square(n) { return n * n; }

En cambio, expresiones y arrows se elevan como variables (let/const): no pueden invocarse antes de su definición.

Scope explicado en serio: global, de función y de bloque

Existen tres niveles clave: global, de función y de bloque (llaves {} con let/const).

const global = '🌍';

function demo() {
  const interno = '🔒 función';
  if (true) {
    const bloque = '🧱 bloque';
    console.log(global);  // ok
    console.log(interno); // ok
    console.log(bloque);  // ok
  }
  // console.log(bloque); // ❌ fuera del bloque
}

demo();
// console.log(interno); // ❌ fuera de la función

TDZ: por qué “Cannot access before initialization”

Con let y const existe la Temporal Dead Zone (TDZ): desde que se entra al scope hasta la línea de declaración, la variable no está disponible.

// TDZ en acción
// console.log(a); // ❌ ReferenceError
let a = 1;

Closures en 3 líneas: qué son y cuándo aparecen

Un closure ocurre cuando una función recuerda el entorno donde se creó.

function crearSumador(x) {
  return function(y) { return x + y; };
}
const sumar10 = crearSumador(10);
sumar10(5); // 15

Este patrón es base para contadores, encapsulación de estado y módulos simples.

Errores comunes y cómo arreglarlos rápido

  • Reasignar const → usar let o evitar la reasignación.
  • Confundir bloque con función → let/const respetan bloque; var no.
  • Invocar funciones no elevadas → definir antes o usar declaración de función.
  • Variables globales involuntarias → declarar siempre con let/const.
  • TDZ → declarar antes de usar; no acceder a let/const antes de su línea.

Nota práctica: cuando “algo no existe”, conviene revisar en qué scope se está y si la variable ya fue declarada en ese punto.

Snippets listos para copiar y pegar (consola y archivos)

Reasignación segura con let:

let nivel = 1;
nivel++;        // 2
console.log(nivel);

Evitar globales accidentales:

'use strict';
const boton = document.querySelector('#go');
// Declarar siempre con let/const para no crear globales sin querer

Declaración vs expresión vs arrow:

function area(r) { return Math.PI * r * r; }
const perimetro = function(r) { return 2 * Math.PI * r; };
const diametro = r => 2 * r;

TDZ mini-demo:

// console.log(msg); // ❌ ReferenceError (TDZ)
const msg = 'Listo';
console.log(msg);    // ✅

Mini-proyecto: botón contador (variables, funciones, scope y closure)

Ejercicio que reúne variable, función, closure y eventos.

HTML mínimo:

<button id="btn">Clicks: 0</button>

JS (al final del body o con defer):

function crearContador() {
  let count = 0; // scope cerrado por el closure
  return function incrementar() {
    count++;
    return count;
  };
}

const incrementar = crearContador();
const btn = document.getElementById('btn');

btn.addEventListener('click', () => {
  const n = incrementar();
  btn.textContent = `Clicks: ${n}`;
});

Qué se refuerza (checklist):

  • let para valores que cambian (count).
  • Función que retorna función → closure.
  • Scope: count vive dentro de crearContador, pero la función interna lo conserva.

FAQs rápidas sobre variables, funciones y scope

¿var está “prohibido”?
No, pero en la práctica actual casi nunca es necesario; let y const ofrecen reglas más claras.

¿const impide mutar un objeto?
No. Impide reasignar la variable; el objeto interno puede mutar si el diseño lo admite.

¿Por qué aparece “Cannot access before initialization”?
Por la TDZ: se está intentando usar let/const antes de la línea de declaración.

¿Las arrow functions cambian this?
Sí: capturan el this léxico; conviene cuando se necesita ese comportamiento.

Conclusión

Dominar let/const, elegir correctamente el tipo de función y comprender el scope (global, función, bloque) previene una gran cantidad de errores. Con la chuleta de decisiones, los snippets y el mini-proyecto, se obtiene una base práctica y sólida para seguir avanzando con JavaScript.


JavaScript

Jairo

Comentarios (0)

No hay comentarios aún. ¡Sé el primero en comentar!

Envíame un comentario

🍪 Utilizamos cookies para mejorar tu experiencia de navegación, analizar el tráfico del sitio y personalizar el contenido. Al continuar navegando, aceptas nuestro uso de cookies. Más información