--- title: Proxy slug: Web/JavaScript/Reference/Global_Objects/Proxy translation_of: Web/JavaScript/Reference/Global_Objects/Proxy ---
{{JSRef}}
L'oggetto Proxy è utilizzato per definire comportamenti personalizzati per operazioni fondamentali (per esempio: ricerca delle proprietà, assegnazione, enumerazione, invocazione delle funzioni, ecc.).

Terminologia

handler
Oggetto placeholder, il quale contiene le trappole.
traps
I metodi che forniscono l'accesso alle proprietà. Questo è analogo al concetto di trappola nei sistemi operativi.
target
Oggetti, che i proxy virtualizzano (sostituiscono). Viene spesso utilizzato come back-end di archiviazione per il proxy. Le invarianti, riguardanti oggetti non estensibili o proprietà non configurabili, sono verificate prima di interagire con l'obiettivo.

Sintassi

var p = new Proxy(target, handler);

Parametri

target
Un oggetto target che il Proxy ingloberà. Può essere un qualsiasi tipo di oggetto, array nativi inclusi, funzioni o anche altri Proxy.
handler
Un oggetto le cui proprietà sono funzioni che definiscono i comportamenti del proxy quando un'operazione viene effettuata su di esso.

Metodi

{{jsxref("Proxy.revocable()")}}
Crea un oggetto Proxy revocabile.

Metodi dell'handler object

L'oggetto handler è un oggetto placeholder, il quale contiene le trappole per il Proxy.

Esempi

Esempio base

In questo esempio base il numero 37 viene restituito come valore di default quando l'oggetto non contiene la proprietà richiesta. Viene utilizzato il get handler.

var handler = {
    get: function(target, name) {
        return name in target ?
            target[name] :
            37;
    }
};

var p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;

console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 37

No-op forwarding proxy

In questo esempio viene utilizzato un semplice oggetto Javascript come target, al quale il proxy inoltrerà tutte le operazioni che sono state applicate su di esso. 

var target = {};
var p = new Proxy(target, {});

p.a = 37; // operazione inoltrata al target

console.log(target.a); // 37. Operazione inoltrata con successo

Validation

Con un proxy, puoi facilmente validare il valore passato per un oggetto. In questo esempio viene utilizzato il  set handler.

let validator = {
  set: function(obj, prop, value) {
    if (prop === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError('L\'età non è un numero intero');
      }
      if (value > 200) {
        throw new RangeError('L\'età sembra non essere valida');
      }
    }

    // Il comportamento di default da adoperare per memorizzare il valore
    obj[prop] = value;

    return true;
  }
};

let person = new Proxy({}, validator);

person.age = 100;
console.log(person.age); // 100
person.age = 'young'; // Lancia una eccezione
person.age = 300; // Lancia una eccezione

Extending constructor

Una funzione proxy può facilmente estendere un costruttore con un nuovo costruttore. Questo esempio usa gli handler: construct e apply .

function extend(sup, base) {
  var descriptor = Object.getOwnPropertyDescriptor(
    base.prototype, 'constructor'
  );
  base.prototype = Object.create(sup.prototype);
  var handler = {
    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);
    }
  };
  var proxy = new Proxy(base, handler);
  descriptor.value = proxy;
  Object.defineProperty(base.prototype, 'constructor', descriptor);
  return proxy;
}

var Person = function(name) {
  this.name = name;
};

var Boy = extend(Person, function(name, age) {
  this.age = age;
});

Boy.prototype.sex = 'M';

var Peter = new Boy('Peter', 13);
console.log(Peter.sex);  // "M"
console.log(Peter.name); // "Peter"
console.log(Peter.age);  // 13

Manipulating DOM nodes

Alcune volte vorresti attivare o disattivare un attributo o una classe di due elementi differenti. Qui è mostrato come è possibile farlo utilizzando il set handler.

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');
      }
    }

    // Il comportamento di default da adoperare per memorizzare il valore
    obj[prop] = newval;

    // Indicate success
    return true;
  }
});

let i1 = view.selected = document.getElementById('item-1');
console.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'

Value correction and an extra property

L'oggetto products  del proxy valuta il valore passato e lo converte in un array se è necessario. L'oggetto supporta anche una proprietà extra chiamata latestBrowser, uttilizzabile sia come getter che come setter.

let products = new Proxy({
  browsers: ['Internet Explorer', 'Netscape']
},
{
  get: function(obj, prop) {
    // An extra property
    if (prop === 'latestBrowser') {
      return obj.browsers[obj.browsers.length - 1];
    }

    // Il comportamento di default per restituire il valore
    return obj[prop];
  },
  set: function(obj, prop, value) {
    // An extra property
    if (prop === 'latestBrowser') {
      obj.browsers.push(value);
      return true;
    }

    // Converte il valore se non è un array
    if (typeof value === 'string') {
      value = [value];
    }

    // Il comportamento di default per memorizzare il valore
    obj[prop] = value;

    // Indicate success
    return true;
  }
});

console.log(products.browsers); // ['Internet Explorer', 'Netscape']
products.browsers = 'Firefox'; // passa una stringa (per sbaglio)
console.log(products.browsers); // ['Firefox'] <- nessun problema, il valore passato è un array

products.latestBrowser = 'Chrome';
console.log(products.browsers); // ['Firefox', 'Chrome']
console.log(products.latestBrowser); // 'Chrome'

Trovare un oggetto in un array dalla sua proprietà

Questo proxy estende un array con alcune caratteristiche utiliti. Come puoi notare, puoi facilmente definire nuove proprietà senza utilizzare Object.defineProperties. Questo esempio può essere adattato per trovare una riga di una tabella partendo dalla sua cella. In questo caso il target sarà table.rows.

let products = new Proxy([
  { name: 'Firefox', type: 'browser' },
  { name: 'SeaMonkey', type: 'browser' },
  { name: 'Thunderbird', type: 'mailer' }
],
{
  get: function(obj, prop) {
    // Il comportamento di default per ritornare un valore; prop è di solito un numero intero
    if (prop in obj) {
      return obj[prop];
    }

    // Ottieni il numero di prodotti; un alias di 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];
      }
    }

    // Ottieni un prodotto dal campo name
    if (result) {
      return result;
    }

    // Ottieni un prodotto dal campo type
    if (prop in types) {
      return types[prop];
    }

    // Ottieni i tipi di prodotto
    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']); // undefined
console.log(products.browser); // [{ name: 'Firefox', type: 'browser' }, { name: 'SeaMonkey', type: 'browser' }]
console.log(products.types); // ['browser', 'mailer']
console.log(products.number); // 3

Una lista completa di traps

Adesso, per creare una lista di trappole, per scopi didattici, proveremo a proxare un oggetto non nativo che è particolarmente adatto a questo tipo di operazioni: l' oggetto globale docCookies creato da the "little framework" published on the document.cookie page.

/*
  var docCookies = ... get the "docCookies" object here:
  https://developer.mozilla.org/en-US/docs/DOM/document.cookie#A_little_framework.3A_a_complete_cookies_reader.2Fwriter_with_full_unicode_support
*/

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);
  },
  enumerate: function (oTarget, sKey) {
    return oTarget.keys();
  },
  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;
  },
});

/* Test dei cookie */

console.log(docCookies.my_cookie1 = 'First value');
console.log(docCookies.getItem('my_cookie1'));

docCookies.setItem('my_cookie1', 'Changed value');
console.log(docCookies.my_cookie1);

Specifiche

Specification Status Comment
{{SpecName('ES2015', '#sec-proxy-objects', 'Proxy')}} {{Spec2('ES2015')}} Definizione iniziale.
{{SpecName('ES2016', '#sec-proxy-objects', 'Proxy')}} {{Spec2('ES2016')}}  
{{SpecName('ES2017', '#sec-proxy-objects', 'Proxy')}} {{Spec2('ES2017')}}  
{{SpecName('ESDraft', '#sec-proxy-objects', 'Proxy')}} {{Spec2('ESDraft')}}  

Compatibilità tra Browser

{{Compat("javascript.builtins.Proxy", 2)}}

Vedi anche

Nota di licenza

Alcuni contentui (test, esempi) in questa pagina sono stati copiati o adattatu dall' ECMAScript wiki i quali contenuti sono sotto licenza CC 2.0 BY-NC-SA.