--- title: Meta programação slug: Web/JavaScript/Guide/Meta_programming translation_of: Web/JavaScript/Guide/Meta_programming ---
Começando com ECMAScript 6, o JavaScript ganha suporte para os objetos {{jsxref("Proxy")}} e {{jsxref("Reflect")}}, permitindo você interceptar e definir o comportamento personalizado para operações fundamentais da linguagem (por exemplo, pesquisa de propriedade, atribuição, enumeração, invocação de função, etc). Com a ajuda destes dois objetos você será capaz de programar a nível meta em JavaScript.
Introduzido em ECMAScript 6, objetos {{jsxref("Proxy")}} permitem que você intercepte determinadas operações e implementar comportamentos personalizados. Por exemplo, receber uma propriedade em um objeto:
var handler = {
get: function(target, name){
return name in target ? target[name] : 42;
}};
var p = new Proxy({}, handler);
p.a = 1;
console.log(p.a, p.b); // 1, 42
O objeto Proxy define um target (um objeto vazio aqui) e um objeto handler em que um get trap é implementado. Aqui, um objeto que está em proxy não retornará indefinido quando receber propriedades indefinidas, mas, ao contrário, retornar o número 42.
Exemplos adicionais estão disponíveis na página de referência de {{jsxref("Proxy")}} .
Os seguintes termos são usados quando se fala sobre a funcionalidade de proxies.
A tabela a seguir resume as traps disponíveis aos objetos do tipo Proxy. Veja as páginas de referência para explicações detalhadas e exemplos.
| Handler / trap | Interceptions | Invariants |
|---|---|---|
| {{jsxref("Global_Objects/Proxy/handler/getPrototypeOf", "handler.getPrototypeOf()")}} | {{jsxref("Object.getPrototypeOf()")}} {{jsxref("Reflect.getPrototypeOf()")}} {{jsxref("Object/proto", "__proto__")}} {{jsxref("Object.prototype.isPrototypeOf()")}} {{jsxref("Operators/instanceof", "instanceof")}} |
|
| {{jsxref("Global_Objects/Proxy/handler/setPrototypeOf", "handler.setPrototypeOf()")}} | {{jsxref("Object.setPrototypeOf()")}} {{jsxref("Reflect.setPrototypeOf()")}} |
Se |
| {{jsxref("Global_Objects/Proxy/handler/isExtensible", "handler.isExtensible()")}} | {{jsxref("Object.isExtensible()")}} {{jsxref("Reflect.isExtensible()")}} |
Object.isExtensible(proxy) deve retornar o mesmo valor que Object.isExtensible(target). |
| {{jsxref("Global_Objects/Proxy/handler/preventExtensions", "handler.preventExtensions()")}} | {{jsxref("Object.preventExtensions()")}} {{jsxref("Reflect.preventExtensions()")}} |
Object.preventExtensions(proxy) retorna true somente se Object.isExtensible(proxy) retornar false. |
| {{jsxref("Global_Objects/Proxy/handler/getOwnPropertyDescriptor", "handler.getOwnPropertyDescriptor()")}} | {{jsxref("Object.getOwnPropertyDescriptor()")}} {{jsxref("Reflect.getOwnPropertyDescriptor()")}} |
|
| {{jsxref("Global_Objects/Proxy/handler/defineProperty", "handler.defineProperty()")}} | {{jsxref("Object.defineProperty()")}} {{jsxref("Reflect.defineProperty()")}} |
|
| {{jsxref("Global_Objects/Proxy/handler/has", "handler.has()")}} | Property query: foo in proxyInherited property query: foo in Object.create(proxy){{jsxref("Reflect.has()")}} |
|
| {{jsxref("Global_Objects/Proxy/handler/get", "handler.get()")}} | Property access: proxy[foo]and proxy.barInherited property access: Object.create(proxy)[foo]{{jsxref("Reflect.get()")}} |
|
| {{jsxref("Global_Objects/Proxy/handler/set", "handler.set()")}} | Property assignment: proxy[foo] = bar and proxy.foo = barInherited property assignment: Object.create(proxy)[foo] = bar{{jsxref("Reflect.set()")}} |
|
| {{jsxref("Global_Objects/Proxy/handler/deleteProperty", "handler.deleteProperty()")}} | Property deletion: delete proxy[foo] and delete proxy.foo{{jsxref("Reflect.deleteProperty()")}} |
Uma propriedade não pode ser excluída, se existir como uma propriedade própria não configurável do objeto de destino. |
| {{jsxref("Global_Objects/Proxy/handler/enumerate", "handler.enumerate()")}} | Property enumeration / for...in: for (var name in proxy) {...}{{jsxref("Reflect.enumerate()")}} |
O método |
| {{jsxref("Global_Objects/Proxy/handler/ownKeys", "handler.ownKeys()")}} | {{jsxref("Object.getOwnPropertyNames()")}} {{jsxref("Object.getOwnPropertySymbols()")}} {{jsxref("Object.keys()")}} {{jsxref("Reflect.ownKeys()")}} |
|
| {{jsxref("Global_Objects/Proxy/handler/apply", "handler.apply()")}} | proxy(..args){{jsxref("Function.prototype.apply()")}} and {{jsxref("Function.prototype.call()")}} {{jsxref("Reflect.apply()")}} |
Não há invariantes para o método |
| {{jsxref("Global_Objects/Proxy/handler/construct", "handler.construct()")}} | new proxy(...args){{jsxref("Reflect.construct()")}} |
O resultado deve ser um Object. |
O método {{jsxref("Proxy.revocable()")}} é utilizado para criar um objeto Proxy revogável. Isso significa que o proxy pode ser revogado através da função revoke, desligando-o. Depois disso, qualquer operação com o proxy lançará um {{jsxref("TypeError")}}.
var revocable = Proxy.revocable({}, {
get: function(target, name) {
return "[[" + name + "]]";
}
});
var proxy = revocable.proxy;
console.log(proxy.foo); // "[[foo]]"
revocable.revoke();
console.log(proxy.foo); // TypeError é lançado
proxy.foo = 1 // TypeError novamente
delete proxy.foo; // ainda um TypeError
typeof proxy // "object", typeof não desencadeia nenhuma trap
{{jsxref("Reflect")}} é um objeto embutido que contém métodos que permitem a criação de operações interceptáveis em JavaScript. Os métodos são iguais àqueles de {{jsxref("Global_Objects/Proxy/handler","proxy handlers","","true")}}. Reflect não é um objeto do tipo function.
Reflect auxilia no encaminhamento de operações padrão do handler para o target.
{{jsxref("Reflect.has()")}}, por exemplo, tem o mesmo efeito prático que o operador in, com a facilidade de ser utilizado como uma função:
Reflect.has(Object, "assign"); // true
apply melhoradaEm ES5, você normalmente utiliza o método {{jsxref("Function.prototype.apply()")}} para invocar uma função com um dado valor para this e arguments fornecido como um array (ou um objeto parecido com um array).
Function.prototype.apply.call(Math.floor, undefined, [1.75]);
Com {{jsxref("Reflect.apply")}} essa operação se torna menos verbosa e mais fácil de compreender:
Reflect.apply(Math.floor, undefined, [1.75]);
// 1;
Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]);
// "hello"
Reflect.apply(RegExp.prototype.exec, /ab/, ["confabulation"]).index;
// 4
Reflect.apply("".charAt, "ponies", [3]);
// "i"
Com {{jsxref("Object.defineProperty")}}, a qual retorna um object em caso de sucesso ou lança um {{jsxref("TypeError")}} em caso contrário, você utilizaria um bloco {{jsxref("Statements/try...catch","try...catch")}} para capturar qualquer erro que tenha ocorrido ao definir uma propriedade. Devido ao fato de {{jsxref("Reflect.defineProperty")}} retornar um status do tipo Boolean, você pode simplesmente utilizar aqui um bloco {{jsxref("Statements/if...else","if...else")}}:
if (Reflect.defineProperty(target, property, attributes)) {
// success
} else {
// failure
}
{{Previous("Web/JavaScript/Guide/Iterators_and_Generators")}}