Esta tradução está incompleta. Ajude atraduzir este artigo.
Começando com ECMAScript 6, JavaScript ganha apoio para o Proxy
e Reflect
objetos, permitindo que você para interceptar e definir o comportamento personalizado para operações de linguagem fundamentais (por exemplo, pesquisa de propriedade, cessão, enumeração, a função de chamada, etc). Com a ajuda destes dois objetos que são capazes de programar a nível meta de JavaScript.
Proxies
introduzido em ECMAScript 6, Proxy
objetos permitem que você intercepte determinadas operações e implementa comportamentos personalizados. Por exemplo recebendo uma propriedade em um objeto:
var handler = { get: function(target, nome){ return name in target ? target[nome] : 42; }}; var p = new Proxy({}, handler); p.a = 1; console.log(p.a, p.b); // 1, 42
O objeto Proxy define um alvo (um objeto aqui) e um handler objeto em que um get
trap é implementado. Aqui, um objeto que está em proxy não retornará indefinido quando chegar propriedades indefinidas, mas, ao contrário, retornar o número 42.
Exemplos adicionais estão disponíveis na Proxy
pagina de referência.
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 virtualiza o proxy. Ele é frequentemente usado como back-end de armazenamento para o proxy. Invariantes (semântica que permanecem inalteradas) relativas objeto não-extensibilidade ou propriedades de não-configuráveis são verificados contra o alvo.
- invariantes
- Semântica que permanecem inalteradas na execução de operações personalizadas são chamados de invariantes. Se você violar as invariantes de um manipulador, um
TypeError
será lançada.
Handlers e traps
The following table summarizes the available traps available to Proxy
objects. See the reference pages for detailed explanations and examples.
Handler / trap | Interceptions | Invariants |
---|---|---|
handler.getPrototypeOf() |
Object.getPrototypeOf() Reflect.getPrototypeOf() __proto__ Object.prototype.isPrototypeOf() instanceof |
|
handler.setPrototypeOf() |
Object.setPrototypeOf() Reflect.setPrototypeOf() |
If target is not extensible, the prototype parameter must be the same value as Object.getPrototypeOf(target) . |
handler.isExtensible() |
Object.isExtensible() Reflect.isExtensible() |
Object.isExtensible(proxy) must return the same value as Object.isExtensible(target) . |
handler.preventExtensions() |
Object.preventExtensions() Reflect.preventExtensions() |
Object.preventExtensions(proxy) only returns true if Object.isExtensible(proxy) is false . |
handler.getOwnPropertyDescriptor() |
Object.getOwnPropertyDescriptor() Reflect.getOwnPropertyDescriptor() |
|
handler.defineProperty() |
Object.defineProperty() Reflect.defineProperty() |
|
handler.has() |
Property query: foo in proxy Inherited property query: foo in Object.create(proxy) Reflect.has() |
|
handler.get() |
Property access: proxy[foo] and proxy.bar Inherited property access: Object.create(proxy)[foo] Reflect.get() |
|
handler.set() |
Property assignment: proxy[foo] = bar and proxy.foo = bar Inherited property assignment: Object.create(proxy)[foo] = bar Reflect.set() |
|
handler.deleteProperty() |
Property deletion: delete proxy[foo] and delete proxy.foo Reflect.deleteProperty() |
A property cannot be deleted, if it exists as a non-configurable own property of the target object. |
handler.enumerate() |
Property enumeration / for...in: for (var name in proxy) {...} Reflect.enumerate() |
The enumerate method must return an object. |
handler.ownKeys() |
Object.getOwnPropertyNames() Object.getOwnPropertySymbols() Object.keys() Reflect.ownKeys() |
|
handler.apply() |
proxy(..args) Function.prototype.apply() and Function.prototype.call() Reflect.apply() |
There are no invariants for the handler.apply method. |
handler.construct() |
new proxy(...args) Reflect.construct() |
The result must be an Object . |
Revocable Proxy
The Proxy.revocable()
method is used to create a revocable Proxy
object. This means that the proxy can be revoked via the function revoke
and switches the proxy off. Afterwards, any operation leads on the proxy leads to a 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 is thrown proxy.foo = 1 // TypeError again delete proxy.foo; // still TypeError typeof proxy // "object", typeof doesn't trigger any trap
Reflection
Reflect
is a built-in object that provides methods for interceptable JavaScript operations. The methods are the same as those of the proxy handlers. Reflect
is not a function object.
Reflect
helps with forwarding default operations from the handler to the target.
With Reflect.has()
for example, you get the in
operator as a function:
Reflect.has(Object, "assign"); // true
A better apply
function
In ES5, you typically use the Function.prototype.apply()
method to call a function with a given this
value and arguments
provided as an array (or an array-like object).
Function.prototype.apply.call(Math.floor, undefined, [1.75]);
With Reflect.apply
this becomes less verbose and easier to understand:
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"
Checking if property definition has been successful
With Object.defineProperty
, which returns an object if successful, or throws a TypeError
otherwise, you would use a try...catch
block to catch any error that occurred while defining a property. Because Reflect.defineProperty
returns a Boolean success status, you can just use an if...else
block here:
if (Reflect.defineProperty(target, property, attributes)) { // success } else { // failure }