aboutsummaryrefslogtreecommitdiff
path: root/files/fr/web/javascript/reference/global_objects/proxy/index.html
diff options
context:
space:
mode:
authorFlorian Merz <me@fiji-flo.de>2021-02-11 12:36:08 +0100
committerFlorian Merz <me@fiji-flo.de>2021-02-11 12:36:08 +0100
commit39f2114f9797eb51994966c6bb8ff1814c9a4da8 (patch)
tree66dbd9c921f56e440f8816ed29ac23682a1ac4ef /files/fr/web/javascript/reference/global_objects/proxy/index.html
parent8260a606c143e6b55a467edf017a56bdcd6cba7e (diff)
downloadtranslated-content-39f2114f9797eb51994966c6bb8ff1814c9a4da8.tar.gz
translated-content-39f2114f9797eb51994966c6bb8ff1814c9a4da8.tar.bz2
translated-content-39f2114f9797eb51994966c6bb8ff1814c9a4da8.zip
unslug fr: move
Diffstat (limited to 'files/fr/web/javascript/reference/global_objects/proxy/index.html')
-rw-r--r--files/fr/web/javascript/reference/global_objects/proxy/index.html407
1 files changed, 407 insertions, 0 deletions
diff --git a/files/fr/web/javascript/reference/global_objects/proxy/index.html b/files/fr/web/javascript/reference/global_objects/proxy/index.html
new file mode 100644
index 0000000000..095515482d
--- /dev/null
+++ b/files/fr/web/javascript/reference/global_objects/proxy/index.html
@@ -0,0 +1,407 @@
+---
+title: Proxy
+slug: Web/JavaScript/Reference/Objets_globaux/Proxy
+tags:
+ - ECMAScript 2015
+ - JavaScript
+ - Proxy
+ - Reference
+translation_of: Web/JavaScript/Reference/Global_Objects/Proxy
+---
+<div>{{JSRef}}</div>
+
+<p>L'objet <strong>Proxy</strong> est utilisé afin de définir un comportement sur mesure pour certaines opérations fondamentales (par exemple, l'accès aux propriétés, les affectations, les énumérations, les appels de fonctions, etc.).</p>
+
+<h2 id="Terminologie">Terminologie</h2>
+
+<dl>
+ <dt><a href="/fr/docs/Web/JavaScript/Reference/Objets_globaux/Proxy/handler">gestionnaire</a> (<em>handler</em>)</dt>
+ <dd>Un objet qui contient les trappes qui intercepteront les opérations.</dd>
+ <dt>trappes</dt>
+ <dd>Les méthodes qui fournissent l'accès aux propriétés. Ce concept est analogue aux <a href="https://en.wikipedia.org/wiki/Trap_%28computing%29">trappes</a> utilisées dans les systèmes d'exploitations.</dd>
+ <dt>cible</dt>
+ <dd>L'objet virtualisé par le proxy. Il est souvent utilisé comme objet de stockage. Les invariants (c'est-à-dire les éléments de sémantique qui restent inchangés) relatifs à la non-extensibilité et au caractère non-configurable des propriétés sont vérifiés par rapport à la cible.</dd>
+</dl>
+
+<h2 id="Syntaxe">Syntaxe</h2>
+
+<pre class="syntaxbox">var p = new Proxy(cible, gestionnaire);
+</pre>
+
+<h3 id="Paramètres">Paramètres</h3>
+
+<dl>
+ <dt><code>cible</code></dt>
+ <dd>Une cible (qui peut être n'importe quel objet, un tableau, une fonction, ou même un autre proxy) qu'on souhaite envelopper dans un <code>Proxy</code>.</dd>
+ <dt><code>gestionnaire</code></dt>
+ <dd>Un objet dont les propriétés sont des fonctions qui définissent le comportement du proxy lorsqu'on utilise une opération sur celui-ci.</dd>
+</dl>
+
+<h2 id="Méthodes">Méthodes</h2>
+
+<dl>
+ <dt>{{jsxref("Proxy.revocable()")}}</dt>
+ <dd>Permet de créer un objet <code>Proxy</code> révocable.</dd>
+</dl>
+
+<h2 id="Méthodes_pour_le_gestionnaire">Méthodes pour le gestionnaire</h2>
+
+<p>L'objet utilisé comme gestionnaire regroupe les différentes fonctions « trappes » pour le <code>Proxy</code>.</p>
+
+<div>{{page('/fr/docs/Web/JavaScript/Reference/Objets_globaux/Proxy/handler', 'Méthodes') }}</div>
+
+<h2 id="Exemples">Exemples</h2>
+
+<h3 id="Exemple_simple">Exemple simple</h3>
+
+<p>Dans ce court exemple, on renvoie le nombre <code>37</code> comme valeur par défaut lorsque la propriété nommée n'est pas présente dans l'objet. Pour cela, on utilise le gestionnaire correspondant à {{jsxref("Objets_globaux/Proxy/handler/get","get")}}.</p>
+
+<pre class="brush: js">var handler = {
+ get: function(obj, prop){
+ return prop in obj?
+ obj[prop] :
+ 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
+</pre>
+
+<h3 id="Proxy_«_invisible_»">Proxy « invisible »</h3>
+
+<p>Dans cet exemple, le proxy transfère toutes les opérations qui sont appliquées à l'objet cible.</p>
+
+<pre class="brush: js">var cible = {};
+var p = new Proxy(cible, {});
+
+p.a = 37; // L'opération est transmise à la cible par le proxy
+
+console.log(cible.a); // 37. L'opération a bien été transmise
+</pre>
+
+<h3 id="Validation">Validation</h3>
+
+<p>En utilisant un <code>Proxy</code>, il devient simple de valider les valeurs passées à un objet. Dans cet exemple, on utilise le gestionnaire correspondant à {{jsxref("Objets_globaux/Proxy/handler/set","set")}}.</p>
+
+<pre class="brush: js">let validateur = {
+ set: function(obj, prop, valeur) {
+ if (prop === 'âge') {
+ if (!Number.isInteger(valeur)) {
+ throw new TypeError('Cet âge n\'est pas un entier.');
+ }
+ if (valeur &gt; 200) {
+ throw new RangeError('Cet âge semble invalide.');
+ }
+ }
+
+ // Le comportement par défaut : enregistrer la valeur
+ obj[prop] = valeur;
+
+ // On indique le succès de l'opération
+ return true;
+ }
+};
+
+let personne = new Proxy({}, validateur);
+
+personne.âge = 100;
+console.log(personne.âge); // 100
+personne.âge = 'jeune'; // lève une exception
+personne.âge = 300; // lève une exception
+</pre>
+
+<h3 id="Étendre_un_constructeur">Étendre un constructeur</h3>
+
+<p>En utilisant une fonction proxy, on peut étendre un constructeur avec un nouveau constructeur. Dans cet exemple, on utilise les gestionnaires correspondants à {{jsxref("Objets_globaux/Proxy/handler/construct","construct")}} et {{jsxref("Objets_globaux/Proxy/handler/apply","apply")}}.</p>
+
+<pre class="brush: js">function étendre(sup,base) {
+ var descripteur = Object.getOwnPropertyDescriptor(
+ base.prototype, "constructor"
+ );
+ base.prototype = Object.create(sup.prototype);
+ var gestionnaire = {
+ construct: function(cible, args) {
+ var obj = Object.create(base.prototype);
+ this.apply(cible,obj,args);
+ return obj;
+ },
+ apply: function(cible, that, args) {
+ sup.apply(that,args);
+ base.apply(that,args);
+ }
+ };
+ var proxy = new Proxy(base,gestionnaire);
+ descripteur.value = proxy;
+ Object.defineProperty(base.prototype, "constructor", descripteur);
+ return proxy;
+}
+
+var Personne = function(nom){
+ this.nom = nom;
+};
+
+var Garçon = étendre(Personne, function(nom, âge) {
+ this.âge = âge;
+});
+
+Garçon.prototype.genre = "M";
+
+var Pierre = new Garçon("Pierre", 13);
+console.log(Pierre.genre); // "M"
+console.log(Pierre.nom); // "Pierre"
+console.log(Pierre.âge); // 13</pre>
+
+<h3 id="Manipuler_les_nœuds_DOM">Manipuler les nœuds DOM</h3>
+
+<p>Parfois, on veut passer un attribut ou un nom de classe entre deux éléments différents. Dans cet exemple, on utilise le gestionnaire lié à {{jsxref("Objets_globaux/Proxy/handler/set","set")}}.</p>
+
+<pre class="brush: js">let vue = new Proxy({
+ selected: null
+},
+{
+ set: function(obj, prop, nouvelleValeur) {
+ let ancienneValeur = obj[prop];
+
+ if (prop === 'selected') {
+ if (ancienneValeur) {
+ ancienneValeur.setAttribute('aria-selected', 'false');
+ }
+ if (nouvelleValeur) {
+ nouvelleValeur.setAttribute('aria-selected', 'true');
+ }
+ }
+
+ // Le comportement par défaut : enregistrer la valeur
+ obj[prop] = nouvelleValeur;
+
+ // On indique le succès de l'opération
+ return true;
+ }
+});
+
+let i1 = vue.selected = document.getElementById('item-1');
+console.log(i1.getAttribute('aria-selected')); // 'true'
+
+let i2 = vue.selected = document.getElementById('item-2');
+console.log(i1.getAttribute('aria-selected')); // 'false'
+console.log(i2.getAttribute('aria-selected')); // 'true'
+</pre>
+
+<h3 id="Corriger_une_valeur_et_ajouter_une_propriété_supplémentaire">Corriger une valeur et ajouter une propriété supplémentaire</h3>
+
+<p>Dans l'exemple qui suit, le proxy <code>produits</code> évalue la valeur passée et la convertit en tableau si besoin. L'objet supporte également la propriété supplémentaire <code>dernierNavigateur</code> à la fois comme accesseur et mutateur.</p>
+
+<pre class="brush: js">let produits = new Proxy({
+ navigateurs: ['Internet Explorer', 'Netscape']
+},
+{
+ get: function(obj, prop) {
+ // Une propriété supplémentaire
+ if (prop === 'dernierNavigateur') {
+ return obj.navigateurs[obj.navigateurs.length - 1];
+ }
+
+ // Le comportement par défaut : renvoyer la valeur
+ return obj[prop];
+ },
+ set: function(obj, prop, valeur) {
+ // Une propriété supplémentaire
+ if (prop === 'dernierNavigateur') {
+ obj.navigateurs.push(valeur);
+ return true;
+ }
+
+ // on convertit la valeur si ce n'est pas un tableau
+ if (typeof valeur === 'string') {
+ valeur = [valeur];
+ }
+
+ // Le comportement par défaut : enregistrer la valeur
+ obj[prop] = valeur;
+
+ // On indique le succès de l'opération
+ return true;
+ }
+});
+
+console.log(produits.navigateurs); // ['Internet Explorer', 'Netscape']
+produits.navigateurs = 'Firefox'; // on passe une chaîne
+console.log(produits.navigateurs); // ['Firefox'] &lt;- pas de problème, elle est convertie en tableau
+
+produits.dernierNavigateur = 'Chrome';
+console.log(produits.navigateurs); // ['Firefox', 'Chrome']
+console.log(produits.dernierNavigateur); // 'Chrome'
+</pre>
+
+<h3 id="Trouver_un_élément_dans_un_tableau_grâce_à_sa_propriété">Trouver un élément dans un tableau grâce à sa propriété</h3>
+
+<p>Dans cet exemple, ce proxy étend le tableau avec des fonctionnalités supplémentaires. Ici, on définit des propriétés sans utiliser {{jsxref("Objets_globaux/Object/defineProperties","Object.defineProperties")}}. Cet exemple pourrait être adapté pour trouver la ligne d'un tableau à partir d'une de ces cellules (la cible serait alors <a href="/fr/docs/Web/API/HTMLTableElement.rows"><code>table.rows</code></a>).</p>
+
+<pre class="brush: js">let produits = new Proxy([
+ { nom: 'Firefox', type: 'navigateur' },
+ { nom: 'SeaMonkey', type: 'navigateur' },
+ { nom: 'Thunderbird', type: 'client mail' }
+],
+{
+ get: function(obj, prop) {
+ // Le comportement par défaut : on renvoie la valeur
+ // prop est généralement un entier
+ if (prop in obj) {
+ return obj[prop];
+ }
+
+ // On obtient le nombre de produits
+ // un alias pour products.length
+ if (prop === 'nombre') {
+ return obj.length;
+ }
+
+ let résultat, types = {};
+
+ for (let produit of obj) {
+ if (produit.nom === prop) {
+ résultat = produit;
+ }
+ if (types[produit.type]) {
+ types[produit.type].push(produit);
+ } else {
+ types[produit.type] = [produit];
+ }
+ }
+
+ // Obtenir un produit grâce à un nom
+ if (résultat) {
+ return résultat;
+ }
+
+ // Obtenir un produit par type
+ if (prop in types) {
+ return types[prop];
+ }
+
+ // Obtenir les types de produits
+ if (prop === 'types') {
+ return Object.keys(types);
+ }
+
+ return undefined;
+ }
+});
+
+console.log(produits[0]); // { nom: 'Firefox', type: 'navigateur' }
+console.log(produits['Firefox']); // { nom: 'Firefox', type: 'navigateur' }
+console.log(produits['Chrome']); // undefined
+console.log(produits.navigateur); // [{ nom: 'Firefox', type: 'navigateur' }, { nom: 'SeaMonkey', type: 'navigateur' }]
+console.log(produits.types); // ['navigateur', 'client mail']
+console.log(produits.nombre); // 3
+</pre>
+
+<h3 id="Un_exemple_avec_toutes_les_trappes">Un exemple avec toutes les trappes</h3>
+
+<p>Pour illustrer l'ensemble des trappes, on tente de « proxifier » un objet non natif : l'objet global <code>docCookies</code> créé grâce à <a href="/fr/docs/Web/API/Document/cookie/Simple_document.cookie_framework">cet exemple</a>.</p>
+
+<pre class="brush: js">/*
+ var docCookies = ... définir l'objet "docCookies" grâce à
+ 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 &amp;&amp; "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;
+ },
+});
+
+/* Cookies test */
+
+console.log(docCookies.mon_cookie1 = "Première valeur");
+console.log(docCookies.getItem("mon_cookie1"));
+
+docCookies.setItem("mon_cookie1", "Valeur modifiée");
+console.log(docCookies.mon_cookie1);</pre>
+
+<h2 id="Spécifications">Spécifications</h2>
+
+<table class="standard-table">
+ <tbody>
+ <tr>
+ <th scope="col">Spécification</th>
+ <th scope="col">État</th>
+ <th scope="col">Commentaires</th>
+ </tr>
+ <tr>
+ <td>{{SpecName('ES2015', '#sec-proxy-objects', 'Proxy')}}</td>
+ <td>{{Spec2('ES2015')}}</td>
+ <td>Définition initiale.</td>
+ </tr>
+ <tr>
+ <td>{{SpecName('ES2016', '#sec-proxy-objects', 'Proxy')}}</td>
+ <td>{{Spec2('ES2016')}}</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>{{SpecName('ES2017', '#sec-proxy-objects', 'Proxy')}}</td>
+ <td>{{Spec2('ES2017')}}</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>{{SpecName('ESDraft', '#sec-proxy-objects', 'Proxy')}}</td>
+ <td>{{Spec2('ESDraft')}}</td>
+ <td></td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Compatibilité_des_navigateurs">Compatibilité des navigateurs</h2>
+
+<div class="hidden">Ce tableau de compatibilité a été généré à partir de données structurées. Si vous souhaitez contribuer à ces données, n'hésitez pas à envoyer une <em>pull request</em> sur <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a>.</div>
+
+<p>{{Compat("javascript.builtins.Proxy", 2)}}</p>
+
+<h2 id="Voir_aussi">Voir aussi</h2>
+
+<ul>
+ <li><a href="https://www.youtube.com/watch?v=sClk6aB_CPk">“Proxies are awesome”, une présentation de Brendan Eich à JSConf</a> (en anglais) (<a href="https://www.slideshare.net/BrendanEich/metaprog-5303821">présentation</a>)</li>
+ <li><a href="https://wiki.ecmascript.org/doku.php?id=harmony:proxies">La page pour la proposition ECMAScript Harmony sur Proxy</a> et <a href="https://wiki.ecmascript.org/doku.php?id=harmony:proxies_semantics">la page sur la sémantique des proxies ECMAScript Harmony</a></li>
+ <li><a href="http://web.archive.org/web/20171007221059/http://soft.vub.ac.be/~tvcutsem/proxies/">Un tutoriel sur les proxies</a> (en anglais)</li>
+ <li><a href="/fr/docs/JavaScript/Old_Proxy_API">L'ancienne API pour les Proxy SpiderMonkey</a></li>
+ <li>{{jsxref("Object.watch()")}}, une fonctionnalité non-standard présente dans Gecko.</li>
+</ul>
+
+<h2 id="Notes_de_licence">Notes de licence</h2>
+
+<p>Certains composants de cette page (texte, exemples) ont été copiés ou adaptés du <a href="https://wiki.ecmascript.org/doku.php">Wiki ECMAScript</a> dont le contenu est sous licence <a href="https://creativecommons.org/licenses/by-nc-sa/2.0/">CC 2.0 BY-NC-SA</a>.</p>