--- title: Metaprogramación slug: Web/JavaScript/Guide/Meta_programming tags: - ECMAScript 2015 - Guía - JavaScript - Proxy - Reflejar - 'l10n:priority' translation_of: Web/JavaScript/Guide/Meta_programming ---
A partir de ECMAScript 2015, JavaScript gana soporte para los objetos {{jsxref("Proxy")}} y {{jsxref("Reflect")}} lo cual te permite interceptar y definir un comportamiento personalizado para las operaciones fundamentales del lenguaje (por ejemplo, búsqueda de propiedades, asignación, enumeración, invocación de funciones, etc.). Con la ayuda de estos dos objetos, puedes programar en el metanivel de JavaScript.
Introducidos en ECMAScript 6, los objetos {{jsxref("Proxy")}} te permiten interceptar ciertas operaciones e implementar comportamientos personalizados.
Por ejemplo, obtener una propiedad sobre un objeto:
let handler = { get: function(target, name) { return name in target? target[name] : 42 } } let p = new Proxy({}, handler) p.a = 1 console.log(p.a, p.b) // 1, 42
El objeto Proxy
define un target
(un objeto vacío aquí) y un objeto handler
, en el que se implementa un get
trap. Aquí, un objeto que es proxy no devolverá undefined
cuando obtenga propiedades indefinidas, sino que devolverá el número 42
.
Hay ejemplos adicionales disponibles en la página de referencia {{jsxref("Proxy")}}.
Los siguientes términos se utilizan cuando se habla de la funcionalidad de los proxies.
target
.La siguiente tabla resume las trampas disponibles para los objetos Proxy
. Ve las páginas de referencia para explicaciones detalladas y ejemplos.
Controlador/Trampa | Intercepciones | Invariantes |
---|---|---|
{{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()")}} |
Si target no es extensible, el parámetro prototype debe tener el mismo valor que Object.getPrototypeOf(target) . |
{{jsxref("Global_Objects/Proxy/handler/is Extensible", "handler.isExtensible()")}} | {{jsxref("Object.isExtensible()")}} {{jsxref("Reflect.isExtensible()")}} |
Object.isExtensible(proxy) debe devolver el mismo valor que Object.isExtensible(target) . |
{{jsxref("Global_Objects/Proxy/handler/preventExtensions", "handler.preventExtensions()")}} | {{jsxref("Object.preventExtensions()")}} {{jsxref("Reflect.preventExtensions()")}} |
Object.preventExtensions(proxy) solo devuelve true si Object.isExtensible(proxy) es 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()")}} |
|
|
{{jsxref("Global_Objects/Proxy/handler/get", "handler.get()")}} |
|
|
{{jsxref("Global_Objects/Proxy/handler/set", "handler.set()")}} |
|
|
{{jsxref("Global_Objects/Proxy/handler/deleteProperty", "handler.deleteProperty()")}} |
|
Una propiedad no se puede eliminar si existe como una propiedad propia no configurable de target . |
{{jsxref("Global_Objects/Proxy/handler/enumerate", "handler.enumerate()")}} |
|
El método enumerate debe devolver un objeto. |
{{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()")}} y {{jsxref("Function.prototype.call()")}} {{jsxref("Reflect.apply()")}} |
No hay invariantes para el método handler.apply . |
{{jsxref("Global_Objects/Proxy/handler/construct", "handler.construct()")}} | new proxy(...args) {{jsxref("Reflect.construct()")}} |
El resultado debe ser un Objeto . |
Proxy
revocableEl método {{jsxref ("Proxy.revocable()")}} se usa para crear un objeto Proxy
revocable. Esto significa que el proxy se puede revocar mediante la función revoke
y apagar el proxy.
Posteriormente, cualquier operación en el proxy conduce a un {{jsxref("TypeError")}}.
let revocable = Proxy.revocable({}, { get: function(target, name) { return '[[' + name + ']]' } }) let proxy = revocable.proxy console.log(proxy.foo) // "[[foo]]" revocable.revoke() console.log(proxy.foo) // Lanza TypeError proxy.foo = 1 // TypeError nuevamente delete proxy.foo // todavía TypeError typeof proxy // "object", typeof no activa ninguna trampa
{{jsxref("Reflect")}} es un objeto integrado que proporciona métodos para operaciones JavaScript interceptables. Los métodos son los mismos que los de {{jsxref ("Global_Objects/Proxy/handler", "proxy handlers", "", "true")}}.
Reflect
no es un objeto función.
Reflect
ayuda con el reenvío de las operaciones predeterminadas del controlador al target
.
Con {{jsxref("Reflect.has()")}} por ejemplo, obtienes el operador in
como función:
Reflect.has(Object, 'assign') // true
apply
En ES5, normalmente usas el método {{jsxref("Function.prototype.apply()")}} para llamar a una función con un valor this
y arguments
proporcionado como un arreglo (o un objeto similar a un arreglo).
Function.prototype.apply.call(Math.floor, undefined, [1.75])
Con {{jsxref("Reflect.apply")}} esto se vuelve menos detallado y más fácil de entender:
Reflect.apply(Math.floor, undefined, [1.75]); // 1; Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]); // "hola" Reflect.apply(RegExp.prototype.exec, /ab/, ["confabulation"]).index; // 4 Reflect.apply("".charAt, "ponies", [3]); // "i"
Con {{jsxref("Object.defineProperty")}}, que devuelve un objeto si tiene éxito, o arroja un {{jsxref("TypeError")}} de lo contrario, usaría un bloque {{jsxref("Statements/try...catch", "try...catch")}} para detectar cualquier error que haya ocurrido al definir una propiedad. Debido a que {{jsxref("Reflect.defineProperty")}} devuelve un estado de éxito booleano, aquí puedes usar un bloque {{jsxref("Statements/if...else", "if...else")}}:
if (Reflect.defineProperty(target, property, attributes)) { // éxito } else { // fracaso }
{{Previous("Web/JavaScript/Guide/Iterators_and_Generators")}}