Ir al contenido principal

Creación de objetos

Introducción

Los objetos son uno de los conceptos fundamentales de JavaScript y representan una de las estructuras de datos más versátiles y potentes del lenguaje. A diferencia de los tipos de datos primitivos (como números o cadenas de texto), los objetos nos permiten agrupar datos relacionados junto con funcionalidades asociadas en una única entidad. En el mundo real podemos pensar en un objeto como una entidad con características (propiedades) y comportamientos (métodos), y JavaScript nos permite modelar este paradigma de manera efectiva.

En este artículo exploraremos las diferentes formas de crear objetos en JavaScript, desde la sintaxis más simple hasta técnicas más avanzadas. Comprender correctamente la creación de objetos es esencial, ya que gran parte del desarrollo web moderno se basa en esta estructura fundamental.

Concepto de objetos en JavaScript

Un objeto en JavaScript es una colección de pares clave-valor, donde cada clave (también llamada propiedad) está asociada a un valor. Estos valores pueden ser de cualquier tipo: números, cadenas de texto, booleanos, funciones, e incluso otros objetos.

Antes de adentrarnos en los métodos de creación, es importante entender que JavaScript es un lenguaje basado en prototipos, no en clases (aunque las clases se introdujeron en ES6 como azúcar sintáctico). Esto significa que los objetos pueden heredar directamente de otros objetos, lo que influye en cómo se crean y estructuran.

Sintaxis literal de objetos

La forma más común y directa de crear un objeto en JavaScript es utilizando la sintaxis literal, que consiste en definir las propiedades y métodos del objeto entre llaves {}.

// Sintaxis literal de objeto
const persona = {
    nombre: "Laura",
    edad: 28,
    profesion: "Desarrolladora",
    saludar: function() {
        return "Hola, me llamo " + this.nombre;
    }
};

console.log(persona.nombre); // Muestra: Laura
console.log(persona.saludar()); // Muestra: Hola, me llamo Laura

Esta sintaxis es concisa y legible, lo que la convierte en la opción preferida en la mayoría de los casos. Algunos aspectos a destacar:

  • Las propiedades se definen como pares clave: valor
  • Las claves pueden ir sin comillas si son identificadores válidos
  • Los valores pueden ser de cualquier tipo, incluyendo funciones
  • Cada par se separa del siguiente mediante una coma

Sintaxis literal abreviada (ES6+)

Con ECMAScript 2015 (ES6), se introdujeron mejoras en la sintaxis literal:

// Abreviación de propiedades
const nombre = "Carlos";
const edad = 32;

const usuario = {
    nombre, // Equivale a nombre: nombre
    edad,   // Equivale a edad: edad
    
    // Métodos abreviados (sin palabra "function")
    saludar() {
        return `Hola, soy ${this.nombre}`;
    }
};

console.log(usuario.saludar()); // Muestra: Hola, soy Carlos

Constructor Object()

Otra forma de crear objetos es utilizar el constructor Object(). Aunque es menos común que la sintaxis literal, es importante conocerlo:

// Usando el constructor Object
const coche = new Object();
coche.marca = "Seat";
coche.modelo = "Ibiza";
coche.año = 2020;
coche.arrancar = function() {
    return `El ${this.marca} ${this.modelo} está arrancando`;
};

console.log(coche.arrancar()); // Muestra: El Seat Ibiza está arrancando

Este enfoque crea primero un objeto vacío y luego añade propiedades y métodos uno a uno. Es más verboso y generalmente menos eficiente que la sintaxis literal, pero puede ser útil en situaciones donde necesitamos construir un objeto de forma dinámica.

Patrones de creación de objetos

Constructor personalizado (función constructora)

Antes de ES6, la forma estándar de crear múltiples objetos con la misma estructura era utilizar funciones constructoras:

// Función constructora
function Producto(nombre, precio) {
    this.nombre = nombre;
    this.precio = precio;
    this.conIVA = function() {
        return this.precio * 1.21;
    };
}

const producto1 = new Producto("Monitor", 200);
const producto2 = new Producto("Teclado", 50);

console.log(producto1.nombre); // Muestra: Monitor
console.log(producto2.conIVA()); // Muestra: 60.5 (50 * 1.21)

Puntos importantes:

  • Por convención, las funciones constructoras comienzan con mayúscula
  • La palabra clave this se refiere al nuevo objeto que se está creando
  • Se utiliza new para invocar la función como constructor
  • Cada instancia recibe su propia copia de las propiedades y métodos

Un problema con este enfoque es que cada instancia recibe su propia copia de los métodos, lo que puede ser ineficiente en memoria. Tradicionalmente, esto se resolvía usando el prototipo:

function Empleado(nombre, puesto) {
    this.nombre = nombre;
    this.puesto = puesto;
}

// Añadir método al prototipo en lugar de a cada instancia
Empleado.prototype.presentarse = function() {
    return `Hola, soy ${this.nombre} y trabajo como ${this.puesto}`;
};

const empleado1 = new Empleado("Ana", "Diseñadora");
console.log(empleado1.presentarse()); // Muestra: Hola, soy Ana y trabajo como Diseñadora

Clases (ES6+)

Con ES6, JavaScript introdujo la sintaxis de clases, que es una forma más clara y elegante de implementar el patrón de constructor y prototipo:

// Clase ES6
class Vehiculo {
    constructor(marca, modelo) {
        this.marca = marca;
        this.modelo = modelo;
        this.encendido = false;
    }
    
    arrancar() {
        this.encendido = true;
        return `El ${this.marca} ${this.modelo} está arrancando`;
    }
    
    apagar() {
        this.encendido = false;
        return `El ${this.marca} ${this.modelo} se ha apagado`;
    }
}

const miCoche = new Vehiculo("Renault", "Clio");
console.log(miCoche.arrancar()); // Muestra: El Renault Clio está arrancando

Las clases son en realidad "azúcar sintáctico" sobre el sistema de prototipos existente en JavaScript, pero proporcionan una sintaxis más clara y familiar para programadores que vienen de otros lenguajes.

Object.create()

El método Object.create() proporciona una forma diferente de crear objetos que permite establecer explícitamente el prototipo del nuevo objeto:

// Objeto que servirá como prototipo
const personaPrototipo = {
    saludar() {
        return `Hola, me llamo ${this.nombre}`;
    },
    despedirse() {
        return `Adiós, hasta pronto`;
    }
};

// Crear nuevo objeto con personaPrototipo como prototipo
const estudiante = Object.create(personaPrototipo);
estudiante.nombre = "Miguel";
estudiante.curso = "JavaScript Avanzado";

console.log(estudiante.saludar()); // Muestra: Hola, me llamo Miguel
console.log(estudiante.curso); // Muestra: JavaScript Avanzado

Object.create() es particularmente útil cuando queremos implementar herencia prototípica de manera explícita o cuando queremos crear objetos sin ejecutar un constructor.

También podemos definir propiedades durante la creación:

const cliente = Object.create(Object.prototype, {
    nombre: {
        value: "Laura",
        writable: true,
        enumerable: true,
        configurable: true
    },
    saldo: {
        value: 1000,
        writable: true,
        enumerable: true,
        configurable: true
    }
});

console.log(cliente.nombre); // Muestra: Laura

Este segundo parámetro nos permite definir detalladamente las características de cada propiedad, como si se puede modificar (writable), si aparece en enumeraciones (enumerable), o si se puede eliminar (configurable).

Propiedades computadas

ES6 introdujo las propiedades computadas, que permiten utilizar expresiones para definir las propiedades de un objeto:

const prefijo = "app";
const contador = 1;

const configuracion = {
    [`${prefijo}_id`]: 12345,
    [`elemento_${contador}`]: "primer elemento",
    ["metodo" + contador]: function() {
        return "Ejecutando método computado";
    }
};

console.log(configuracion.app_id); // Muestra: 12345
console.log(configuracion.elemento_1); // Muestra: primer elemento
console.log(configuracion.metodo1()); // Muestra: Ejecutando método computado

Las propiedades computadas son útiles cuando necesitamos crear nombres de propiedades dinámicamente, por ejemplo, al consumir datos de una API o generar objetos con estructuras variables.

Características de los objetos

Mutabilidad

A diferencia de los tipos primitivos, los objetos en JavaScript son mutables, lo que significa que podemos cambiar sus propiedades después de la creación:

const telefono = {
    marca: "Samsung",
    modelo: "Galaxy"
};

telefono.modelo = "Galaxy S21";
telefono.color = "Negro"; // Añadir nueva propiedad

console.log(telefono); // Muestra: { marca: 'Samsung', modelo: 'Galaxy S21', color: 'Negro' }

Observa que aunque el objeto se declara con const, sus propiedades pueden modificarse. Lo que const impide es reasignar la variable a otro objeto o valor.

Comparación de objetos

Los objetos se comparan por referencia, no por contenido:

const obj1 = { valor: 10 };
const obj2 = { valor: 10 };
const obj3 = obj1;

console.log(obj1 === obj2); // Muestra: false (diferentes referencias)
console.log(obj1 === obj3); // Muestra: true (misma referencia)

Incluso si dos objetos tienen exactamente las mismas propiedades y valores, se consideran diferentes si son instancias separadas.

Resumen

Hemos explorado las principales formas de crear objetos en JavaScript, desde la sintaxis literal de objetos, que es la más común y directa, hasta métodos más específicos como Object.create() o las clases ES6. Cada enfoque tiene sus propios casos de uso y ventajas.

Los objetos son fundamentales en JavaScript y constituyen la base de muchos patrones de programación y frameworks modernos. En los próximos artículos profundizaremos en cómo trabajar con propiedades y métodos de objetos, acceder a ellos eficientemente y explorar conceptos avanzados como getters, setters y descriptores de propiedades.