É provável que a maior parte da sua interação com as propriedades do objeto seja no nível da superfície, incluindo a criação de literais de objetos e a configuração e o acesso usando chaves. No entanto, é possível configurar internamente qualquer propriedade um objeto para controle refinado sobre como essas propriedades são acessadas, alterados e definidos. Cada propriedade de objeto tem um conjunto de atributos invisíveis que contêm metadados associados à propriedade, chamados de "propriedade descritores".
Há dois tipos de descritores associados a qualquer propriedade: data descritores e descritores do acessador. Um descritor de dados inclui pares de chave-valor que contêm o valor de uma propriedade, independentemente dela o valor é gravável, configurável ou enumerável. Os descritores do acessador contêm que são executadas quando uma propriedade é definida, alterada ou acessada.
Propriedade | Tipo de descritor | Valor padrão de Object.defineProperty() |
Descrição |
---|---|---|---|
[[Value]] |
Dados | undefined |
Contém o valor de uma propriedade. |
[[Writable]] |
Dados | false |
Determina se você pode mudar o valor da propriedade. |
[[Get]] |
Acessador | undefined |
A função getter da propriedade, que é executada quando o é acessada. |
[[Set]] |
Acessador | undefined |
A função setter da propriedade, que é executada quando o é definida ou alterada. |
[[Configurable]] |
Ambos | false |
Se o valor for false , não será possível excluir a propriedade e
atributos não podem ser alterados. Se for false e
[[Writable]] for true , o valor da propriedade poderá
ainda podem ser alteradas. |
[[Enumerable]] |
Ambos | false |
Se for true , você poderá iterar na propriedade usando
Loops for...in ou a Object.keys() estática
. |
Cada uma dessas propriedades usa a mesma abreviação de [[Prototype]]
, indicando
para que essas propriedades não sejam acessadas diretamente. Em vez disso, use o método
Método estático Object.defineProperty()
para definir ou modificar as propriedades de um
objeto. Object.defineProperty()
aceita três argumentos: o objeto em que a ação será aplicada,
a chave de propriedade a ser criada ou modificada e um objeto contendo a
descritores associados à propriedade que está sendo criada ou modificada.
Por padrão, as propriedades criadas usando Object.defineProperty()
não sejam graváveis, enumeráveis ou configuráveis. No entanto, qualquer propriedade que você criar
como parte do literal do objeto ou usando a notação de ponto ou colchete é
graváveis, enumeráveis e configuráveis.
const myObj = {};
Object.defineProperty(myObj, 'myProperty', {
value: true,
writable: false
});
myObj.myProperty;
> true
myObj.myProperty = false;
myObj.myProperty;
> true
Por exemplo, quando [[Writable]]
tem um valor false
, tentar definir um novo valor
da propriedade associada falha silenciosamente fora do modo restrito e gera uma
erro no modo estrito:
{
const myObj = {};
Object.defineProperty(myObj, 'myProperty', {
value: true,
writable: false
});
myObj.myProperty = false;
myObj.myProperty;
}
> true
(function () {
"use strict";
const myObj = {};
Object.defineProperty(myObj, 'myProperty', {
value: true,
writable: false
});
myObj.myProperty = false;
myObj.myProperty;
}());\
> Uncaught TypeError: "myProperty" is read-only
O uso eficaz de descritores é um conceito bastante avançado, mas
entender a estrutura interna de um objeto é essencial
sintaxes envolvidas no trabalho com objetos de formas mais comuns. Por exemplo:
esses conceitos entram em jogo ao usar o método estático Object.create()
,
o que oferece um controle detalhado sobre quaisquer protótipos anexados ao novo
objeto.
Object.create()
cria um novo objeto usando um objeto existente como o
protótipo. Isso permite que o novo objeto herde propriedades e métodos de outro
definido pelo usuário da mesma forma que os objetos herdam as propriedades
Protótipo Object
integrado do JavaScript. Quando você invoca Object.create()
com
um objeto como argumento, ele cria um objeto vazio com o objeto passado como
no protótipo.
const myCustomPrototype = {
'myInheritedProp': 10
};
const newObject = Object.create( myCustomPrototype );
newObject;
> Object { }
<prototype>: Object { myInheritedProp: 10 }
myInheritedProp: 10
<prototype>: Object { … }
Object.create
pode ter um segundo argumento que especifica as próprias propriedades para o
objeto recém-criado usando uma sintaxe semelhante a Object.defineProperty()
:
ou seja, chaves de mapeamento de objeto para um conjunto de atributos de descritor:
const myCustomPrototype = {
'myInheritedProp': 10
};
const myObj = Object.create( myCustomPrototype, {
myProperty: {
value: "The new property value.",
writable: true,
configurable: true
}
});
myObj;
> Object { … }
myProperty: "The new property value."
<prototype>: Object { myInheritedProp: 10 }
Neste exemplo, o novo objeto (myObj
) usa um literal de objeto.
(myCustomPrototype
) como protótipo, que contém o arquivo herdado
Object.prototype
, o que resulta em uma série de protótipos herdados chamada de
cadeia de protótipos. Cada objeto tem um protótipo, atribuído ou herdado,
que tem um protótipo atribuído ou herdado próprio. Essa cadeia termina em
null
, que não tem um protótipo próprio.
const myPrototype = {
'protoProp': 10
};
const newObject = Object.setPrototypeOf( { 'objProp' : true }, myPrototype );
newObject;
> Object { objProp: true }
objProp: true
<prototype>: Object { protoProp: 10 }
protoProp: 10
<prototype>: Object { … }
As propriedades contidas em um protótipo de valor estão disponíveis no "nível superior" de um objeto, sem precisar acessar a propriedade do protótipo diretamente:
const objectLiteral = {
"value" : true
};
objectLiteral;
> Object { value: true }
value: true
<prototype>: Object { … }
objectLiteral.toString();
"[object Object]"
Esse padrão se aplica a toda a cadeia de protótipos associada a uma objeto: ao tentar acessar uma propriedade, o intérprete procura por essa propriedade em cada "nível" da cadeia do protótipo, de cima para baixo, até encontra a propriedade ou a cadeia termina:
const myCustomPrototype = {
'protoProp': "Prototype property value."
};
const myObj = Object.create( myCustomPrototype, {
myProperty: {
value: "Top-level property value.",
writable: true,
configurable: true
}
});
myObj.protoProp;
> "Prototype property value."
Teste seu conhecimento
Quais descritores são acessadores?
[[Get]]
[[Set]]
[[Writable]]