--- title: Proxy slug: Web/JavaScript/Reference/Global_Objects/Proxy translation_of: Web/JavaScript/Reference/Global_Objects/Proxy ---
var p = new Proxy(target, handler);
target
handler
L'oggetto handler è un oggetto placeholder, il quale contiene le trappole per il Proxy.
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
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
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
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
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'
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'
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
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);
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')}} |
{{Compat("javascript.builtins.Proxy", 2)}}
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.