Movatterモバイル変換


[0]ホーム

URL:


  1. Tecnología web para desarrolladores
  2. JavaScript
  3. Referencia de JavaScript
  4. Objetos globales
  5. Proxy

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

View in EnglishAlways switch to English

Proxy

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since ⁨septiembre de 2016⁩.

El objetoProxy permite crear un intermediario para otro objeto, el cualpuede interceptar y redefinir operaciones fundamentales para dicho objeto.

Descripción

UnProxy se crea con dos parámetros:

  • target: el objeto original que se quiere envolver.
  • handler: un objeto que define cuáles operaciones serán interceptadas y cómoredefinir dichas operaciones.

Por ejemplo, este código define un objeto simple que tiene solo dos propiedades,y un manipulador más simple aún que no tiene propiedades:

js
const target = {  message1: "hello",  message2: "everyone",};const handler1 = {};const proxy1 = new Proxy(target, handler1);

Ya que el manipulador está vacío, este proxy se comporta justo como el objetooriginal:

js
console.log(proxy1.message1); // helloconsole.log(proxy1.message2); // everyone

Para personalizar el intermediario, definimos funciones en el objetomanipulador:

js
const target = {  message1: "hello",  message2: "everyone",};const handler2 = {  get: function (target, prop, receiver) {    return "world";  },};const proxy2 = new Proxy(target, handler2);

Aquí hemos provisto una implementación del manipuladorget(), el cual intercepta losintentos de acceder a las propiedades del objeto envuelto.

Las funciones manipuladoras son llamadas a menudotrampas, probablementeporque atrapan las llamadas al objeto envuelto. La trampa simple de arriba enhandler2 redefine todos los accesores de propiedades:

js
console.log(proxy2.message1); // worldconsole.log(proxy2.message2); // world

Con la ayuda de la claseReflect podemos darle a algunos accesoresel comportamiento original y redefinir otros:

js
const target = {  message1: "hello",  message2: "everyone",};const handler3 = {  get: function (target, prop, receiver) {    if (prop === "message2") {      return "world";    }    return Reflect.get(...arguments);  },};const proxy3 = new Proxy(target, handler3);console.log(proxy3.message1); // helloconsole.log(proxy3.message2); // world

Constructor

Proxy()

Crea un nuevo objetoProxy.

Métodos estáticos

Proxy.revocable()

Crea un objetoProxy revocable.

Ejemplos

Ejemplo básico

En este ejemplo, el número37 es devuelto como valor pordefecto cuando elnombre de propiedad no está en el objeto. Se realiza usando el manipuladorget().

js
const handler = {  get: function (obj, prop) {    return prop in obj ? obj[prop] : 37;  },};const p = new Proxy({}, handler);p.a = 1;p.b = undefined;console.log(p.a, p.b);//  1, undefinedconsole.log("c" in p, p.c);//  false, 37

Proxy sin modificaciones

En este ejemplo se usa un objeto nativo de JavaScript para el cual elproxyreenviará todas las operaciones que se le apliquen.

js
const target = {};const p = new Proxy(target, {});p.a = 37;//  operación reenviada al objeto envueltoconsole.log(target.a);//  37//  (¡La operación ha sido reenviada correctamente!)

Nótese que mientras que esto funciona para objetos JavaScript, no lo hace paraobjetos nativos del navegador como Elementos del DOM.

Validación

Con unProxy, puedes puedes validar fácilmente el valor enviado para unobjeto. Este ejemplo usa el manipuladorset().

js
let validator = {  set: function (obj, prop, value) {    if (prop === "age") {      if (!Number.isInteger(value)) {        throw new TypeError("La edad no es un entero");      }      if (value > 200) {        throw new RangeError("La edad parece inválida");      }    }    // El comportamiento por defecto es almacenar el valor    obj[prop] = value;    // Indica éxito    return true;  },};const person = new Proxy({}, validator);person.age = 100;console.log(person.age); // 100person.age = "young"; // Lanza una excepciónperson.age = 300; // Lanza una excepción

Extendiendo el constructor

Una función intermediaria podría fácilmente extender un constructor con un nuevoconstructor. Este ejemplo usa los manipuladoresconstruct() yapply().

js
function extend(sup, base) {  base.prototype = Object.create(sup.prototype);  base.prototype.constructor = new Proxy(base, {    construct: function (target, args) {      var obj = Object.create(base.prototype);      this.apply(target, obj, args);      return obj;    },    apply: function (target, that, args) {      sup.apply(that, args);      base.apply(that, args);    },  });  return base.prototype.constructor;}var Person = function (name) {  this.name = name;};var Boy = extend(Person, function (name, age) {  this.age = age;});Boy.prototype.gender = "M";var Peter = new Boy("Peter", 13);console.log(Peter.gender); // "M"console.log(Peter.name); // "Peter"console.log(Peter.age); // 13

Manipulando nodos del DOM

A veces querrás alternar algún atributo o clase de dos elementos distintos. Eneste ejemplo se explica cómo lo puedes hacer usando el manipuladorset().

js
let view = new Proxy({  selected: null},{  set: function(obj, prop, newval) {    let oldval = obj[prop];    if (prop === 'selected') {      if (oldval) {        oldval.setAttribute('aria-selected', 'false');      }      if (newval) {        newval.setAttribute('aria-selected', 'true');      }    }    // El comportamiento por defecto es almacenar el valor    obj[prop] = newval;    // Indica éxito    return true;  }});let i1 = view.selected = document.getElementById('item-1');  //da error aquí, i1 es nullconsole.log(i1.getAttribute('aria-selected'));//  'true'let i2 = view.selected = document.getElementById('item-2');console.log(i1.getAttribute('aria-selected'));//  'false'console.log(i2.getAttribute('aria-selected'));//  'true'Note: even if selected: !null, then giving oldval.setAttribute is not a function

Corrección de valor y una propiedad extra

El objeto intermediarioproducts evalúa el valor pasado y lo convierte en unarray de ser necesario. El objeto también soporta una propiedad extra llamadalatestBrowser tanto comogetter y comosetter.

js
let products = new Proxy(  {    browsers: ["Internet Explorer", "Netscape"],  },  {    get: function (obj, prop) {      // Una propiedad extra      if (prop === "latestBrowser") {        return obj.browsers[obj.browsers.length - 1];      }      // El comportamiento por defecto es retornar el valor      return obj[prop];    },    set: function (obj, prop, value) {      // Una propiedad extra      if (prop === "latestBrowser") {        obj.browsers.push(value);        return true;      }      // Convierte el valor si no es un array      if (typeof value === "string") {        value = [value];      }      // El comportamiento por defecto es almacenar el valor      obj[prop] = value;      // Indica éxito      return true;    },  },);console.log(products.browsers);//  ['Internet Explorer', 'Netscape']products.browsers = "Firefox";//  pasa una cadena (por error)console.log(products.browsers);//  ['Firefox'] <- no hay problema, el valor es un arregloproducts.latestBrowser = "Chrome";console.log(products.browsers);//  ['Firefox', 'Chrome']console.log(products.latestBrowser);//  'Chrome'

Buscando un elemento de un arreglo por su propiedad

Esteproxy extiende un arreglo con ciertas funcionalidades utilitarias. Comose puede ver, puedes "definir" propiedades de manera flexible sin usarObject.defineProperties(). Este ejemplose puede adaptar para encontrar una fila de una tabla por su celda. En dichocaso, el target seríatable.rows.

js
let products = new Proxy(  [    { name: "Firefox", type: "browser" },    { name: "SeaMonkey", type: "browser" },    { name: "Thunderbird", type: "mailer" },  ],  {    get: function (obj, prop) {      // El comportamiento por defecto es retornar al valor; prop generalmente es un número      if (prop in obj) {        return obj[prop];      }      // Obtiene el número de productos; un alias de products.length      if (prop === "number") {        return obj.length;      }      let result,        types = {};      for (let product of obj) {        if (product.name === prop) {          result = product;        }        if (types[product.type]) {          types[product.type].push(product);        } else {          types[product.type] = [product];        }      }      // Obtiene un producto por su nombre      if (result) {        return result;      }      // Obtiene productos por tipo      if (prop in types) {        return types[prop];      }      // Obtiene los tipos de productos      if (prop === "types") {        return Object.keys(types);      }      return undefined;    },  },);console.log(products[0]); // { name: 'Firefox', type: 'browser' }console.log(products["Firefox"]); // { name: 'Firefox', type: 'browser' }console.log(products["Chrome"]); // undefinedconsole.log(products.browser); // [{ name: 'Firefox', type: 'browser' }, { name: 'SeaMonkey', type: 'browser' }]console.log(products.types); // ['browser', 'mailer']console.log(products.number); // 3

Un ejemplo con todas lastrampas

Para crear un ejemplo con la lista completa detrampas, con motivosdidácticos, intentaremos intervenir un objetono-nativo que se ajustaparticularmente a este tipo de operación: el objeto globaldocCookies creadoporun simple marco de cookies.

js
/*  var docCookies = ... obtén el objeto "docCookies" aquí:  https://reference.codeproject.com/dom/document/cookie/simple_document.cookie_framework*/var docCookies = new Proxy(docCookies, {  get: function (oTarget, sKey) {    return oTarget[sKey] || oTarget.getItem(sKey) || undefined;  },  set: function (oTarget, sKey, vValue) {    if (sKey in oTarget) {      return false;    }    return oTarget.setItem(sKey, vValue);  },  deleteProperty: function (oTarget, sKey) {    if ((!sKey) in oTarget) {      return false;    }    return oTarget.removeItem(sKey);  },  ownKeys: function (oTarget, sKey) {    return oTarget.keys();  },  has: function (oTarget, sKey) {    return sKey in oTarget || oTarget.hasItem(sKey);  },  defineProperty: function (oTarget, sKey, oDesc) {    if (oDesc && "value" in oDesc) {      oTarget.setItem(sKey, oDesc.value);    }    return oTarget;  },  getOwnPropertyDescriptor: function (oTarget, sKey) {    var vValue = oTarget.getItem(sKey);    return vValue      ? {          value: vValue,          writable: true,          enumerable: true,          configurable: false,        }      : undefined;  },});/* Pruebas de cookies */console.log((docCookies.my_cookie1 = "Primer valor"));console.log(docCookies.getItem("my_cookie1"));docCookies.setItem("my_cookie1", "Valor cambiado");console.log(docCookies.my_cookie1);

Especificaciones

Specification
ECMAScript® 2026 Language Specification
# sec-proxy-objects

Compatibilidad con navegadores

Véase también

Help improve MDN

Learn how to contribute

This page was last modified on byMDN contributors.


[8]ページ先頭

©2009-2025 Movatter.jp