1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
|
---
title: Object.defineProperty()
slug: Web/JavaScript/Reference/Global_Objects/Object/defineProperty
tags:
- ECMAScript5
- JavaScript
- Método(2)
- Objeto
translation_of: Web/JavaScript/Reference/Global_Objects/Object/defineProperty
---
<div>{{JSRef}}</div>
<p>O método <code><strong>Object.defineProperty()</strong></code> define uma nova propriedade diretamente em um objeto, ou modifica uma propriedade já existente em um objeto, e retorna o objeto.</p>
<div class="note">
<p><strong>Nota</strong>: Você invoca este método diretamente no construtor do {{jsxref("Object")}} ao invés de invocar em uma instância do tipo <code>Object</code>.</p>
</div>
<h2 id="Sintaxe">Sintaxe</h2>
<pre class="syntaxbox notranslate"><code>Object.defineProperty(<var>obj</var>, <var>prop</var>, <var>descriptor</var>)</code></pre>
<h3 id="Parâmetros">Parâmetros</h3>
<dl>
<dt><code>obj</code></dt>
<dd>O objeto no qual será definida a propriedade.</dd>
<dt><code>prop</code></dt>
<dd>O nome da propriedade que será definida ou modificada.</dd>
<dt><code>descriptor</code></dt>
<dd>O descritor para a propriedade que será definida ou modificada.</dd>
</dl>
<h3 id="Valor_de_retorno">Valor de retorno</h3>
<p>O objeto que foi passado à função.</p>
<h2 id="Descrição">Descrição</h2>
<p>Esse método permite uma 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 {{jsxref("Statements/for...in", "for...in")}} ou pelo método {{jsxref("Object.keys")}}), e cujos valores podem ser alterados e {{jsxref("Operators/delete", "deletados", "", 1)}}, esse método permite a modificação deste comportamento padrão. Por padrão, valores incluídos utilizando <code>Object.defineProperty()</code> são imutáveis.</p>
<p>Os descritores de propriedades presentes nos objetos se apresentam em duas variedades: descritores de dados e descritores de assessores. Um <em>descritor de dado</em> é uma propriedade que contém um valor, podendo este ser gravável ou não. Um <em>descritor de assessor </em>é 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.</p>
<p>Ambos os descritores de dados e de assessor são objetos. Eles compartilham as seguintes chaves obrigatórias:</p>
<dl>
<dt><code>configurable</code></dt>
<dd><code>true</code> se e somente se o tipo deste descritor de propriedade pode ser alterado e se a propriedade pode ser deletada do objeto correspondente.<br>
<strong>Valor padrão é <code>false</code>.</strong></dd>
<dt><code>enumerable</code></dt>
<dd><code>true</code> se e somente se esta propriedade aparece durante enumeração das propriedades no objeto correspondente.<br>
<strong>Valor padrão é <code>false</code>.</strong></dd>
</dl>
<p>Um descritor de dados também possui as seguintes chaves opcionais:</p>
<dl>
<dt><code>value</code></dt>
<dd>O valor associado com a propriedade. Pode ser qualquer valor válido em Javascript (número, objeto, função, etc).<br>
<strong>Valor padrão é {{jsxref("undefined")}}.</strong></dd>
<dt><code>writable</code></dt>
<dd><code>true</code> se e somente se o valor associado com a propriedade pode ser modificada com um {{jsxref("Operators/Assignment_Operators", "operador de atribuição", "", 1)}}.<br>
<strong>Valor padrão é <code>false</code>.</strong></dd>
</dl>
<p>Um descritor de assessor também possui as seguintes chaves opcionais:</p>
<dl>
<dt><code>get</code></dt>
<dd>Uma função que servirá como um getter da propriedade, ou {{jsxref("undefined")}} se não houver getter. Quando a propriedade é acessada, esta função é chamada sem argumentos e com <code>this</code> define para o objeto no qual a propriedade é acessada (este pode não ser o objeto sobre o qual a propriedade está definida devido a herança). O valor retornado será usado como valor da propriedade.<br>
<strong>Valor padrão é {{jsxref("undefined")}}.</strong></dd>
<dt><code>set</code></dt>
<dd>A função que servirá como um setter para a propriedade, ou {{jsxref("undefined")}} se não houver setter. Quando a propriedade é atribuída, esta função é chamada com um argumento (o valor sendo atribuído para a propriedade) e com <code>this</code> configura o objeto através do qual a propriedade é atribuída.<br>
<strong>Valor padrão é {{jsxref("undefined")}}.</strong></dd>
</dl>
<p>Se um descritor tem nenhum das chaves <code>value</code>, <code>writable</code>, <code>get</code> e <code>set</code>, ele é tratado como um descritor de dados. Se um descritor tem ambas chaves <code>value</code> ou <code>writable</code> e <code>get</code> ou <code>set</code> keys, uma exceção é lançada.</p>
<p>Tenha em mente que estes atributos não são necessariamente as propriedades do próprio descritor. Propriedades herdadas serão consideradas também. Para garantir que estes padrões sejam preservados, você pode congelar o {{jsxref("Object.prototype")}} previamente, declarar todas as opções explicitamente, ou apontar para {{jsxref("null")}} com {{jsxref("Object.create", "Object.create(null)")}}.</p>
<pre class="brush: js notranslate">// usando __proto__
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);</pre>
<h2 id="Exemplos">Exemplos</h2>
<p>Se você deseja utilizar o método <code>Object.defineProperty</code> com uma sintaxe estilo <em>flags-binárias</em>, veja os <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty/Additional_examples">exemplos adicionais</a>.</p>
<h3 id="Criando_uma_propriedade">Criando uma propriedade</h3>
<p>Quando a propriedade especificada não existe no objeto, <code>Object.defineProperty()</code> cria uma nova propriedade conforme descrito anteriormente. Campos podem ser omitidos no descritor, e os valores padrão para esses campos serão introduzidos.</p>
<p>Todos os campos do tipo Boolean possuem como valor padrão <code>false</code>. Os campos <code>value</code>, <code>get</code>, e <code>set</code> possuem como padrão {{jsxref("undefined")}}. Uma propriedade que é definida sem os valores para <code>get</code>/<code>set</code>/<code>value</code>/<code>writable</code> é dita "genérica" e classificada como um descritor de dados.</p>
<pre class="brush: js notranslate">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</pre>
<h3 id="Modificando_uma_propriedade">Modificando uma propriedade</h3>
<p>Quando uma propriedade já existe, <code>Object.defineProperty()</code> 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 <code>configurable</code> como <code>false</code> a propriedade é chamada "não configurável" e nenhum atributo pode ser alterado <font face="consolas, Liberation Mono, courier, monospace">(exceto a alteração irreversível de <em>writable </em>para <em>false</em>)</font>. Não é possível alternar o tipo de uma propriedade entre dados e assessor quando esta for não-configurável.</p>
<p>Um {{jsxref("TypeError")}} é lançado quando são realizadas tentativas de se alterar propriedades não-configuráveis (exceto o atributo <code>writable</code>) a menos que o valor atual e o novo sejam os mesmos.</p>
<h4 id="O_atributo_writable">O atributo writable</h4>
<p>Quando o atributo <code>writable</code> de uma propriedade é definido como <code>false</code>, a propriedade é dita "não-gravável". Seu valor não poderá ser alterado.</p>
<pre class="brush: js notranslate">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.</pre>
<p>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.</p>
<h4 id="O_atributo_enumerable">O atributo enumerable</h4>
<p>O atributo <code>enumerable</code> de uma propriedade define se ela deve ser exibida em uma repetição {{jsxref("Statements/for...in", "for...in")}} e por {{jsxref("Object.keys()")}} ou não.</p>
<pre class="brush: js notranslate">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 é true 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</pre>
<h4 id="O_atributo_configurable">O atributo configurable</h4>
<p>O atributo <code>configurable</code> controla ao mesmo se uma propriedade pode ser deletada do objeto, e se seus atributos (exceto a mudança de <code>writable</code> para <code>false</code>) podem ser alterados.</p>
<pre class="brush: js notranslate">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</pre>
<p>Se o atributo <code>configurable</code> de <code>o.a</code> fosse <code>true</code>, nenhum dos erros seria lançado e a propriedade estaria deletada ao final.</p>
<h3 id="Incluindo_propriedades_e_valores_padrão">Incluindo propriedades e valores padrão</h3>
<p>É 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 <code>Object.defineProperty()</code>, como pode ser visto no exemplo abaixo:</p>
<pre class="brush: js notranslate">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
});</pre>
<h3 id="Setters_e_getters_customizados">Setters e getters customizados</h3>
<p>O exemplo abaixo mostra como implementar um objeto auto-arquivável. Quando a propriedade <code>temperature</code> é atribuída, o array <code>archive</code> recebe uma nova entrada de log.</p>
<pre class="brush: js notranslate">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 }]</pre>
<p>Neste exemplo, um getter sempre retorna o mesmo valor.</p>
<pre class="brush: js notranslate">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
</pre>
<h3 id="Propriedades_de_Herança">Propriedades de Herança </h3>
<p>Se uma propriedade de acessor é herdada, métodos <code>get</code> e <code>set</code> serão chamados quando a propriedade é acessada e modificada sobre os objetos descendentes. Se estes métodos usam uma variável para armazenar o valor, este valor será compartilhada por todos os objetos.</p>
<pre class="notranslate"><code>function myclass() {
}
var value;
Object.defineProperty(myclass.prototype, "x", {
get() {
return value;
},
set(x) {
value = x;
}
});
var a = new myclass();
var b = new myclass();
a.x = 1;
console.log(b.x); // 1</code></pre>
<p>Isto pode ser corrigido armazenando o valor em outra propriedade. Em métodos <code>get</code> e <code>set</code>, <code>this</code> aponta para o objeto no qual é usado para acessar ou modificar a propriedade.</p>
<pre class="notranslate"><code>function myclass() {
}
Object.defineProperty(myclass.prototype, "x", {
get() {
return this.stored_x;
},
set(x) {
this.stored_x = x;
}
});
var a = new myclass();
var b = new myclass();
a.x = 1;
console.log(b.x); // undefined</code></pre>
<p>Ao contrário das propriedades do acessor, propriedades do valor serão sempre configuradas sobre o próprio objeto, não sobre um protótipo. Entretanto, se uma propriedade de valor não-gravável é herdada, ele ainda previne de modicação a propriedade do objeto.</p>
<pre class="notranslate"><code>function myclass() {
}
myclass.prototype.x = 1;
Object.defineProperty(myclass.prototype, "y", {
writable: false,
value: 1
});
var a = new myclass();
a.x = 2;
console.log(a.x); // 2
console.log(myclass.prototype.x); // 1
a.y = 2; // Ignorado, lança no modo strict
console.log(a.y); // 1
console.log(myclass.prototype.y); // 1</code>
</pre>
<h2 id="Especificações">Especificações</h2>
<table>
<tbody>
<tr>
<th scope="col">Especificação</th>
<th scope="col">Status</th>
<th scope="col">Comentários</th>
</tr>
<tr>
<td>{{SpecName('ES5.1', '#sec-15.2.3.6', 'Object.defineProperty')}}</td>
<td>{{Spec2('ES5.1')}}</td>
<td>Definição inicial. Implementada no JavaScript 1.8.5.</td>
</tr>
<tr>
<td>{{SpecName('ES6', '#sec-object.defineproperty', 'Object.defineProperty')}}</td>
<td>{{Spec2('ES6')}}</td>
<td></td>
</tr>
<tr>
<td>{{SpecName('ESDraft', '#sec-object.defineproperty', 'Object.defineProperty')}}</td>
<td>{{Spec2('ESDraft')}}</td>
<td></td>
</tr>
</tbody>
</table>
<h2 id="Browser_compatibility">Compatibilidade com navegadores</h2>
<p>{{Compat("javascript.builtins.Object.defineProperty")}}</p>
<h2 id="Notas_de_compatibilidade">Notas de compatibilidade</h2>
<h3 id="Redefinindo_a_propriedade_length_de_um_objeto_Array">Redefinindo a propriedade <code>length</code> de um objeto <code>Array</code> </h3>
<p>É possível redefinir a propriedade {{jsxref("Array.length", "length")}} de arrays, sujeita às restrições de redefinição usuais. (A propriedade {{jsxref("Array.length", "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 {{jsxref("Array.length", "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.</p>
<p>Das versões 4 até 22 do Firefox, um {{jsxref("TypeError")}} é lançado em qualquer tentativa (seja ela permitida ou não) de redefinir a propriedade {{jsxref("Array.length", "length")}} de um array.</p>
<p>Versões do Chrome que implementam <code>Object.defineProperty()</code> em algumas circunstâncias ignoram um valor para <em>length</em> diferente do valor atual da propriedade {{jsxref("Array.length", "length")}} do array. Em algumas circustâncias, alterar o atributo <code>writable</code> 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 <em>length</em> não-gravável.</p>
<p>Versões do Safari que implementam <code>Object.defineProperty()</code> ignoram um valor para <code>length</code> diferente do valor atual da propriedade {{jsxref("Array.length", "length")}}, e tentantivas de alterar o atributo <code>writable</code> executam sem erros embora não modifiquem seu comportamento.</p>
<p>Apenas o Internet Explorer 9 a posteriores, e o Firefox 23 e posteriores, parecem implementar total e corretamente a redefinição da propriedade {{jsxref("Array.length", "length")}} de arrays. Por enquanto, não confie que a redefinição da propriedade {{jsxref("Array.length", "length")}} vá funcionar, mesmo que de uma forma particular. E mesmo quando você <em>puder </em>confiar, <a href="http://whereswalden.com/2013/08/05/new-in-firefox-23-the-length-property-of-an-array-can-be-made-non-writable-but-you-shouldnt-do-it/">existem boas razões para não fazer isso</a>.</p>
<h3 id="Notas_específicas_para_o_Internet_Explorer_8">Notas específicas para o Internet Explorer 8</h3>
<p>O Internet Explorer 8 implementa o método <code>Object.defineProperty()</code> para uso <a href="https://msdn.microsoft.com/en-us/library/dd229916%28VS.85%29.aspx">apenas em objetos DOM</a>. Algumas observações:</p>
<ul>
<li>Tentativas de usar <code>Object.defineProperty()</code> em objetos nativos lançam um erro.</li>
<li>Todos os atributos da propriedade devem ter seu valor definido. Os atributos <code>configurable</code>, <code>enumerable</code> e <code>writable</code> devem ser <code>true</code> para um descritor do tipo dado, e <code>true</code> para <code>configurable</code> e <code>false</code> para <code>enumerable</code> em descritores do tipo assessor. (?) Qualquer tentativa de usar outros valores (?) resultará no lançamento de um erro.</li>
<li>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.</li>
</ul>
<h2 id="Veja_também">Veja também</h2>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Enumerability_and_ownership_of_properties">Enumerabilidade and posse de propriedades</a></li>
<li>{{jsxref("Object.defineProperties()")}}</li>
<li>{{jsxref("Object.propertyIsEnumerable()")}}</li>
<li>{{jsxref("Object.getOwnPropertyDescriptor()")}}</li>
<li>{{jsxref("Object.prototype.watch()")}}</li>
<li>{{jsxref("Object.prototype.unwatch()")}}</li>
<li>{{jsxref("Operators/get", "get")}}</li>
<li>{{jsxref("Operators/set", "set")}}</li>
<li>{{jsxref("Object.create()")}}</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty/Additional_examples">Exemplos adicionais de <code>Object.defineProperty</code></a></li>
<li>{{jsxref("Reflect.defineProperty()")}}</li>
</ul>
|