--- title: Proxy slug: Web/JavaScript/Reference/Global_Objects/Proxy translation_of: Web/JavaScript/Reference/Global_Objects/Proxy ---
var p = new Proxy(target, handler);
targethandlerL'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.