Movatterモバイル変換


[0]ホーム

URL:


MDN Web Docs

Esta página ha sido traducida del inglés por la comunidad. Aprende más y únete a la comunidad de MDN Web Docs.

Metaprogramación

A partir de ECMAScript 2015, JavaScript gana soporte para los objetosProxy yReflect 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.

Proxies

Introducidos en ECMAScript 6, los objetosProxy te permiten interceptar ciertas operaciones e implementar comportamientos personalizados.

Por ejemplo, obtener una propiedad sobre un objeto:

js
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 objetoProxy define untarget (un objeto vacío aquí) y un objetohandler, en el que se implementa ungettrap. Aquí, un objeto que es proxy no devolveráundefined cuando obtenga propiedades indefinidas, sino que devolverá el número42.

Hay ejemplos adicionales disponibles en la página de referenciaProxy.

Terminología

Los siguientes términos se utilizan cuando se habla de la funcionalidad de los proxies.

handler

Objeto marcador de posición que contiene trampas.

traps

Los métodos que proporcionan acceso a la propiedad. (Esto es análogo al concepto detrampas en los sistemas operativos).

target

Objeto que virtualiza el proxy. A menudo se utiliza como interfaz de administración de almacenamiento para el proxy. Las invariantes (semántica que permanece sin cambios) con respecto a la no extensibilidad del objeto o las propiedades no configurables se verifican con eltarget.

invariants

La semántica que permanece sin cambios al implementar operaciones personalizadas se denominaninvariants. Si violas las invariantes de un controlador, se lanzará unTypeError.

Controladores y trampas

La siguiente tabla resume las trampas disponibles para los objetosProxy. Ve laspáginas de referencia para explicaciones detalladas y ejemplos.

Controlador/TrampaIntercepcionesInvariantes
handler.getPrototypeOf()Object.getPrototypeOf()
Reflect.getPrototypeOf()
__proto__
Object.prototype.isPrototypeOf()
instanceof
  • El métodogetPrototypeOf regresa un objeto onull.
  • Sitarget no es extensible, el métodoObject.getPrototypeOf(proxy) debe devolver el mismo valor queObject.getPrototypeOf(target).
handler.setPrototypeOf()Object.setPrototypeOf()
Reflect.setPrototypeOf()
Sitarget no es extensible, el parámetroprototype debe tener el mismo valor queObject.getPrototypeOf(target).
handler.isExtensible()Object.isExtensible()
Reflect.isExtensible()
Object.isExtensible(proxy) debe devolver el mismo valor queObject.isExtensible(target).
handler.preventExtensions()Object.preventExtensions()
Reflect.preventExtensions()
Object.preventExtensions(proxy) solo devuelvetrue siObject.isExtensible(proxy) esfalse.
handler.getOwnPropertyDescriptor()Object.getOwnPropertyDescriptor()
Reflect.getOwnPropertyDescriptor()
  • getOwnPropertyDescriptor debe devolver un objeto oundefined.
  • Una propiedad no se puede reportar como inexistente si existe como una propiedad propia no configurable detarget.
  • Una propiedad no se puede reportar como inexistente si existe como propiedad propia detarget ytarget no es extensible.
  • Una propiedad no se puede reportar como existente si no existe como una propiedad propia detarget ytarget no es extensible.
  • No se puede reportar una propiedad como no configurable si no existe como propiedad propia detarget o si existe como propiedad propia configurable detarget.
  • El resultado deObject.getOwnPropertyDescriptor(target) se puede aplicar atarget usandoObject.defineProperty y no lanzará una excepción.
handler.defineProperty()Object.defineProperty()
Reflect.defineProperty()
  • No se puede agregar una propiedad sitarget no es extensible.
  • Una propiedad no se puede agregar como (o modificar para ser) no configurable si no existe como una propiedad propia no configurable detarget.
  • Una propiedad no puede ser no configurable si existe una propiedad configurable correspondiente detarget.
  • Si una propiedad tiene una propiedad de objetotarget correspondiente, entoncesObject.defineProperty(target,prop,descriptor) no lanzará una excepción.
  • En modo estricto, un valorfalse devuelto por el controladordefineProperty lanzará una excepciónTypeError.
handler.has()
Consulta de propiedad
foo in proxy
Consulta de propiedad heredada
foo in Object.create(proxy)
Reflect.has()
  • Una propiedad no se puede reportar como inexistente, si existe como una propiedad propia no configurable detarget.
  • Una propiedad no se puede reportar como inexistente si existe como propiedad propia detarget ytarget no es extensible.
handler.get()
Acceso a la propiedad
proxy[foo]
proxy.bar
Acceso a propiedad heredada
Object.create[proxy](foo)
Reflect.get()
  • El valor reportado para una propiedad debe ser el mismo que el valor de la propiedadtarget correspondiente si la propiedad detarget es una propiedad de datos de solo lectura y no es configurable.
  • El valor reportado para una propiedad debe serundefined si la propiedadtarget correspondiente es una propiedad de acceso no configurable que tieneundefined como su atributo[[Get]].
handler.set()
Asignación de propiedad
proxy[foo] = bar
proxy.foo = bar
Asignación de propiedad heredada
Object.create[proxy](foo) = bar
{jsxref("Reflect.set()")}}
  • No se puede cambiar el valor de una propiedad para que sea diferente del valor de la propiedadtarget correspondiente si la propiedadtarget correspondiente es una propiedad de datos de solo lectura y no es configurable.
  • No se puede establecer el valor de una propiedad si la propiedadtarget correspondiente es una propiedad de acceso no configurable que tieneundefined como su atributo[[Get]].
  • En modo estricto, un valor de retornofalse del controladorset arrojará una excepciónTypeError.
handler.deleteProperty()
Eliminación de propiedad
deleteproxy[foo]
deleteproxy.foo
Reflect.deleteProperty()
Una propiedad no se puede eliminar si existe como una propiedad propia no configurable detarget.
handler.enumerate()
Enumeración de propiedad/for...in:
for (let name inproxy) {...}
Reflect.enumerate()
El métodoenumerate debe devolver un objeto.
handler.ownKeys()Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Object.keys()
Reflect.ownKeys()
  • El resultado deownKeys es una lista.
  • El Tipo de cada elemento de la Lista de resultados esString oSymbol.
  • La Lista de resultados debe contener las claves de todas las propiedades propias no configurables detarget.
  • Si el objetotarget no es extensible, entonces la Lista de resultados debe contener todas las claves de las propiedades propias detarget y ningún otro valor.
handler.apply()proxy(..args)
Function.prototype.apply() yFunction.prototype.call()
Reflect.apply()
No hay invariantes para el métodohandler.apply.
handler.construct()new proxy(...args)
Reflect.construct()
El resultado debe ser unObjeto.

Proxy revocable

El métodoProxy.revocable() se usa para crear un objetoProxy revocable. Esto significa que el proxy se puede revocar mediante la funciónrevoke y apagar el proxy.

Posteriormente, cualquier operación en el proxy conduce a unTypeError.

js
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 TypeErrorproxy.foo = 1; // TypeError nuevamentedelete proxy.foo; // todavía TypeErrortypeof proxy; // "object", typeof no activa ninguna trampa

Reflexión

Reflect es un objeto integrado que proporciona métodos para operaciones JavaScript interceptables. Los métodos son los mismos que los deproxy handlers.

Reflect no es un objeto función.

Reflect ayuda con el reenvío de las operaciones predeterminadas del controlador altarget.

ConReflect.has() por ejemplo, obtienes el operadorin como función:

js
Reflect.has(Object, "assign"); // true

Una mejor funciónapply

En ES5, normalmente usas el métodoFunction.prototype.apply() para llamar a una función con un valorthis yarguments proporcionado como un arreglo (o unobjeto similar a un arreglo).

js
Function.prototype.apply.call(Math.floor, undefined, [1.75]);

ConReflect.apply esto se vuelve menos detallado y más fácil de entender:

js
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;// 4Reflect.apply("".charAt, "ponies", [3]);// "i"

Comprobando si la definición de la propiedad ha sido exitosa

ConObject.defineProperty, que devuelve un objeto si tiene éxito, o arroja unTypeError de lo contrario, usaría un bloquetry...catch para detectar cualquier error que haya ocurrido al definir una propiedad. Debido a queReflect.defineProperty devuelve un estado de éxito booleano, aquí puedes usar un bloqueif...else:

js
if (Reflect.defineProperty(target, property, attributes)) {  // éxito} else {  // fracaso}

Help improve MDN

Learn how to contribute.

This page was last modified on byMDN contributors.


[8]ページ先頭

©2009-2025 Movatter.jp