Função Object.create e Configuração de propriedades de objetos em JavaScript
Função Object.create
Outra maneira de criar um objeto é por meio da função Object.create
, que aceita dois parâmetros. O primeiro parâmetro é o protótipo, base para a criação do objeto, e o segundo parâmetro é a definição das propriedades e métodos do objeto:
const tom = Object.create(protótipo, { propriedades e métodos });
Por exemplo:
const tom = Object.create(Object.prototype, {
name: {
value: "Tom",
},
age: {
value: 39,
},
print: {
value: function () {
console.log(`Name: ${this.name} Age: ${this.age}`);
},
},
});
console.log(tom.name); // Tom
console.log(tom.age); // 39
tom.print(); // Name: Tom Age: 39
Aqui, como protótipo na função Object.create()
, passa-se o Object.prototype
. O segundo parâmetro da função é a definição de propriedades no formato:
nome_da_propriedade/método: {
value: valor_da_propriedade/método
}
Ao nome da propriedade/método é associado um objeto que possui a propriedade value
, que de fato armazena o valor da propriedade/método. Por exemplo, a propriedade age
é igual a 39:
age: {
value: 39;
}
Para um método, o valor é a definição da função.
Após a criação do objeto, podemos acessar suas propriedades e métodos como de costume:
console.log(tom.age); // 39
Este método de criação de objetos pode parecer um pouco complexo e excessivo. No entanto, ele permite configurar detalhadamente as propriedades. Por exemplo, além do campo value
na configuração de uma propriedade, podemos definir campos adicionais:
writable
: armazena um valor booleano, que indica se a propriedade pode ser escrita, ou seja, se um novo valor pode ser atribuído a ela. Por padrão, esse atributo éfalse
.enumerable
: armazena um valor booleano, que indica se a propriedade correspondente é enumerável, ou seja, se a propriedade é incluída durante a enumeração das propriedades do objeto (por exemplo, usando o loop for...in). Por padrão, éfalse
.configurable
: armazena um valor booleano, que indica se o próprio atributo para a propriedade correspondente pode ser alterado, ou seja, se a propriedade pode ser configurada posteriormente usando atributos. O valor padrão para este atributo também éfalse
.set
: define qual função é chamada quando o valor da propriedade é alterado.get
: define qual função é chamada ao ler o valor da propriedade.
Aplicando alguns desses atributos:
const tom = Object.create(Object.prototype, {
name: {
value: "Tom",
enumerable: true, // disponível para enumeração
writable: false, // NÃO disponível para escrita
},
age: {
value: 39,
enumerable: true, // disponível para enumeração
writable: true, // disponível para escrita
},
print: {
value: function () {
console.log(`Name: ${this.name} Age: ${this.age}`);
},
enumerable: false, // não disponível para enumeração
writable: false, // NÃO disponível para escrita
},
});
console.log(tom.name); // Tom
tom.name = "Tomas";
console.log(tom.name); // Tom - a propriedade name não está disponível para alteração
console.log(tom.age); // 39
tom.age = 22;
console.log(tom.age); // 22 - a propriedade age está disponível para alteração
tom.print(); // Name: Tom Age: 22
// iterando sobre o objeto
for (prop in tom) {
console.log(prop);
}
// Saída no console:
// name
// age
No exemplo acima, a função Object.create
utiliza muito código para criar um objeto. Mas, se temos muitas propriedades e métodos, e apenas algumas configurações (por exemplo, tornar uma propriedade somente leitura) são necessárias para uma propriedade específica, então podemos criar um objeto de maneira padrão, e todas as propriedades adicionais que exigem configuração são definidas usando a função Object.defineProperty
:
const tom = {
age: 39,
print: function () {
console.log(`Name: ${this.name} Age: ${this.age}`);
},
};
Object.defineProperty(tom, "name", {
value: "Tom",
writable: false, // NÃO disponível para escrita
});
console.log(tom.name); // Tom
tom.name = "Tomas";
console.log(tom.name); // Tom - a propriedade name não está disponível para alteração
tom.print(); // Name: Tom Age: 22
A função Object.defineProperty()
aceita três parâmetros. O primeiro parâmetro é o objeto para o qual a propriedade é definida. O segundo parâmetro é o nome da propriedade. O terceiro parâmetro é um objeto de configuração. Portanto, neste caso, definimos para o objeto tom
a propriedade name
, que será disponível apenas para leitura.
Se precisarmos definir várias propriedades dessa forma, usamos a função Object.defineProperties
, que aceita um objeto e um conjunto de configurações para as propriedades adicionadas:
const tom = { age: 39 };
// definindo propriedades adicionais para o objeto tom
Object.defineProperties(tom, {
name: {
// definindo a propriedade name
value: "Tom",
writable: false, // NÃO disponível para escrita
},
print: {
// definindo o método print
value: function () {
console.log(`Name: ${this.name} Age: ${this.age}`);
},
writable: false, // NÃO disponível para escrita
},
});
tom.name = "Tomas"; // a propriedade name não está disponível para alteração
tom.print = function () {
console.log("Hello World");
}; // o método print não está disponível para alteração
tom.print(); // Name: Tom Age: 39
Vale notar que dessa maneira podemos não apenas adicionar novas propriedades, mas também redefinir a configuração de propriedades já existentes. Por exemplo:
const tom = { name: "Tom" };
// proibindo alterações na propriedade name
Object.defineProperty(tom, "name", { writable: false });
tom.name = "Tomas";
console.log(tom.name); // Tom - o valor da propriedade não foi alterado