<h2>Entendendo Proxy e Reflect na Prática</h2>
<p>Proxy e Reflect são dois APIs JavaScript que trabalham juntos para interceptar e personalizar operações em objetos. Um Proxy funciona como intermediário: você define "armadilhas" (traps) que interceptam ações como leitura, escrita e exclusão de propriedades. Reflect é seu complemento, fornecendo métodos que replicam o comportamento padrão do JavaScript. Juntos, eles formam a base para frameworks reativos como Vue.js e MobX.</p>
<p>A diferença fundamental: Proxy intercepta operações, enquanto Reflect as executa de forma controlada. Quando você quer criar reatividade, precisa saber exatamente quando uma propriedade é acessada ou modificada. Isso permite rastrear dependências e disparar atualizações automáticas em sua interface.</p>
<pre><code class="language-javascript">// Exemplo básico: rastreador de acesso
const target = { nome: 'João', idade: 30 };
const handler = {
get(target, prop) {
console.log(Acessando: ${prop});
return Reflect.get(target, prop);
},
set(target, prop, valor) {
console.log(Alterando ${prop} para ${valor});
return Reflect.set(target, prop, valor);
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.nome); // "Acessando: nome" → "João"
proxy.idade = 31; // "Alterando idade para 31"</code></pre>
<h2>Construindo um Sistema Reativo Básico</h2>
<p>Um framework reativo detecta mudanças e propaga atualizações automaticamente. O segredo está em manter um registro de quais propriedades foram acessadas durante a execução de uma função e executar essa função novamente quando essas propriedades mudam.</p>
<p>Vamos construir um sistema minimal de reatividade:</p>
<pre><code class="language-javascript">class Reactive {
constructor(data) {
this.data = data;
this.watchers = new Map(); // Prop → Set de callbacks
this.currentEffect = null;
return this.createProxy(data);
}
createProxy(target) {
return new Proxy(target, {
get: (obj, prop) => {
// Rastrear dependência durante execução de efeito
if (this.currentEffect) {
if (!this.watchers.has(prop)) {
this.watchers.set(prop, new Set());
}
this.watchers.get(prop).add(this.currentEffect);
}
return Reflect.get(obj, prop);
},
set: (obj, prop, valor) => {
const resultado = Reflect.set(obj, prop, valor);
// Disparar callbacks quando propriedade muda
if (this.watchers.has(prop)) {
this.watchers.get(prop).forEach(callback => callback());
}
return resultado;
}
});
}
effect(fn) {
this.currentEffect = fn;
fn();
this.currentEffect = null;
}
}
// Uso prático
const state = new Reactive({ contador: 0, nome: 'App' });
state.effect(() => {
console.log(Contador: ${state.contador});
});
state.contador++; // Executa novamente: "Contador: 1"
state.contador++; // Executa novamente: "Contador: 2"
state.nome = 'Novo'; // Não executa (dependência não registrada)</code></pre>
<p>Este é o padrão fundamental: rastrear leitura durante efeitos e executar novamente em mudanças. Vue 3 e MobX usam variações mais sofisticadas, mas o conceito é idêntico.</p>
<h2>Validação e Transformação com Handlers Avançados</h2>
<p>Além de get e set, Proxy oferece 13 traps diferentes. Para frameworks robustos, você precisa controlar deleteProperty, has, ownKeys e defineProperty. Vamos criar um sistema com validação:</p>
<pre><code class="language-javascript">function createModel(schema) {
return new Proxy({}, {
get(target, prop) {
return Reflect.get(target, prop);
},
set(target, prop, valor) {
const regra = schema[prop];
if (!regra) {
throw new Error(Propriedade inválida: ${prop});
}
if (regra.type && typeof valor !== regra.type) {
throw new TypeError(
${prop} deve ser ${regra.type}, recebeu ${typeof valor}
);
}
if (regra.validate && !regra.validate(valor)) {
throw new Error(Validação falhou para ${prop});
}
return Reflect.set(target, prop, valor);
},
deleteProperty(target, prop) {
if (schema[prop]?.required) {
throw new Error(Não pode deletar propriedade obrigatória: ${prop});
}
return Reflect.deleteProperty(target, prop);
}
});
}
// Exemplo de uso
const user = createModel({
email: {
type: 'string',
required: true,
validate: (v) => v.includes('@')
},
idade: {
type: 'number',
validate: (v) => v >= 18
}
});
user.email = 'test@example.com'; // OK
user.idade = 25; // OK
user.idade = 15; // Erro: Validação falhou
delete user.email; // Erro: Não pode deletar propriedade obrigatória</code></pre>
<p>Esta abordagem permite criar camadas de validação e segurança que aplicam regras de negócio automaticamente, essencial em aplicações complexas.</p>
<h2>Performance e Padrões Avançados</h2>
<p>Proxies têm custo de performance. Em frameworks reativos, você não cria um Proxy para cada propriedade — cria um por objeto raiz. Para estruturas aninhadas, você precisa decidir: fazer Proxies profundos (recursivos) ou raso (shallow).</p>
<pre><code class="language-javascript">class ReactiveDeep {
constructor(data) {
this.watchers = new Map();
this.currentEffect = null;
return this.wrap(data);
}
wrap(target) {
if (typeof target !== 'object' || target === null) {
return target;
}
return new Proxy(target, {
get: (obj, prop) => {
if (this.currentEffect) {
const key = ${prop};
if (!this.watchers.has(key)) {
this.watchers.set(key, new Set());
}
this.watchers.get(key).add(this.currentEffect);
}
const valor = Reflect.get(obj, prop);
// Envolver objetos aninhados também
return typeof valor === 'object' && valor !== null
? this.wrap(valor)
: valor;
},
set: (obj, prop, valor) => {
const resultado = Reflect.set(obj, prop, valor);
if (this.watchers.has(prop)) {
this.watchers.get(prop).forEach(cb => cb());
}
return resultado;
}
});
}
effect(fn) {
this.currentEffect = fn;
fn();
this.currentEffect = null;
}
}
const app = new ReactiveDeep({
user: { perfil: { nome: 'Ana' } }
});
app.effect(() => {
console.log(app.user.perfil.nome);
});
app.user.perfil.nome = 'Bruno'; // Dispara efeito</code></pre>
<blockquote><p><strong>Dica de produção:</strong> Para aplicações muito grandes, considere lazy-wrapping e memoização de Proxies para evitar recriá-los constantemente.</p></blockquote>
<h2>Conclusão</h2>
<p>Dominando Proxy e Reflect, você consegue: <strong>(1)</strong> Interceptar todas operações em objetos e implementar reatividade automática, fundação de frameworks modernos; <strong>(2)</strong> Aplicar validação, transformação e segurança em tempo real sem código repetitivo; <strong>(3)</strong> Entender como Vue.js, MobX e bibliotecas similares funcionam internamente, permitindo debug e otimização sofisticada.</p>
<p>A chave é começar simples (rastreamento básico), depois adicionar validação e estruturas aninhadas. Em produção, sempre considere performance — Proxies são poderosos mas têm custo.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Proxy" target="_blank" rel="noopener noreferrer">MDN Web Docs - Proxy</a></li>
<li><a href="https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Reflect" target="_blank" rel="noopener noreferrer">MDN Web Docs - Reflect</a></li>
<li><a href="https://vuejs.org/guide/extras/reactivity-in-depth.html" target="_blank" rel="noopener noreferrer">Vue.js 3 - Reactivity in Depth</a></li>
<li><a href="https://javascript.info/proxy" target="_blank" rel="noopener noreferrer">JavaScript.info - Proxy e Reflect</a></li>
<li><a href="https://eloquentjavascript.net/13_modules.html" target="_blank" rel="noopener noreferrer">Eloquent JavaScript - Capítulo sobre Metaprogramming</a></li>
</ul>