En Javascript podemos definir cualquier variable como un objeto declarándola con new (NO se recomienda) o creando un literal object (usando notación JSON). Ejemplo con new (no recomendado):
const alumno = new Object()
alumno.nombre = 'Carlos' // se crea la propiedad 'nombre' y se le asigna un valor
alumno['apellidos'] = 'Pérez Ortiz' // se crea la propiedad 'apellidos'
alumno.edad = 19
Creando un literal object (es la forma recomendada) el ejemplo anterior sería:
const alumno = {
nombre: 'Carlos',
apellidos: 'Pérez Ortiz',
edad: 19,
};
Podemos acceder a las propiedades con .
(punto) o [ ]
:
console.log(alumno.nombre) // imprime 'Carlos'
console.log(alumno['nombre']) // imprime 'Carlos'
let prop = 'nombre'
console.log(alumno[prop]) // imprime 'Carlos'
Si intentamos acceder a propiedades que no existen no se produce un error, se devuelve undefined:
console.log(alumno.ciclo) // muestra undefined
Sin embargo se genera un error si intentamos acceder a propiedades de algo que no es un objeto:
console.log(alumno.ciclo) // muestra undefined
console.log(alumno.ciclo.descrip) // se genera un ERROR
Para evitar ese error antes había que comprobar que existan las propiedades previas:
console.log(alumno.ciclo && alumno.ciclo.descrip)
// si alumno.ciclo es un objeto muestra el valor de
// alumno.ciclo.descrip y si no muestra undefined
Con ES2020 (ES11) se ha incluido el operador de encadenamiento opcional ?. para evitar tener que comprobar esto nosotros:
console.log(alumno.ciclo?.descrip)
// si alumno.ciclo es un objeto muestra el valor de
// alumno.ciclo.descrip y si no muestra undefined
Podremos recorrer las propiedades de un objecto con for..in
:
for (let prop in alumno) {
console.log(prop + ': ' + alumno[prop])
}
Si el valor de una propiedad es el valor de una variable que se llama como la propiedad no es necesario ponerlo:
let nombre = 'Carlos'
const alumno = {
nombre, // es equivalente a nombre: nombre
apellidos: 'Pérez Ortiz',
...
Una propiedad de un objeto puede ser una función:
alumno.getInfo = function() {
return 'El alumno ' + this.nombre + ' ' + this.apellidos + ' tiene ' + this.edad + ' años'
}
NOTA: No podemos ponerlo con sintaxis arrow function porque no se podría acceder a las propiedades del objeto con this
.
Y para llamarlo se hace como con cualquier otra propiedad:
console.log(alumno.getInfo()) // imprime 'El alumno Carlos Pérez Ortíz tiene 19 años'
EJERCICIO: Crea un objeto llamado tvSamsung con las propiedades nombre (“TV Samsung 42”), categoria (“Televisores”), unidades (4), precio (345.95) y con un método llamado importe que devuelve el valor total de las unidades (nº de unidades * precio)
El operador de propagación, ...
(3 puntos), permite extraer las propiedades de un objeto. Ejemplo:
const personaCarlos = {
nombre: 'Carlos',
apellidos: 'Pérez Ortiz',
edad: 19,
};
const alumnoCarlos = {
...personaCarlos,
ciclo: 'DAW',
curso: 2,
};
El objeto alumnoCarlos tendrá las propiedades de personaCarlos y las que se le añadan. Si se repiten las propiedades se sobreescriben:
const alumnoCarlos = {
...personaCarlos,
ciclo: 'DAW',
curso: 2,
edad: 20,
};
Similar al anterior, permite extraer directamente a variables sólo las propiedades que necesitemos de un objeto. Ejemplo:
const personaCarlos = {
nombre: 'Carlos',
apellidos: 'Pérez Ortiz',
edad: 19,
};
function muestraNombre({nombre, apellidos}) {
console.log('El nombre es ' + nombre + ' ' + apellidos)
}
muestraNombre(personaCarlos)
Aunque a la función se le pasa un objeto esta toma como parámetros sólo 2 de sus propiedades y las asigna a las variables nombre y apellidos.
También podemos asignar valores por defecto:
function miProducto({nombre, apellidos = 'Desconocidos'}) {
...
En Javascript los objetos se comparan por referencia, no por valor. Por lo que dos objetos con los mismos valores no son iguales:
const a = {id:2, name: 'object 2'}
const b = {id:2, name: 'object 2'}
console.log(a === b) // muestra false
Cuando copiamos una variable de tipo boolean, string o number o se pasa como parámetro a una función se hace una copia de la misma y si se modifica la variable original no es alterada. Ej.:
let a = 54
let b = a // a = 54 b = 54
b = 86 // a = 54 b = 86
Sin embargo al copiar objetos (y arrays, que son un tipo de objeto) la nueva variable apunta a la misma posición de memoria que la antigua por lo que los datos de ambas son los mismos:
const a = {id:2, name: 'object 2'}
const b = a
b.name = 'object 3' // a = {id:2, name: 'object 3'} b = {id:2, name: 'object 3'}
const a = [54, 23, 12]
const b = a // a = [54, 23, 12] b = [54, 23, 12]
b[0] = 3 // a = [3, 23, 12] b = [3, 23, 12]
const fecha1 = new Date('2018-09-23')
const fecha2 = fecha1 // fecha1 = '2018-09-23' fecha2 = '2018-09-23'
fecha2.setFullYear(1999) // fecha1 = '1999-09-23' fecha2 = '1999-09-23'
Para obtener una copia independiente de un array o un objeto podemos usar el operador de propagación ...
o el método Object.assign
. Ejemplo:
const a = {id:2, name: 'object 2'}
const b = {...a} // ahora ambos objetos contienen lo mismo pero son diferentes
b.name = 'object 3' // a = {id:2, name: 'object 2'} b = {id:2, name: 'object 3'}
Con Object.assign
haremos:
const a = {id:2, name: 'object 2'}
const b = Object.assign({}, a) // ahora ambos objetos contienen lo mismo pero son diferentes
Sin embargo si el objeto tiene como propiedades otros objetos estos se continúan pasando por referencia. Es ese caso lo más sencillo sería hacer:
const a = {id: 2, name: 'object 2', address: {street: 'Rue del Percebe', num: 13} }
const copiaDeA = JSON.parse(JSON.stringify(a)) // ahora ambos objetos contienen lo mismo pero son diferentes
o bien usar la función structuredClone
:
const a = {id: 2, name: 'object 2', address: {street: 'Rue del Percebe', num: 13} }
const b = structuredClone(a) // ahora ambos objetos contienen lo mismo pero son diferentes
EJERCICIO: Dado el objeto a del último ejemplo copialo a un nuevo objeto b con
...
y prueba a cambiar las pripiedades id y street de b. ¿Qué pasa con sus valores en a?.