Esta página foi traduzida do inglês pela comunidade.Saiba mais e junte-se à comunidade MDN Web Docs.
Meta programação
Começando com ECMAScript 6, o JavaScript ganha suporte para os objetosProxy eReflect, 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ívelmeta em JavaScript.
In this article
Proxies
Introduzido em ECMAScript 6, objetosProxy 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, 42O objeto Proxy define umtarget (um objeto vazio aqui) e um objetohandler em que umgettrap é 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 deProxy .
Terminologia
Os seguintes termos são usados quando se fala sobre a funcionalidade de proxies.
- handler
Espaço reservado de objeto que contenha traps.
- traps
Os métodos que fornecem acesso de propriedade. Isto é análogo ao conceito de traps em sistemas operacionais.
- target
Objeto que o proxy está virtualizando. Ele é frequentemente usado como backend de armazenamento para o proxy. Invariantes (semânticas que permanecem inalteradas) relativas a objetos que não podem ser extendidos ou propriedades que não podem ser configuradas são comparadas com o target.
- invariantes
Semânticas que permanecem inalteradas na execução de operações personalizadas são chamados deinvariantes. Se você violar as invariantes de um manipulador, um
TypeErrorserá lançado.
Handlers e traps
A tabela a seguir resume as traps disponíveis aos objetos do tipo Proxy. Veja aspáginas de referência para explicações detalhadas e exemplos.
| Handler / trap | Interceptions | Invariants |
|---|---|---|
handler.getPrototypeOf() | Object.getPrototypeOf()Reflect.getPrototypeOf()__proto__Object.prototype.isPrototypeOf()instanceof |
|
handler.setPrototypeOf() | Object.setPrototypeOf()Reflect.setPrototypeOf() | Se |
handler.isExtensible() | Object.isExtensible()Reflect.isExtensible() | Object.isExtensible(proxy) deve retornar o mesmo valor queObject.isExtensible(target). |
handler.preventExtensions() | Object.preventExtensions()Reflect.preventExtensions() | Object.preventExtensions(proxy) retornatrue somente seObject.isExtensible(proxy) retornarfalse. |
handler.getOwnPropertyDescriptor() | Object.getOwnPropertyDescriptor()Reflect.getOwnPropertyDescriptor() |
|
handler.defineProperty() | Object.defineProperty()Reflect.defineProperty() |
|
handler.has() | Property query:foo in proxyInherited property query: foo in Object.create(proxy)Reflect.has() |
|
handler.get() | 1 Property access:proxy[foo]andproxy.barInherited property access: Object.create(proxy)[foo]Reflect.get() |
|
handler.set() | Property assignment:proxy[foo] = bar andproxy.foo = barInherited property assignment: Object.create(proxy)[foo] = barReflect.set() |
|
handler.deleteProperty() | Property deletion:delete proxy[foo] anddelete proxy.fooReflect.deleteProperty() | Uma propriedade não pode ser excluída, se existir como uma propriedade própria não configurável do objeto de destino. |
handler.enumerate() | Property enumeration / for...in:for (var name in proxy) {...}Reflect.enumerate() | O método |
handler.ownKeys() | Object.getOwnPropertyNames()Object.getOwnPropertySymbols()Object.keys()Reflect.ownKeys() |
|
handler.apply() | proxy(..args)Function.prototype.apply() andFunction.prototype.call()Reflect.apply() | Não há invariantes para o método |
handler.construct() | new proxy(...args)Reflect.construct() | O resultado deve ser umObject. |
Proxy Revogável
O métodoProxy.revocable() é utilizado para criar um objeto Proxy revogável. Isso significa que o proxy pode ser revogado através da funçãorevoke, desligando-o. Depois disso, qualquer operação com o proxy lançará umTypeError.
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çadoproxy.foo = 1; // TypeError novamentedelete proxy.foo; // ainda um TypeErrortypeof proxy; // "object", typeof não desencadeia nenhuma trapReflexão
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 deproxy handlers.Reflect não é um objeto do tipo function.
Reflect auxilia no encaminhamento de operações padrão do handler para o target.
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"); // trueUma funçãoapply melhorada
Em ES5, você normalmente utiliza o métodoFunction.prototype.apply() para invocar uma função com um dado valor parathis earguments fornecido como um array (ou umobjeto parecido com um array).
Function.prototype.apply.call(Math.floor, undefined, [1.75]);ComReflect.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;// 4Reflect.apply("".charAt, "ponies", [3]);// "i"Verificando se a definição da propriedade obteve sucesso
ComObject.defineProperty, a qual retorna umobject em caso de sucesso ou lança umTypeError em caso contrário, você utilizaria um blocotry...catch para capturar qualquer erro que tenha ocorrido ao definir uma propriedade. Devido ao fato deReflect.defineProperty retornar um status do tipoBoolean, você pode simplesmente utilizar aqui um blocoif...else:
if (Reflect.defineProperty(target, property, attributes)) { // success} else { // failure}