T5.6 Objetos
Objetos¶
En JS los objetos se crean a partir de prototipos... aunque desde ECMAScript 5 también podemos crearlos a partir de clases.
En realidad tenemos 6 métodos para crear objetos. Comencemos por los prototipos:
1. Declaración literal¶
A partir de una declaración literal del objeto:
const personaLiteral = {
nombre: "Juan",
apellidos: ["Fernández", "González"],
anhoNacimiento: 1950,
getEdad: function (){ return 2025-this.anhoNacimiento; }
};
console.log(personaLiteral);
// Acceso por propiedad o método (con el punto)
console.log(personaLiteral.nombre + " tiene " + personaLiteral.getEdad() + " años.");
// Acceso a propiedad como un "array"
console.log(`Primer apellido ${personaLiteral['apellidos'][0]}`);
personaLiteral.apellidos[2] = "Juanjo";
console.log("Nombre: ", personaLiteral['apellidos'] );
2. A partir de un prototipo¶
Añadiendo propiedes y métodos a un objeto vacío, u otro objeto:
const cocheVacio = {};
console.log(cocheVacio);
cocheVacio.nombre = "Opel";
console.log(cocheVacio);
cocheVacio.acelerar = function (velocidad) { this.velocidad += velocidad; };
cocheVacio.getVelocidad = function () { return this.velocidad; };
console.log(cocheVacio);
try {
console.log(cocheVacio.getVelocidad());
} catch (e) {
console.error(e);
}
cocheVacio.detener = function () { this.velocidad = 0; };
console.log(cocheVacio);
cocheVacio.acelerar(100);
console.log(`Después de acelerar 100 = ${cocheVacio.getVelocidad()}`);
cocheVacio.detener();
console.log(`Después de detener el vehículo = ${cocheVacio.getVelocidad()}`);
cocheVacio.acelerar(50);
console.log(`Después de volver a acelerar = ${cocheVacio.getVelocidad()}`);
// Sin privacidad
console.log(cocheVacio.velocidad);
// O añadiendo a persona
personaLiteral.altura = 175;
console.log(personaLiteral);
Importante: cuidado que los objetos se asignan con referencias (como en Java), por lo que podemos meter la pata con facilidad
// 1. Creamos un objeto
const usuario = {
nombre: "John Doe",
edad: 14,
verificado: false
};
// 2. Lo "copiamos"
const nuevoUsuario = usuario;
console.log(nuevoUsuario); // {nombre: 'John Doe', edad: 14, verificado: false}
// 3. Modificamos el nuevo
nuevoUsuario.nombre = "Jane Doe";
console.log(nuevoUsuario); // {nombre: 'Jane Doe', edad: 14, verificado: false}
// 4. Verificamos el original
console.log(usuario); // {nombre: 'Jane Doe', edad: 14, verificado: false}
Veamos entonces como clonarlo correctamente:
// Creando un objeto a partir de otro
let clon = Object.create(usuario);
clon.nombre = "cero"
console.log(clon, usuario);
// Usando el Operador de Propagación (Spread Operator)
let clon1 = { ...usuario };
clon1.nombre = "uno";
console.log(clon1, usuario);
// Usando Object.assign()
let clon2 = Object.assign({}, usuario);
clon2.nombre = "dos";
console.log(clon2, usuario);
// Usando JSON.parse()
let clon3 = JSON.parse(JSON.stringify(usuario))
clon3.nombre = "tres";
console.log(clon3, usuario);
También podemos añadir funciones:
clon1.saluda = () => console.log('Hola mundo');
clon1.saluda();
Nota: Ésto añade la declaración de la función al objeto.
3. new Object()¶
Con el constructor new Object():
const otroVacio = new Object();
otroVacio.nombre = "Vacio";
console.log(otroVacio);
Nota: es raro. No se adapta al formato clásico de JS ni al de otros lenguajes como Java por lo que es raro verlo (nadie está cómodo con este formato). Mejor no usar.
4. Función constructora¶
function Persona(nombre, edad, idiomas) {
this.nombre = nombre; // Asignar propiedades
this.edad = edad;
this.idiomas = idiomas;
// Método
/* Esto genera una función en cada objeto (lo del punto 2)
this.saludar = function() {
console.log(`Hola, soy ${this.nombre} y tengo ${this.edad} años.`);
};*/
}
// Ésto genera una función en el prototipo de la clase
Persona.prototype.saludar = function() {
console.log(`Hola, soy ${this.nombre} y tengo ${this.edad} años.`);
};
// Crear instancias del objeto
const manuel = new Persona('Manuel', 36, ['Español', 'Inglés', 'Italiano']);
console.log(manuel);
manuel.saludar();
Vemos que este método ya es algo similar a lo que conocemos en Java, sólo tenemos la diferencia de las funciones que podemos asociarlas a los objetos o al prototipo (igual para todos los objetos).
5. Con class¶
Esto si que es lo que ya conocemos de Java:
class OtraPersona {
// Constructor para inicializar propiedades
constructor(nombre, edad, idiomas) {
this.nombre = nombre;
this.edad = edad;
this.idiomas = idiomas;
}
// Método para saludar
saludar() {
console.log(`Hola, soy ${this.nombre} y tengo ${this.edad} años.`);
}
// Método para listar idiomas (con lambdas)
listarIdiomas = () => console.log(`Hablo: ${this.idiomas.join(', ')}`);
}
// Crear instancias de la clase
const pedro = new OtraPersona('Pedro', 36, ['Español', 'Inglés', 'Italiano']);
console.log(pedro);
pedro.saludar();
pedro.listarIdiomas()
6. Con Object.create(prototipo)¶
Esta última opción es muy nativa de JS:
const bici = {
velocidad: 0,
acelerar: function (velocidad) { this.velocidad += velocidad; },
getVelocidad: function () { return this.velocidad; },
toString: function(){ return this.getVelocidad(); }
}
const miBici = Object.create(bici);
miBici.acelerar(10);
console.log("miBici",miBici);
miBici.acelerar(30);
console.log(miBici.getVelocidad());
console.log(miBici + ' km/h');
El método toString()¶
Repitamos la creación de objetos añadiendo el método toString() para mejorar la interacción con el mundo:
const bici = {
velocidad: 0,
acelerar: function (velocidad) { this.velocidad += velocidad; },
getVelocidad: function () { return this.velocidad; },
toString: function(){ return this.getVelocidad(); }
}
const miBici = Object.create(bici);
miBici.acelerar(10);
console.log(miBici, miBici.toString());
console.log(miBici + ' km/h');
typeof vs instanceof¶
console.log( typeof pedro, typeof miBici)
if ( pedro instanceof Persona ) console.log(`${pedro} -> Es un objeto de tipo "Persona"`);
if ( pedro instanceof OtraPersona ) console.log(pedro, ` -> Es un objeto de tipo "${pedro.constructor.name}"`);
Desectructuración de objetos:¶
let a, b, c;
({a, b, c} = { a: 3, b: 4, c: 5 });
let objeto = {a, b, c};
// Composición
let objetoCompuesto = {uno: 1, dos: 2, ...objeto};
console.log("Objeto de trabajo = ", objetoCompuesto);
console.log("Obtenemos el 2º atributo", objetoCompuesto.b);