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

javascript
// Objeto simple clave:valor
const controller = {
    nombre: "Juan",
    edad: 30
};

console.log(controller.nombre); // "Juan"
console.log(controller.edad);   // 30

2. Objetos que guardan funciones (métodos)

Aquí empieza la magia:

javascript
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!)

javascript
// 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

javascript
// 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

javascript
// 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 EJECUTA

6. 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

javascript
// 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 ())

javascript
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 ())

javascript
// 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):

javascript
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

javascript
// 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 segundo

En tu ejemplo de Express

javascript
// 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ón

Ejemplo práctico para que veas la diferencia

javascript
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ónSintaxisCuándo se ejecuta
Quiero el RESULTADO ahoracontroller.mostrarIndex()Inmediatamente
Quiero REGALAR la funcióncontroller.mostrarIndexCuando el receptor decida



--


El patrón que usas en Express

javascript
// 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 () internamente

Ejercicio para que internalices

javascript
// 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

javascript
// 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

javascript
// 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 pasa

Lo que pasa dentro de app.get (simplificado)

javascript
// 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 completa

Diferencia clave que ahora entiendes

javascript
// 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és

Ejemplo visual con tipos

javascript
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:

javascript
miBoton.addEventListener('click', function() {
    console.log('Clickeado');
});

✅ Correcto - Pasar referencia (equivalente al anterior):

javascript
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 this dentro de la función se comportará igual

❌ Incorrecto - Ejecutar inmediatamente:

javascript
const miFuncion = function() {
    console.log('Clickeado');
};

miBoton.addEventListener('click', miFuncion());  // ← Con () = ERROR LÓGICO

¿Qué pasa aquí?

  1. miFuncion() se ejecuta INMEDIATAMENTE (en el momento de registrar el evento)

  2. Muestra "Clickeado" ahora, no cuando se haga click

  3. La función retorna undefined (porque no tiene return)

  4. addEventListener recibe undefined en lugar de una función

  5. Cuando hagas click, no pasará nada (o dará error)

Pequeña diferencia importante:

Aunque son equivalentes, hay una diferencia sutil pero clave:

javascript
// 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:

javascript
// 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 definidaAl hacer click
miFuncionLa referencia a la funciónAl hacer click
miFuncion()El resultado de ejecutar miFuncionInmediatamente

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

Entradas más populares de este blog

1-valores duplicados en un arreglo

n-funcion - el botón-n