Definición y Control de Propiedades en Objetos JavaScript
Clase 4 de 20 • Curso Intermedio de Programación Orientada a Objetos en JavaScript
Resumen
El método defineProperty
de la superclase Object
no solo nos permite definir nuevos atributos en un objeto, sino también configurar las siguientes propiedades:
- Configurable: indica si el nuevo atributo puede ser eliminado.
- Enumerable: indica si el nuevo atributo podrá ser mostrado mediante funciones que listen las propiedades de un objeto. Hay excepciones en las que igual puede ser visualizado un atributo que tenga definido como
false
la propiedadenumerable
. - Writable: indica si el nuevo atributo puede ser modificado de valor.
Normalmente, estas propiedades por defecto son definidas como true
por JavaScript, sin embargo, si generamos los atributos de un objeto con Object.defineProperty
, podríamos definirlas a nuestro gusto.
const juan = {
name: "Juanito",
age: 18,
approvedCourses: ["Curso 1"],
addCourse(newCourse) {
console.log("This", this);
console.log("This.approvedCourses", this.approvedCourses);
this.approvedCourses.push(newCourse);
}
};
Object.defineProperty(juan, "nombreNuevaPropiedad", {
value: "JavaScript", // Valor que tendrá
enumerable: false,
writable: true,
configurable: false,
});
Accesibilidad a los atributos de un objeto
Con configurable
, enumerable
y writable
podemos limitar el acceso y modificación de los atributos de un objeto. Veamos su funcionamiento mediante un par de ejemplos:
Atributos que no puedan ser listados
Definimos enumerable
como false
. Este atributo recién creado no se podrá visualizar si por ejemplo intentamos listar las llaves del objeto usando Object.keys
:
// Definimos el objeto
const juan = {
name: "Juanito",
age: 18,
approvedCourses: ["Curso 1"],
addCourse(newCourse) {
console.log("This", this);
console.log("This.approvedCourses", this.approvedCourses);
this.approvedCourses.push(newCourse);
}
};
Object.defineProperty(juan, "navigator", { // Creamos un nuevo atributo
value: "Chrome",
enumerable: false,
writable: true,
configurable: true,
});
console.log( // Imprimimos las llaves del objeto
Object.keys(juan)
); // [ 'name', 'age', 'approvedCourses', 'addCourse' ]
Sin embargo, hay una excepción si usamos Object.getOwnPropertyNames
:
// Definimos el objeto
const juan = {
name: "Juanito",
age: 18,
approvedCourses: ["Curso 1"],
addCourse(newCourse) {
console.log("This", this);
console.log("This.approvedCourses", this.approvedCourses);
this.approvedCourses.push(newCourse);
}
};
Object.defineProperty(juan, "navigator", { // Creamos un nuevo atributo
value: "Chrome",
enumerable: false, // 👀
writable: true,
configurable: true,
});
console.log( // Imprimimos las propiedades del objeto
Object.getOwnPropertyNames(juan)
); // [ 'name', 'age', 'approvedCourses', 'addCourse', 'navigator' ] 👈 Ya nos aparece
Atributos que no se puedan eliminar
Para ello definimos configurable
como false
en la nueva propiedad:
// Definimos el objeto
const juan = {
name: "Juanito",
age: 18,
approvedCourses: ["Curso 1"],
addCourse(newCourse) {
console.log("This", this);
console.log("This.approvedCourses", this.approvedCourses);
this.approvedCourses.push(newCourse);
}
};
Object.defineProperty(juan, "terminal", { // Creamos un nuevo atributo
value: "WSL",
enumerable: true,
writable: true,
configurable: false, // 👀
});
console.log( // Mostramos las propiedades del objeto previamente... 👁👁
Object.keys(juan)
); // [ 'name', 'age', 'approvedCourses', 'addCourse', 'terminal' ]
delete terminal; // Intentamos eliminar ❌
console.log( // Listamos los atributos para comprobar si se eliminó `terminal` 🤔
Object.keys(juan)
); // [ 'name', 'age', 'approvedCourses', 'addCourse', 'terminal' ] 👈 NO se eliminó
Atributos que no se puedan sobreescribir
Definimos writable
como false
:
// Definimos el objeto
const juan = {
name: "Juanito",
age: 18,
approvedCourses: ["Curso 1"],
addCourse(newCourse) {
console.log("This", this);
console.log("This.approvedCourses", this.approvedCourses);
this.approvedCourses.push(newCourse);
}
};
Object.defineProperty(juan, "editor", { // Creamos un nuevo atributo
value: "VSCode",
enumerable: true,
writable: false,
configurable: true,
});
console.log(juan.editor); // "VSCode"
juan.editor = "Atom"; // Intentamos sobreescribirlo
console.log(juan.editor); // "VSCode" 👈 No cambió
Qué es Object.seal y Object.freeze
El método seal
“sella” un determinado objeto. Es decir:
- Impide que nuevas propiedades sean agregadas.
- Define como
configurable: false
todos los atributos del objeto, con lo que impide que sean borradas. - Los atributos sí pueden ser modificados, ya que la propiedad
writable
permanece asignado comotrue
.
// Definimos el objeto
const juan = {
name: "Juanito",
age: 18,
approvedCourses: ["Curso 1"],
addCourse(newCourse) {
console.log("This", this);
console.log("This.approvedCourses", this.approvedCourses);
this.approvedCourses.push(newCourse);
}
};
Object.seal(juan); // "Sellamos" el objeto
// Listamos para saber las llaves actuales:
console.log(Object.keys(juan)); // [ 'name', 'age', 'approvedCourses', 'addCourse' ]
delete age; // Intentamos eliminar un atributo del objeto
// Listamos para observar si hubo cambios:
console.log(Object.keys(juan)); // [ 'name', 'age', 'approvedCourses', 'addCourse' ]
El método freeze
“congela” un objeto. Es decir:
- Impide que se le agreguen nuevas propiedades.
- Impide que sean eliminadas propiedades ya existentes.
- Evita que sus propiedades
writable
,enumerable
yconfigurable
sean modificadas.
// Definimos el objeto
const juan = {
name: "Juanito",
age: 18,
approvedCourses: ["Curso 1"],
addCourse(newCourse) {
console.log("This", this);
console.log("This.approvedCourses", this.approvedCourses);
this.approvedCourses.push(newCourse);
}
};
Object.freeze(juan); // "Congelamos" el objeto
// Listamos para saber las llaves actuales:
console.log(Object.keys(juan)); // [ 'name', 'age', 'approvedCourses', 'addCourse' ]
delete approvedCourses; // Intentamos eliminar un atributo del objeto
juan.name = "Carlitos"; // Intentamos sobreescribir el valor de este atributo
// Listamos para observar si hubo cambios:
console.log(Object.keys(juan)); // [ 'name', 'age', 'approvedCourses', 'addCourse' ]
// Verificamos si cambió el valor de `name`:
console.log(juan.name); // "Juanito"
Conozcamos ahora cómo funciona la memoria en JavaScript. 🤔👨💻
Contribución creada por: Martín Álvarez (Platzi Contributor) con el aporte de Zajith Corro Viveros.