Esta tradução está incompleta. Por favor, ajude a traduzir este artigo.

 

O método Object.defineProperty() define uma nova propriedade diretamente em um objeto, ou modifica uma propriedade já existente em um objeto, e retorna o objeto.

Sintaxe

Object.defineProperty(obj, prop, descriptor)

Parâmetros

obj
O objeto no qual será definida a propriedade.
prop
O nome da propriedade que será definida ou modificada.
descriptor
O descritor para a propriedade que será definida ou modificada.

Valor de retorno

O objeto que foi passado à função.

Descrição

Esse método permite a precisa inclusão ou modificação de uma propriedade em um objeto. Enquanto a inclusão de propriedades através de atribuição cria propriedades que são visíveis durante a enumeração (por repetições for...in ou pelo método Object.keys), e cujos valores podem ser alterados e deletados, esse método permite a modificação deste comportamento padrão. Por padrão, valores incluídos utilizando Object.defineProperty() são imutáveis.

Os descritores de propriedades presentes nos objetos se apresentam em duas variedades: descritores de dados e descritores de assessores. Um descritor de dado é uma propriedade que contém um valor, podendo este ser gravável ou não. Um descritor de assessor é uma propriedade definida como um par de funções getter-setter. Um descritor deve ser de uma destas variedades; não pode ser de ambas.

Ambos os descritores de dados e de assessor são objetos. Eles compartilham as seguintes chaves obrigatórias:

configurable
true se e somente se a propriedade com este tipo de descritor puder ser alterada e se a propriedade puder ser deletada do objeto correspondente.
O valor padrão é false.
enumerable
true se e somente se esta propriedade deve ser exibida na enumeração das propriedades do objeto correspondente.
O valor padrão é false.

Um descritor de dados também possui as seguintes chaves opcionais:

value
O valor associado à propriedade. Pode ser qualquer valor Javascript válido (número, objeto, função, etc).
O valor padrão é undefined.
writable
Indica se o valor de uma propriedade é gravável ou não. Possui valor true se e somente se o valor puder ser alterado com um operador de atribuição.
O valor padrão é false.

Um descritor de assessor também possui as seguintes chaves opcionais:

get
A função que servirá como getter da propriedade, ou undefined se não houver getter. O valor retornado pela função será usado como valor da propriedade.
O valor padrão é undefined.
set
A função que servirá como setter para a propriedade, ou undefined se não houver setter. A função receberá como único argumento o valor a ser atribuído à propriedade.
O valor padrão é undefined.

Tenha em mente que as opções do descritor não serão necessariamente aplicadas às suas propriedades, pois propriedades herdadas da cadeia de protótipos também são consideradas. Para garantir que estes padrões sejam preservados, você pode congelar o Object.prototype previamente, declarar todas as opções explicitamente, ou apontar para null ao utilizar Object.create(null).

// utilizando Object.create
var obj = {};

var descriptor = Object.create(null); // não herdar propriedades
// não enumerável, não configurável, não gravável por padrão
descriptor.value = 'static';

Object.defineProperty(obj, 'key', descriptor);

// declarando explicitamente
Object.defineProperty(obj, 'key', {
  enumerable: false,   // não enumerável
  configurable: false, // não configurável
  writable: false,     // não gravável
  value: 'static'
});

// reciclando um mesmo objeto
function withValue(value) {
  var d = withValue.d || (
    withValue.d = {
      enumerable: false,
      writable: false,
      configurable: false,
      value: null
    }
  );
  d.value = value;
  return d;
}

// ... e ...
Object.defineProperty(obj, 'key', withValue('static'));

// se o método freeze estiver disponível, prevenir as propriedades
// (value, get, set, enumerable, writable, configurable) de serem
// incluídas ou removidas do protótipo do objeto
(Object.freeze || Object)(Object.prototype);

Exemplos

Se você deseja utilizar o método Object.defineProperty com uma sintaxe estilo flags-binárias, veja os exemplos adicionais.

Criando uma propriedade

Quando a propriedade especificada não existe no objeto, Object.defineProperty()  cria uma nova propriedade conforme descrito anteriormente. Campos podem ser omitidos no descritor, e os valores padrão para esses campos serão introduzidos. Todos os campos do tipo Boolean possuem como valor padrão false. Os campos value, get, e set possuem como padrão undefined.  Uma propriedade que é definida sem os valores para get/set/value/writable é dita "genérica" e classificada como um descritor de dados.

var o = {}; // Criar um novo objeto

// Exemplo de propriedade de objeto inserida através
// de defineProperty com descritor do tipo dado
Object.defineProperty(o, 'a', {
  value: 37,
  writable: true,
  enumerable: true,
  configurable: true
});
// A propriedade 'a' existe no objeto com valor 37

// Exemplo de propriedade de objeto inserida através
// de defineProperty com descritor do tipo assessor
var bValue = 38;

Object.defineProperty(o, 'b', {
  get: function() { return bValue; },
  set: function(newValue) { bValue = newValue; },
  enumerable: true,
  configurable: true
});

o.b; // 38
// A propriedade 'b' existe no objeto com valor 38
// O valor de o.b será sempre idêntico a bValue, a
// menos que o.b seja redefinido

// Você não pode combinar ambos os tipos:
Object.defineProperty(o, 'conflict', {
  value: 0x9f91102,
  get: function() { return 0xdeadbeef; }
});
// lança um TypeError: value existe apenas em descritores
// de dado, get existe apenas em descritores de assessor

Modificando uma propriedade

Quando uma propriedade já existe, Object.defineProperty() tenta modificá-la de acordo com os valores do descritor e a configuração atual do objeto. Se o descritor antigo possuía seu atributo configurable como false a propriedade é chamada "não configurável" e nenhum atributo pode ser alterado (exceto a alteração irreversível de writable para false). Não é possível alternar o tipo de uma propriedade entre dados e assessor quando esta for não-configurável.

Um TypeError é lançado quando são realizadas tentativas de se alterar propriedades não-configuráveis (exceto o atributo writable) a menos que o valor atual e o novo sejam os mesmos.

O atributo writable

Quando o atributo writable de uma propriedade é definido como false, a propriedade é dita "não-gravável". Seu valor não poderá ser alterado.

var o = {}; // Cria um novo objeto

Object.defineProperty(o, 'a', {
  value: 37,
  writable: false
});

console.log(o.a); // escreve 37

o.a = 25; // Nenhum erro é lançado (no modo strict seria 
          // lançado mesmo que o valor fosse o mesmo)

console.log(o.a); // escreve 37. A atribuição não teve efeito.

Como visto no exemplo, tentativas de escrita em uma propriedade não-gravável não alteram seu valor, mas também não lançam erros.

O atributo enumerable

O atributo enumerable de uma propriedade define se ela deve ser exibida em uma repetição for...in e por Object.keys() ou não.

var o = {};

Object.defineProperty(o, 'a', {
  value: 1,
  enumerable: true
});

Object.defineProperty(o, 'b', {
  value: 2,
  enumerable: false
});

Object.defineProperty(o, 'c', {
  value: 3
}); // o valor padrão para enumerable é false

o.d = 4; // o valor padrão para enumerable é false quando
         // a propriedade é criada em uma atribuição

for (var i in o) {
  console.log(i);
}
// escreve 'a' e 'd' (em ordem indefinida)

Object.keys(o); // ['a', 'd']

o.propertyIsEnumerable('a'); // true
o.propertyIsEnumerable('b'); // false
o.propertyIsEnumerable('c'); // false

O atributo configurable

O atributo configurable controla ao mesmo se uma propriedade pode ser deletada do objeto, e se seus atributos (exceto a mudança de writable para false) podem ser alterados.

var o = {};

Object.defineProperty(o, 'a', {
  get: function() { return 1; },
  configurable: false
});

Object.defineProperty(o, 'a', {
  configurable: true
}); // lança um TypeError

Object.defineProperty(o, 'a', {
  enumerable: true
}); // lança um TypeError

Object.defineProperty(o, 'a', {
  set: function() {}
}); // lança um TypeError (o atributo set já estava definido)

Object.defineProperty(o, 'a', {
  get: function() { return 1; }
}); // lança um TypeError 
    // (mesmo o novo get fazendo exatamente a mesma coisa)

Object.defineProperty(o, 'a', {
  value: 12
}); // lança um TypeError

console.log(o.a); // escreve 1
delete o.a; // Nada acontece
console.log(o.a); // escreve 1

Se o atributo configurable de o.a fosse true, nenhum dos erros seria lançado e a propriedade estaria deletada ao final.

Incluindo propriedades e valores padrão

É importante considerar a forma como os valores padrão para atributos são aplicados. Normalmente existe diferença entre usar a notação por ponto para atribuir um valor e usar Object.defineProperty(), como pode ser visto no exemplo abaixo:

var o = {};

o.a = 1;

// é equivalente a:
Object.defineProperty(o, 'a', {
  value: 1,
  writable: true,
  configurable: true,
  enumerable: true
});

// Por outro lado,
Object.defineProperty(o, 'a', { value: 1 });

// é equivalente a:
Object.defineProperty(o, 'a', {
  value: 1,
  writable: false,
  configurable: false,
  enumerable: false
});

Setters e getters customizados

O exemplo abaixo mostra como implementar um objeto auto-arquivável. Quando a propriedade temperature é atribuída, o array archive recebe uma nova entrada de log.

function Archiver() {
  var temperature = null;
  var archive = [];

  Object.defineProperty(this, 'temperature', {
    get: function() {
      console.log('get!');
      return temperature;
    },
    set: function(value) {
      temperature = value;
      archive.push({ val: temperature });
    }
  });

  this.getArchive = function() { return archive; };
}

var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 }, { val: 13 }]

ou

var pattern = {
    get: function () {
        return 'Eu sempre retorno esta string, ' +
               'não importa o que você atribuiu';
    },
    set: function () {
        this.myname = 'esta string é meu nome';
    }
};

function TestDefineSetAndGet() {
    Object.defineProperty(this, 'myproperty', pattern);
}

var instance = new TestDefineSetAndGet();
instance.myproperty = 'test';

console.log(instance.myproperty);
// Eu sempre retorno esta string, não importa o que você atribuiu

console.log(instance.myname); // esta string é meu nome

Especificações

Especificação Status Comentários
ECMAScript 5.1 (ECMA-262)
The definition of 'Object.defineProperty' in that specification.
Padrão Definição inicial. Implementada no JavaScript 1.8.5.
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Object.defineProperty' in that specification.
Padrão  
ECMAScript Latest Draft (ECMA-262)
The definition of 'Object.defineProperty' in that specification.
Padrão em tempo real  

Compatibilidade de browser

FeatureChromeEdgeFirefoxInternet ExplorerOperaSafari
Basic support5 Yes49111.65.12
FeatureAndroid webviewChrome for AndroidEdge mobileFirefox for AndroidIE mobileOpera AndroidiOS Safari
Basic support Yes Yes Yes4 Yes11.5 Yes

1. Also supported in Internet Explorer 8, but only on DOM objects and with some non-standard behaviors.

2. Also supported in Safari 5, but not on DOM objects.

Notas de compatibilidade

Redefinindo a propriedade length de um objeto Array 

É possível redefinir a propriedade length de arrays, sujeita às restrições de redefinição usuais. (A propriedade length é inicialmente não configurável, não enumerável, mas gravável. Assim, em um array que não foi modificado, é possível alterar o valor da propriedade length ou torná-la não-gravável. Não é permitido alterar sua enumerabilidade ou configurabilidade, ou quando se encontrar não-gravável, alterar seu valor ou torná-la gravável novamente.) Entretanto, nem todos os browsers permitem esta redefinição.

Das versões 4 até 22 do Firefox, um TypeError é lançado em qualquer tentativa (seja ela permitida ou não) de redefinir a propriedade length de um array.

Versões do Chrome que implementam Object.defineProperty() em algumas circunstâncias ignoram um valor para length diferente do valor atual da propriedade length do array. Em algumas circustâncias, alterar o atributo writable falha de forma silenciosa (sem lançar uma exceção). Além disso, alguns métodos que modificam o array como {jsxref("Array.prototype.push")}} não respeitam uma propriedade length não-gravável.

Versões do Safari que implementam Object.defineProperty() ignoram um valor para length diferente do valor atual da propriedade length, e tentantivas de alterar o atributo writable executam sem erros embora não modifiquem seu comportamento.

Apenas o Internet Explorer 9 a posteriores, e o Firefox 23 e posteriores, parecem implementar total e corretamente a redefinição da propriedade length de arrays. Por enquanto, não confie que a redefinição da propriedade length vá funcionar, mesmo que de uma forma particular. E mesmo quando você puder confiar, existem boas razões para não fazer isso.

Notas específicas para o Internet Explorer 8

O Internet Explorer 8 implementa o método Object.defineProperty() para uso apenas em objetos DOM. Algumas observações:

  • Tentativas de usar Object.defineProperty() em objetos nativos lançam um erro.
  • Todos os atributos da propriedade devem ter seu valor definido. Os atributos configurable, enumerable e writable devem ser true para um descritor do tipo dado, e true para configurable e false para enumerable em descritores do tipo assessor. (?) Qualquer tentativa de usar outros valores (?) resultará no lançamento de um erro.
  • Reconfigurar uma propriedade exige que ela seja deletada anteriormente. Se a propriedade não for deletada, ela permanecerá inalterada após a tentativa de reconfiguração.

Veja também

Etiquetas do documento e colaboradores

 Colaboradores desta página: saulobmansur, joeltonmats, mshmeirelles, ronniery
 Última atualização por: saulobmansur,