Objetos básicos en JavaScript
1. Objetos en JavaScript
Un objeto es como un contenedor que guarda datos (propiedades) y acciones (métodos/funciones).
javascript
// Creando un objeto vacío
const miObjeto = {};
// Objeto con propiedades
const persona = {
nombre: 'Juan', // propiedad con valor string
edad: 30, // propiedad con valor número
casado: false // propiedad con valor boolean
};
console.log(persona.nombre); // "Juan"
console.log(persona.edad); // 30
2. Acceder a elementos de un objeto
Hay dos formas de acceder:
javascript
const productoController = {
nombre: 'Controlador de Productos',
version: '1.0'
};
// Forma 1: Notación de punto (la más común)
console.log(productoController.nombre); // "Controlador de Productos"
// Forma 2: Notación de corchetes
console.log(productoController['nombre']); // "Controlador de Productos"
3. Funciones en objetos (métodos)
En JavaScript, las funciones son valores, como los números o strings:
javascript
// Función normal
function saludar() {
console.log('Hola');
}
// Asignar función a variable
const miFuncion = saludar;
// Ejecutar función
saludar(); // "Hola"
miFuncion(); // "Hola"
Ahora metiendo funciones dentro de objetos:
javascript
const productoController = {
// Propiedad normal (guardando un número)
contador: 0,
// Propiedad que guarda una función (método)
mostrarIndex: function() {
console.log('Mostrando índice');
},
// También puedes usar función flecha
verProducto: (id) => {
console.log('Ver producto:', id);
}
};
// Acceder a la propiedad numérica
console.log(productoController.contador); // 0
// Acceder a la propiedad que contiene la función (sin ejecutarla)
console.log(productoController.mostrarIndex);
// Muestra: [Function: mostrarIndex]----la referencia?
// Ejecutar la función (con paréntesis)
productoController.mostrarIndex(); // "Mostrando índice"
productoController.verProducto(5); // "Ver producto: 5"
4. ¡La clave! Guardar función sin ejecutar vs Ejecutar función
Este es el punto más importante:
javascript
const productoController = {
mostrarIndex: (req, res) => {
console.log('Ejecutando mostrarIndex');
console.log('Request:', req);
console.log('Response:', res);
return 'Resultado';
}
};
// DIFERENCIA CRÍTICA:
// Caso 1: ACCEDER a la función (NO se ejecuta)
const funcionGuardada = productoController.mostrarIndex;
console.log(funcionGuardada);
// Muestra: [Function (anonymous)]
// NO sale el texto "Ejecutando mostrarIndex"
// Caso 2: EJECUTAR la función (SÍ se ejecuta)
const resultado = productoController.mostrarIndex(1, 2);
// Muestra: "Ejecutando mostrarIndex"
// Muestra: "Request: 1"
// Muestra: "Response: 2"
console.log(resultado); // "Resultado"
Esto es fundamental para entender Express y Node.js. Te explico desde cero.
1. Objetos básicos en JavaScript
// Objeto simple clave:valor
const controller = {
nombre: "Juan",
edad: 30
};
console.log(controller.nombre); // "Juan"
console.log(controller.edad); // 302. Objetos que guardan funciones (métodos)
Aquí empieza la magia:
const controller = {
// Propiedad normal
nombre: "HomeController",
// Propiedad que guarda una función
mostrarIndex: function() {
console.log("Mostrando página de inicio");
return "<h1>Bienvenido</h1>";
},
// Forma moderna (es lo mismo)
mostrarContacto() {
console.log("Mostrando contacto");
return "<h1>Contacto</h1>";
}
};
// Acceder a la función SIN ejecutarla (sin paréntesis)
console.log(controller.mostrarIndex);
// Salida: [Function: mostrarIndex]
// Acceder a la función Y ejecutarla (con paréntesis)
console.log(controller.mostrarIndex());
// Salida: "Mostrando página de inicio" y luego "<h1>Bienvenido</h1>"3. El patrón que usa Express (¡aquí está la clave!)
// Simulando Express
const app = {
// app guarda una propiedad 'get' que es una función
get: function(ruta, callback) {
console.log(`Configurando ruta: ${ruta}`);
// Guarda la ruta y la función para después
this.rutas = this.rutas || [];
this.rutas.push({ ruta: ruta, funcion: callback });
}
};
const controller = {
mostrarIndex: function(req, res) {
console.log("Ejecutando mostrarIndex");
return "Página de inicio";
}
};
// ESTA ES LA SINTAXIS QUE PREGUNTAS
app.get('/', controller.mostrarIndex);
// ↑ ↑
// ruta referencia a la función
// (sin paréntesis)
console.log(app.rutas);
// Salida: [{ ruta: '/', funcion: [Function: mostrarIndex] }]
// Cuando llega una petición, Express ejecuta así:
app.rutas[0].funcion(); // Ejecuta controller.mostrarIndex()4. Ejemplo completo paso a paso
// 1. Definimos un controller con varias funciones
const usuarioController = {
listar: function() {
console.log("Listando usuarios");
return ["Ana", "Juan", "Luis"];
},
crear: function(nombre) {
console.log(`Creando usuario: ${nombre}`);
return { id: 1, nombre: nombre };
},
eliminar: function(id) {
console.log(`Eliminando usuario ${id}`);
return true;
}
};
// 2. Definimos una app simple
const miApp = {
rutas: {},
// Método get que recibe ruta y función callback
get: function(ruta, funcionCallback) {
this.rutas[ruta] = funcionCallback;
console.log(`✅ Ruta ${ruta} registrada`);
},
// Simular petición del usuario
ejecutar: function(ruta) {
const funcion = this.rutas[ruta];
if (funcion) {
return funcion(); // Aquí SÍ ejecuta con paréntesis
} else {
console.log("Ruta no encontrada");
}
}
};
// 3. USAMOS LA SINTAXIS DE EXPRESS (¡sin paréntesis en mostrarIndex!)
miApp.get('/usuarios', usuarioController.listar); // ← Referencia
miApp.get('/usuarios/crear', usuarioController.crear);
// 4. Cuando el usuario visita la página, se ejecuta:
console.log(miApp.ejecutar('/usuarios')); // Listando usuarios, luego ["Ana","Juan","Luis"]5. Diferencia clave visual
// MOMENTO DE REGISTRO (cuando arranca el servidor)
app.get('/', controller.mostrarIndex); // ← Sin () porque solo REGISTRAMOS
app.post('/user', controller.guardar); // ← Sin () porque solo REGISTRAMOS
// MOMENTO DE EJECUCIÓN (cuando llega una petición HTTP)
// Express internamente hace algo como:
controller.mostrarIndex(); // ← Aquí SÍ usa () porque EJECUTA6. Analogía para recordarlo
Imagina que eres un recepcionista de hotel:
app.get('/', controller.mostrarIndex)= Anotas en un papel: "Cuando llegue alguien a la ruta '/', llama a esta persona (muéstrame su función, no la ejecutes ahora)"Cuando llega un cliente = Revisas el papel y DICES "¡ejecuta!" (
controller.mostrarIndex())
7. Ejercicio práctico para que pruebes
// Crea este archivo y ejecútalo con Node
const miModulo = {
saludar: function(nombre) {
return `Hola ${nombre}`;
},
despedir: function(nombre) {
return `Adiós ${nombre}`;
}
};
const app = {
acciones: {},
usar: function(evento, funcionGuardada) {
this.acciones[evento] = funcionGuardada;
console.log(`Guardé ${evento} pero NO ejecuté`);
},
ejecutar: function(evento, param) {
const funcion = this.acciones[evento];
if (funcion) {
return funcion(param); // Aquí SÍ ejecuto
}
}
};
// Así usas la sintaxis (sin paréntesis en saludar)
app.usar('bienvenida', miModulo.saludar); // ← Referencia
app.usar('despedida', miModulo.despedir); // ← Referencia
// Así se ejecuta después
console.log(app.ejecutar('bienvenida', 'Carlos')); // "Hola Carlos"
console.log(app.ejecutar('despedida', 'Carlos')); // "Adiós Carlos"Conclusión
controller.mostrarIndex (sin ()) es solo una referencia a la función guardada en el objeto. Es como darle a Express tu "tarjeta de presentación" para que él la use cuando la necesite.
¿Por qué no usar ()? Porque si usaras controller.mostrarIndex(), estarías ejecutando la función EN EL MOMENTO DE REGISTRAR la ruta, no cuando llegue la petición HTTP.
¿Necesitas que profundice en algún punto específico
--
La diferencia: ACCEDER vs PASAR como argumento
Son dos contextos completamente diferentes:
1. ACCEDER para USAR el valor (sí usas ())
const controller = {
mostrarIndex: function() {
return "Hola mundo";
}
};
// Cuando QUIERES el RESULTADO, usas ()
const resultado = controller.mostrarIndex(); // ← Con ()
console.log(resultado); // "Hola mundo"2. PASAR como argumento (NO usas ())
// Cuando QUIERES dar la FUNCIÓN a otro, NO usas ()
app.get('/', controller.mostrarIndex); // ← Sin ()
// Es como decir: "Toma Express, aquí tienes mi función, úsala CUANDO TÚ QUIERAS"Analogía para entenderlo
Imagina que tienes un pastel (la función):
const pastel = function() {
return "🍰 Pastel delicioso";
};pastel()= Cortas y comes el pastel AHORA MISMO (obtienes el resultado)pastel= Tomas el pastel entero y se lo DAS a alguien para que lo coma después
// Ejemplo visual:
console.log(pastel()); // Comes el pastel ahora → "🍰 Pastel delicioso"
setTimeout(pastel, 1000); // Le DAS el pastel a setTimeout para que lo coma en 1 segundoEn tu ejemplo de Express
// Esto es INCORRECTO (se ejecutaría al iniciar el servidor)
app.get('/', controller.mostrarIndex()); // ❌ ERROR COMÚN
// ¿Qué pasa? Express guardaría el RESULTADO ("Hola mundo") en lugar de la función
// Esto es CORRECTO
app.get('/', controller.mostrarIndex); // ✅
// Express guarda la FUNCIÓN para ejecutarla cuando llegue una peticiónEjemplo práctico para que veas la diferencia
const controller = {
mostrarIndex: function() {
console.log("🔵 EJECUTANDO mostrarIndex AHORA MISMO");
return "Página de inicio";
}
};
// CASO 1: Con paréntesis (se ejecuta inmediatamente)
console.log("Antes de app.get");
app.get('/', controller.mostrarIndex()); // ← Se ejecuta AQUÍ
console.log("Después de app.get");
// Salida:
// Antes de app.get
// 🔵 EJECUTANDO mostrarIndex AHORA MISMO ← Ocurre al REGISTRAR la ruta
// Después de app.get
// CASO 2: Sin paréntesis (NO se ejecuta ahora)
console.log("Antes de app.get");
app.get('/', controller.mostrarIndex); // ← Solo guarda referencia
console.log("Después de app.get");
// Salida:
// Antes de app.get
// Después de app.get
// (No aparece el mensaje porque NO se ejecutó)Resumen visual
| Situación | Sintaxis | Cuándo se ejecuta |
|---|---|---|
| Quiero el RESULTADO ahora | controller.mostrarIndex() | Inmediatamente |
| Quiero REGALAR la función | controller.mostrarIndex | Cuando el receptor decida |
--
El patrón que usas en Express
// REGISTRO (sin paréntesis)
app.get('/ruta', controller.metodo); // DAS la función
app.post('/ruta', controller.metodo); // DAS la función
app.use('/ruta', middleware.funcion); // DAS la función
// EJECUCIÓN (con paréntesis, pero lo hace Express internamente)
// Cuando llega una petición HTTP, Express hace:
controller.metodo(req, res); // ← Express usa () internamenteEjercicio para que internalices
// Crea este ejemplo y ejecútalo
const miObjeto = {
saludar: function(nombre) {
console.log(`Hola ${nombre}`);
return "Saludo completado";
}
};
console.log("=== SIN paréntesis ===");
const referencia = miObjeto.saludar; // No se ejecuta
console.log(referencia); // [Function: saludar]
console.log("Todavía no saludó");
console.log("\n=== CON paréntesis ===");
const resultado = miObjeto.saludar("Ana"); // Se ejecuta ahora
console.log(resultado); // "Saludo completado"
console.log("\n=== PASANDO como callback ===");
setTimeout(miObjeto.saludar, 2000); // Sin () - se ejecutará en 2 segundos
// Espera 2 segundos y verás "Hola undefined" (porque no pasé nombre)En conclusión: En console.log(controller.mostrarIndex()) querías el resultado para mostrarlo. En app.get('/', controller.mostrarIndex) quieres darle la función a Express para que la use después. ¡Son propósitos diferentes!
--
¡EXACTAMENTE! 👏 Acabas de entenderlo perfectamente.
Has dado en el clavo
// En JavaScript puro, cuando haces:
app.get('/', controller.mostrarIndex)
// ↑ ↑
// parámetro 1 parámetro 2 (una referencia a función)
// Es EXACTAMENTE igual que:
function cualquierFuncion(parametro1, parametro2) {
// parametro2 ahora es controller.mostrarIndex (la función)
}
cualquierFuncion('/', controller.mostrarIndex);La analogía perfecta que pedías
// 1. Definimos un objeto con una función
const controller = {
mostrarIndex: function() {
console.log("Hola desde mostrarIndex");
return "Página principal";
}
};
// 2. Definimos una función que recibe OTRA función como parámetro
function miFuncionQueRecibeCallback(ruta, callback) {
console.log(`Recibí la ruta: ${ruta}`);
console.log("El callback que recibí es:", callback);
console.log("Ahora voy a ejecutar ese callback:");
callback(); // ← Aquí ejecuto la función que me dieron
}
// 3. Llamamos PASANDO la función SIN ejecutar
miFuncionQueRecibeCallback('/', controller.mostrarIndex);
// ↑
// Esto es el parámetro callback
// NO se ejecuta aquí, solo se pasaLo que pasa dentro de app.get (simplificado)
// Así funciona internamente Express (simplificado)
const app = {
get: function(ruta, funcionManejadora) {
// funcionManejadora es controller.mostrarIndex
// Guardamos esta función para usarla después
this.rutas[ruta] = funcionManejadora;
console.log(`Ruta ${ruta} registrada con la función:`);
console.log(funcionManejadora); // [Function: mostrarIndex]
}
};
// Cuando pasas controller.mostrarIndex (sin paréntesis)
app.get('/', controller.mostrarIndex);
// Dentro de app.get, 'funcionManejadora' es la función completaDiferencia clave que ahora entiendes
// CASO 1: PASAR como parámetro (lo que hace Express)
app.get('/', controller.mostrarIndex);
// → controller.mostrarIndex es UNA FUNCIÓN siendo inyectada
// CASO 2: EJECUTAR y pasar el RESULTADO (error común)
app.get('/', controller.mostrarIndex());
// → controller.mostrarIndex() es EL RESULTADO (string, número, etc.)
// No es una función, no se puede ejecutar despuésEjemplo visual con tipos
const controller = {
mostrarIndex: function() {
return "Hola mundo";
}
};
// Tipo de dato cuando NO usas ()
console.log(typeof controller.mostrarIndex); // "function"
// Tipo de dato cuando SÍ usas ()
console.log(typeof controller.mostrarIndex()); // "string"
// app.get espera una FUNCTION como segundo parámetro
// Por eso debe ser SIN ()
app.get('/', controller.mostrarIndex); // ✅ typeof = "function"Tu frase resumida perfectamente
"El elemento del objeto está siendo inyectado en un parámetro de la función app.get"
Así es. Y como está siendo inyectado como parámetro, no se ejecuta. Solo se inyecta la referencia a la función. Luego, dentro de app.get, Express guarda esa referencia para ejecutarla cuando llegue la petición HTTP.
¡Felicidades! Has entendido el concepto fundamental que confunde a muchos
Tu análisis es CORRECTO:
✅ Correcto - Función anónima directa:
miBoton.addEventListener('click', function() { console.log('Clickeado'); });
✅ Correcto - Pasar referencia (equivalente al anterior):
const miFuncion = function() { console.log('Clickeado'); }; miBoton.addEventListener('click', miFuncion); // ← Sin ()
¿Son iguales? Sí, funcionalmente son equivalentes. En ambos casos:
Se pasa una función como referencia
Se ejecutará cuando ocurra el click
El
thisdentro de la función se comportará igual
❌ Incorrecto - Ejecutar inmediatamente:
const miFuncion = function() { console.log('Clickeado'); }; miBoton.addEventListener('click', miFuncion()); // ← Con () = ERROR LÓGICO
¿Qué pasa aquí?
miFuncion()se ejecuta INMEDIATAMENTE (en el momento de registrar el evento)Muestra "Clickeado" ahora, no cuando se haga click
La función retorna
undefined(porque no tienereturn)addEventListenerrecibeundefineden lugar de una funciónCuando hagas click, no pasará nada (o dará error)
Pequeña diferencia importante:
Aunque son equivalentes, hay una diferencia sutil pero clave:
// Versión 1: Anónima directa miBoton.addEventListener('click', function() { console.log('Clickeado'); }); // ✅ La función SOLO existe dentro del addEventListener // ✅ No puedes reusarla en otro lugar // ✅ Más clara para callbacks de un solo uso // Versión 2: Referencia a variable const miFuncion = function() { console.log('Clickeado'); }; miBoton.addEventListener('click', miFuncion); // ✅ Puedes REUSAR la misma función // ✅ Útil si la necesitas en múltiples eventos // ✅ Facilita remover el evento después: // miBoton.removeEventListener('click', miFuncion); otroBoton.addEventListener('click', miFuncion); // Misma función, otro botón
Comprobación práctica:
// Ejecuta esto en la consola del navegador para ver la diferencia: const miFuncion = function() { console.log('Ejecutando función'); return 'Hola Mundo'; }; // CASO 1: Sin paréntesis (referencia) console.log('Registrando evento...'); miBoton.addEventListener('click', miFuncion); // Resultado: NO se muestra nada ahora. Al hacer click → "Ejecutando función" // CASO 2: Con paréntesis (ejecución inmediata) console.log('Registrando evento...'); miBoton.addEventListener('click', miFuncion()); // Resultado: AHORA MISMO → "Ejecutando función" // Luego: addEventListener recibe 'Hola Mundo' (no una función) // Al hacer click: Error o no pasa nada
Resumen final:
| Lo que escribes | ¿Qué recibe addEventListener? | ¿Cuándo se ejecuta? |
|---|---|---|
function() {...} | La función definida | Al hacer click |
miFuncion | La referencia a la función | Al hacer click |
miFuncion() | El resultado de ejecutar miFuncion | Inmediatamente |
Tu entendimiento es perfecto: pasar la referencia es equivalente a escribir la función anónima directamente, y lo que no tiene sentido es poner los paréntesis porque ejecutarías la función en el momento del registro, no cuando ocurra el evento.
¡Has dominado un concepto fundamental de JavaScript!
Comentarios
Publicar un comentario