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
|
---
title: Proxy
slug: Web/JavaScript/Reference/Global_Objects/Proxy
translation_of: Web/JavaScript/Reference/Global_Objects/Proxy
---
<div>
<div>{{JSRef}}</div>
</div>
<p>O objeto <strong>Proxy</strong> é usado para definir comportamentos customizados para operações fundamentais (por exemplo, pesquisa de propriedade, atribuição, enumeração, invocação de função, etc.).</p>
<h2 id="Terminologia">Terminologia</h2>
<dl>
<dt><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler">handler</a></dt>
<dd>Objeto marcador que contém <em>traps</em>.</dd>
<dt>traps</dt>
<dd>Métodos que fornecem acesso à propriedade. Isto é análogo ao conceito de <em>traps </em>(armadilhas) em sistemas operacionais</dd>
<dt>target</dt>
<dd>Objeto que o proxy virtualiza. É frequentemente utilizado como back-end de armazenamento para o proxy. Os invariantes (semânticas que permanecem inalterados) em relação à não-extensibilidade do objeto ou propriedades não-configuráveis são verificados em relação ao <em>target</em>.</dd>
</dl>
<h2 id="Sintaxe">Sintaxe</h2>
<pre class="syntaxbox">var p = new Proxy(target, handler);
</pre>
<h3 id="Parâmetros">Parâmetros</h3>
<dl>
<dt><code>target</code></dt>
<dd>Um objeto target (pode ser qualquer tipo de objeto, incluindo um array, uma função ou até mesmo outro <em>Proxy</em>) a ser envolvido com o <code>Proxy</code>.</dd>
<dt><code>handler</code></dt>
<dd>Um objeto cujas propriedades são funções que definem o comportamento do proxy quando uma operação é realizada sobre ele.</dd>
</dl>
<h2 id="Métodos">Métodos</h2>
<dl>
<dt>{{jsxref("Proxy.revocable()")}}</dt>
<dd>Cria um objeto <code> Proxy </code> revogável.</dd>
</dl>
<h2 id="Métodos_para_manipular_objetos">Métodos para manipular objetos</h2>
<p>O objeto manipulado é um objeto reservado que contém traps para <code> Proxy. </code></p>
<div>{{page('/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler', 'Methods') }}</div>
<h2 id="Exemplos">Exemplos</h2>
<h3 id="Exemplo_básico">Exemplo básico</h3>
<p>Neste exemplo simples, o número <code> 37 </code> é retornado como o valor padrão quando o nome da propriedade não está no objeto. Usa-se o manipulador <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/get"><code>get</code></a>.</p>
<pre class="brush: js">var handler = {
get: function(target, name) {
return name in target ?
target[name] :
37;
}
};
var p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 37
</pre>
<h3 id="Encaminhamento_de_Proxy">Encaminhamento de Proxy</h3>
<p>Neste exemplo, estamos usando um objeto JavaScript nativo ao qual nosso proxy irá encaminhar todas as operações que são aplicadas para ele.</p>
<pre class="brush: js">var target = {};
var p = new Proxy(target, {});
p.a = 37; // Operação encaminhada para o alvo
console.log(target.a); // 37. A operação foi devidamente encaminhada
</pre>
<h3 id="Validação">Validação</h3>
<p>Com um <code> Proxy</code>, você pode validar facilmente o valor passado para um objeto. Este exemplo usa o manipulador <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/set"> <code> set</code></a>.</p>
<pre class="brush: js">let validator = {
set: function(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('The age is not an integer');
}
if (value > 200) {
throw new RangeError('The age seems invalid');
}
}
//O comportamento padrão para armazenar o valor
obj[prop] = value;
// Indique o sucesso
return true;
}
};
let person = new Proxy({}, validator);
person.age = 100;
console.log(person.age); // 100
person.age = 'young'; // Lança uma exceção
person.age = 300; // Lança uma exceção</pre>
<h3 id="Construtor_de_extensão">Construtor de extensão</h3>
<p>Um proxy de função poderia facilmente estender um construtor com um novo construtor. Este exemplo usa os manipuladores <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/construct"> <code> construct </code> </a> e <a href="/En-US/docs/Web/JavaScript/Referência/Global_Objects/Proxy/handler/apply"> <code> apply</code></a>.</p>
<pre class="brush: js">function extend(sup, base) {
var descriptor = Object.getOwnPropertyDescriptor(
base.prototype, 'constructor'
);
base.prototype = Object.create(sup.prototype);
var handler = {
construct: function(target, args) {
var obj = Object.create(base.prototype);
this.apply(target, obj, args);
return obj;
},
apply: function(target, that, args) {
sup.apply(that, args);
base.apply(that, args);
}
};
var proxy = new Proxy(base, handler);
descriptor.value = proxy;
Object.defineProperty(base.prototype, 'constructor', descriptor);
return proxy;
}
var Person = function(name) {
this.name = name;
};
var Boy = extend(Person, function(name, age) {
this.age = age;
});
Boy.prototype.sex = 'M';
var Peter = new Boy('Peter', 13);
console.log(Peter.sex); // "M"
console.log(Peter.name); // "Peter"
console.log(Peter.age); // 13</pre>
<h3 id="DOM_manipulação_de_nós">DOM manipulação de nós</h3>
<p>Às vezes, você deseja alternar o atributo ou o nome da classe de dois elementos diferentes. Veja como usar o manipulador <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/set"> <code> set</code></a>.</p>
<pre class="brush: js">let view = new Proxy({
selected: null
},
{
set: function(obj, prop, newval) {
let oldval = obj[prop];
if (prop === 'selected') {
if (oldval) {
oldval.setAttribute('aria-selected', 'false');
}
if (newval) {
newval.setAttribute('aria-selected', 'true');
}
}
// O comportamento para armazenar o valor padrão
obj[prop] = newval;
// Indica o sucesso
return true;
}
});
let i1 = view.selected = document.getElementById('item-1');
console.log(i1.getAttribute('aria-selected')); // 'true'
let i2 = view.selected = document.getElementById('item-2');
console.log(i1.getAttribute('aria-selected')); // 'false'
console.log(i2.getAttribute('aria-selected')); // 'true'</pre>
<h3 id="Correção_de_valor_e_uma_propriedade_extra">Correção de valor e uma propriedade extra</h3>
<p>O objeto de proxy <code> produtos </code> avalia o valor passado e converte-o em uma matriz, se necessário. O objeto também suporta uma propriedade adicional chamada <code> latestBrowser </code> tanto em getters como em setters.</p>
<pre class="brush: js">let products = new Proxy({
browsers: ['Internet Explorer', 'Netscape']
},
{
get: function(obj, prop) {
// An extra property
if (prop === 'latestBrowser') {
return obj.browsers[obj.browsers.length - 1];
}
// O comportamento para armazenar o valor padrão
return obj[prop];
},
set: function(obj, prop, value) {
// An extra property
if (prop === 'latestBrowser') {
obj.browsers.push(value);
return true;
}
// Converta o valor se não for uma matriz
if (typeof value === 'string') {
value = [value];
}
// O comportamento para armazenar o valor padrão
obj[prop] = value;
// Indicate success
return true;
}
});
console.log(products.browsers); // ['Internet Explorer', 'Netscape']
products.browsers = 'Firefox'; // pass a string (by mistake)
console.log(products.browsers); // ['Firefox'] <- no problem, the value is an array
products.latestBrowser = 'Chrome';
console.log(products.browsers); // ['Firefox', 'Chrome']
console.log(products.latestBrowser); // 'Chrome'</pre>
<h3 id="Encontrando_um_item_de_objeto_em_uma_matriz_por_propriedade">Encontrando um item de objeto em uma matriz por propriedade</h3>
<p>Esta proxy estende uma matriz com alguns recursos de utilidade. Como você vê, você pode "definir" propriedades flexíveis sem usar <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties"> <code> Object.defineProperties</code></a>. Este exemplo pode ser adaptado para encontrar uma linha de tabela por sua célula. Nesse caso, o alvo será <a href="/en-US/docs/DOM/table.rows"> <code> table.rows </code> </a></p>
<pre class="brush: js">let products = new Proxy([
{ name: 'Firefox', type: 'browser' },
{ name: 'SeaMonkey', type: 'browser' },
{ name: 'Thunderbird', type: 'mailer' }
],
{
get: function(obj, prop) {
// O comportamento para retornar o valor; Prop geralmente é um inteiro
if (prop in obj) {
return obj[prop];
}
// Obter o número de produtos; Com products.length
if (prop === 'number') {
return obj.length;
}
let result, types = {};
for (let product of obj) {
if (product.name === prop) {
result = product;
}
if (types[product.type]) {
types[product.type].push(product);
} else {
types[product.type] = [product];
}
}
// Obtém um produto por nome
if (result) {
return result;
}
// Obtém produtos por tipo
if (prop in types) {
return types[prop];
}
// Obtém tipos de produto
if (prop === 'types') {
return Object.keys(types);
}
return undefined;
}
});
console.log(products[0]); // { name: 'Firefox', type: 'browser' }
console.log(products['Firefox']); // { name: 'Firefox', type: 'browser' }
console.log(products['Chrome']); // undefined
console.log(products.browser); // [{ name: 'Firefox', type: 'browser' }, { name: 'SeaMonkey', type: 'browser' }]
console.log(products.types); // ['browser', 'mailer']
console.log(products.number); // 3</pre>
<h3 id="Um_exemplo_completo_de_lista_de_traps">Um exemplo completo de lista de <code>traps</code></h3>
<p>Agora, para criar uma lista completa de amostra de <code>traps</code>, para fins didáticos, tentaremos propor um objeto <em>não nativo</em> que seja particularmente adequado para este tipo de operação: o objeto global <code>docCookies</code> criado por <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie/Simple_document.cookie_framework" title="https://developer.mozilla.org/en-US/docs/DOM/document.cookie#A_little_framework.3A_a_complete_cookies_reader.2Fwriter_with_full_unicode_support"> a "little framework" publicada na página<code>document.cookie</code></a>.</p>
<pre class="brush: js">/*
var docCookies = ... get the "docCookies" object here:
https://developer.mozilla.org/en-US/docs/DOM/document.cookie#A_little_framework.3A_a_complete_cookies_reader.2Fwriter_with_full_unicode_support
*/
var docCookies = new Proxy(docCookies, {
get: function (oTarget, sKey) {
return oTarget[sKey] || oTarget.getItem(sKey) || undefined;
},
set: function (oTarget, sKey, vValue) {
if (sKey in oTarget) { return false; }
return oTarget.setItem(sKey, vValue);
},
deleteProperty: function (oTarget, sKey) {
if (sKey in oTarget) { return false; }
return oTarget.removeItem(sKey);
},
enumerate: function (oTarget, sKey) {
return oTarget.keys();
},
ownKeys: function (oTarget, sKey) {
return oTarget.keys();
},
has: function (oTarget, sKey) {
return sKey in oTarget || oTarget.hasItem(sKey);
},
defineProperty: function (oTarget, sKey, oDesc) {
if (oDesc && 'value' in oDesc) { oTarget.setItem(sKey, oDesc.value); }
return oTarget;
},
getOwnPropertyDescriptor: function (oTarget, sKey) {
var vValue = oTarget.getItem(sKey);
return vValue ? {
value: vValue,
writable: true,
enumerable: true,
configurable: false
} : undefined;
},
});
/* Teste Cookies */
console.log(docCookies.my_cookie1 = 'First value');
console.log(docCookies.getItem('my_cookie1'));
docCookies.setItem('my_cookie1', 'Changed value');
console.log(docCookies.my_cookie1);</pre>
<h2 id="Especificações">Especificações</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col">Especificações</th>
<th scope="col">Status</th>
<th scope="col">Comentário</th>
</tr>
<tr>
<td>{{SpecName('ES2015', '#sec-proxy-objects', 'Proxy')}}</td>
<td>{{Spec2('ES2015')}}</td>
<td>Definição Inicial.</td>
</tr>
<tr>
<td>{{SpecName('ESDraft', '#sec-proxy-objects', 'Proxy')}}</td>
<td>{{Spec2('ESDraft')}}</td>
<td>?</td>
</tr>
</tbody>
</table>
<h2 id="Navegadores_Compatíveis">Navegadores Compatíveis</h2>
<p>{{Compat("javascript.builtins.Proxy", 2)}}</p>
<h2 id="Notas_Especificas_Gecko">Notas Especificas Gecko</h2>
<ul>
<li>No momento, <code>Object.getPrototypeOf(proxy)</code> retorna incondicionalmente um <code>Object.getPrototypeOf(target)</code>, porque a trap ES2015 getPrototypeOf não foi implementada ({{bug(795904)}}, {{bug(888969)}}).</li>
<li><code>Array.isArray(proxy)</code> retorna incondicionalmente um <code>Array.isArray(target)</code> ({{bug(1096753)}}, {{bug(1111785)}}).</li>
<li><code>Object.prototype.toString.call(proxy)</code> retorna incondicionalmente <code>Object.prototype.toString.call(target)</code>, porque ES2015 Symbol.toStringTag não foi implementado ({{bug(1114580)}}).</li>
</ul>
<h2 id="Veja_também">Veja também</h2>
<ul>
<li><a class="external" href="https://www.youtube.com/watch?v=sClk6aB_CPk">"Proxies are awesome" Brendan Eich presentation at JSConf</a> (<a class="external" href="http://www.slideshare.net/BrendanEich/metaprog-5303821">slides</a>)</li>
<li><a class="external" href="http://wiki.ecmascript.org/doku.php?id=harmony:proxies">ECMAScript Harmony Proxy proposal page</a> e <a class="external" href="http://wiki.ecmascript.org/doku.php?id=harmony:proxies_semantics">ECMAScript página de semântica de proxy Harmony</a></li>
<li><a class="external" href="http://soft.vub.ac.be/~tvcutsem/proxies/">Tutorial em proxies</a></li>
<li><a href="/en-US/docs/JavaScript/Old_Proxy_API" title="/en-US/docs/JavaScript/Old_Proxy_API">SpiderMonkey specific Old Proxy API</a></li>
<li>{{jsxref("Object.watch()")}} É um recurso não padrão, mas foi suportado no Gecko há muito tempo.</li>
</ul>
<h2 id="Nota_de_licença"><code><code>Nota de licença</code></code></h2>
<p>Alguns conteúdos (texto, exemplos) nesta página foram copiados ou adaptados do <a class="external" href="http://wiki.ecmascript.org/doku.php"> ECMAScript wiki </a> que contém à licença de conteúdo <a class="external" href="http://creativecommons.org/licenses/by-nc-sa/2.0/"> CC 2.0 BY-NC-SA </a>.</p>
|