diff --git a/files/fr/_redirects.txt b/files/fr/_redirects.txt index 3adf9c7ec2b12f..03e333056633ef 100644 --- a/files/fr/_redirects.txt +++ b/files/fr/_redirects.txt @@ -3845,7 +3845,8 @@ /fr/docs/Web/API/FileList/FileList /fr/docs/Web/API/FileList /fr/docs/Web/API/FileReader/FileList /fr/docs/Web/API/FileList /fr/docs/Web/API/FileRequest/lockedFile /fr/docs/Web/API/IndexedDB_API -/fr/docs/Web/API/FormData/Utilisation_objets_FormData /fr/docs/Web/API/FormData/Using_FormData_Objects +/fr/docs/Web/API/FormData/Using_FormData_Objects /fr/docs/Web/API/XMLHttpRequest_API/Using_FormData_Objects +/fr/docs/Web/API/FormData/Utilisation_objets_FormData /fr/docs/Web/API/XMLHttpRequest_API/Using_FormData_Objects /fr/docs/Web/API/GlobalEventHandlers/onabort /fr/docs/Web/API/HTMLMediaElement/abort_event /fr/docs/Web/API/GlobalEventHandlers/onauxclick /fr/docs/Web/API/Element/auxclick_event /fr/docs/Web/API/GlobalEventHandlers/onblur /fr/docs/Web/API/Window/blur_event @@ -4099,7 +4100,8 @@ /fr/docs/Web/API/WorkerGlobalScope/ononline /fr/docs/Web/API/WorkerGlobalScope/online_event /fr/docs/Web/API/XMLDocument/async /fr/docs/Web/API/XMLDocument /fr/docs/Web/API/XMLDocument/load /fr/docs/Web/API/XMLDocument -/fr/docs/Web/API/XMLHttpRequest/Utiliser_XMLHttpRequest /fr/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest +/fr/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest /fr/docs/Web/API/XMLHttpRequest_API/Using_XMLHttpRequest +/fr/docs/Web/API/XMLHttpRequest/Utiliser_XMLHttpRequest /fr/docs/Web/API/XMLHttpRequest_API/Using_XMLHttpRequest /fr/docs/Web/API/XMLHttpRequest/onreadystatechange /fr/docs/Web/API/XMLHttpRequest/readystatechange_event /fr/docs/Web/API/XSLTProcessor/XSL_Transformations_in_Mozilla_FAQ /fr/docs/Web/API/XSLTProcessor /fr/docs/Web/API/console.log /fr/docs/Web/API/console/log @@ -4760,7 +4762,7 @@ /fr/docs/Web/Guide/HTML/Liens_email /fr/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks /fr/docs/Web/Guide/HTML/Using_HTML5_audio_and_video /fr/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content /fr/docs/Web/Guide/HTML/Using_HTML_sections_and_outlines /fr/docs/Web/HTML/Element/Heading_Elements -/fr/docs/Web/Guide/Using_FormData_Objects /fr/docs/Web/API/FormData/Using_FormData_Objects +/fr/docs/Web/Guide/Using_FormData_Objects /fr/docs/Web/API/XMLHttpRequest_API/Using_FormData_Objects /fr/docs/Web/HTML/Appliquer_des_couleurs /fr/docs/Web/CSS/CSS_colors/Applying_color /fr/docs/Web/HTML/Applying_color /fr/docs/Web/CSS/CSS_colors/Applying_color /fr/docs/Web/HTML/Attributs /fr/docs/Web/HTML/Attributes @@ -4970,6 +4972,7 @@ /fr/docs/Web/JavaScript/Reference/A_propos /fr/docs/Web/JavaScript/Reference /fr/docs/Web/JavaScript/Reference/About /fr/docs/Web/JavaScript/Reference /fr/docs/Web/JavaScript/Reference/Classes/Class_fields /fr/docs/Web/JavaScript/Reference/Classes/Public_class_fields +/fr/docs/Web/JavaScript/Reference/Classes/Private_class_fields /fr/docs/Web/JavaScript/Reference/Classes/Private_properties /fr/docs/Web/JavaScript/Reference/Commentaires /fr/docs/Web/JavaScript/Reference/Lexical_grammar#Commentaires /fr/docs/Web/JavaScript/Reference/Deprecated_and_obsolete_features/The_legacy_Iterator_protocol /fr/docs/Web/JavaScript/Reference/Deprecated_and_obsolete_features /fr/docs/Web/JavaScript/Reference/Erreurs /fr/docs/Web/JavaScript/Reference/Errors @@ -6180,7 +6183,7 @@ /fr/docs/XHTML /fr/docs/Glossary/XHTML /fr/docs/XMLHttpRequest /fr/docs/Web/API/XMLHttpRequest /fr/docs/XMLHttpRequest/FormData /fr/docs/Web/API/FormData -/fr/docs/XMLHttpRequest/Utiliser_XMLHttpRequest /fr/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest +/fr/docs/XMLHttpRequest/Utiliser_XMLHttpRequest /fr/docs/Web/API/XMLHttpRequest_API/Using_XMLHttpRequest /fr/docs/XMLSerializer /fr/docs/Web/API/XMLSerializer /fr/docs/XPath /fr/docs/Web/XPath /fr/docs/XPath/Axes /fr/docs/Web/XPath/Axes @@ -6473,7 +6476,7 @@ /fr/docs/conflicting/Web/API/Element/transitionend_event /fr/docs/Web/API/Element/transitionend_event /fr/docs/conflicting/Web/API/EventTarget/addEventListener /fr/docs/Web/API/EventTarget/addEventListener /fr/docs/conflicting/Web/API/File_and_Directory_Entries_API /fr/docs/Web/API/File_and_Directory_Entries_API -/fr/docs/conflicting/Web/API/FormData/Using_FormData_Objects /fr/docs/Web/API/FormData/Using_FormData_Objects +/fr/docs/conflicting/Web/API/FormData/Using_FormData_Objects /fr/docs/Web/API/XMLHttpRequest_API/Using_FormData_Objects /fr/docs/conflicting/Web/API/Geolocation/getCurrentPosition /fr/docs/Web/API/Geolocation/getCurrentPosition /fr/docs/conflicting/Web/API/Geolocation/getCurrentPosition_058087067b28ad25fff974fd59827fb6 /fr/docs/Web/API/Geolocation/getCurrentPosition /fr/docs/conflicting/Web/API/Geolocation/getCurrentPosition_5852407122355d2ab39863042583c266 /fr/docs/Web/API/Geolocation/getCurrentPosition diff --git a/files/fr/_wikihistory.json b/files/fr/_wikihistory.json index 3a4fb9fbed0f7f..b4e7942ce8af39 100644 --- a/files/fr/_wikihistory.json +++ b/files/fr/_wikihistory.json @@ -9630,10 +9630,6 @@ "modified": "2020-10-15T22:10:44.093Z", "contributors": ["tristantheb", "SphinxKnight", "Pandazaur", "ThreadElric"] }, - "Web/API/FormData/Using_FormData_Objects": { - "modified": "2019-03-23T22:14:27.375Z", - "contributors": ["Wintersunshine-Do"] - }, "Web/API/FormData/append": { "modified": "2020-10-15T22:10:52.044Z", "contributors": ["tristantheb", "ThreadElric", "cyppan"] @@ -13261,17 +13257,6 @@ "Anonymous" ] }, - "Web/API/XMLHttpRequest/Using_XMLHttpRequest": { - "modified": "2019-03-23T23:16:32.724Z", - "contributors": [ - "sylv1", - "JNa0", - "lessonsharing", - "Deleplace", - "teoli", - "riderodd" - ] - }, "Web/API/XMLHttpRequest/XMLHttpRequest": { "modified": "2019-11-25T21:11:58.899Z", "contributors": ["Lyokolux"] @@ -13328,6 +13313,21 @@ "modified": "2020-10-15T22:31:14.301Z", "contributors": ["Voulto", "devweb157"] }, + "Web/API/XMLHttpRequest_API/Using_FormData_Objects": { + "modified": "2019-03-23T22:14:27.375Z", + "contributors": ["Wintersunshine-Do"] + }, + "Web/API/XMLHttpRequest_API/Using_XMLHttpRequest": { + "modified": "2019-03-23T23:16:32.724Z", + "contributors": [ + "sylv1", + "JNa0", + "lessonsharing", + "Deleplace", + "teoli", + "riderodd" + ] + }, "Web/API/XMLSerializer": { "modified": "2019-03-23T23:46:38.004Z", "contributors": ["Delapouite", "Mgjbot", "Fredchat", "VincentN", "Chbok"] @@ -22035,7 +22035,7 @@ "Yukulele." ] }, - "Web/JavaScript/Reference/Classes/Private_class_fields": { + "Web/JavaScript/Reference/Classes/Private_properties": { "modified": "2020-10-15T22:33:35.342Z", "contributors": ["NemoNobobyPersonne", "N0wan", "yohannlog"] }, diff --git a/files/fr/web/api/formdata/using_formdata_objects/index.md b/files/fr/web/api/formdata/using_formdata_objects/index.md deleted file mode 100644 index 6620489a47e646..00000000000000 --- a/files/fr/web/api/formdata/using_formdata_objects/index.md +++ /dev/null @@ -1,156 +0,0 @@ ---- -title: Utilisation des objets FormData -slug: Web/API/FormData/Using_FormData_Objects ---- - -L'objet [`FormData`](/fr/docs/Web/API/FormData) vous permet de compiler un ensemble de paires clé/valeur à envoyer à l'aide de l'API [`XMLHttpRequest`](/fr/docs/Web/API/XMLHttpRequest). Il est principalement destiné à l'envoi de données de formulaire, mais il peut également être utilisé indépendamment des formulaires pour transmettre des données indexées. Le format des données transmises est le même que celui qu'utiliserait la méthode {{domxref("HTMLFormElement.submit","submit()")}} du formulaire pour envoyer les données si l'encodage de ce dernier était défini sur `multipart/form-data`. - -## Création intégrale d'un objet FormData - -Vous pouvez construire un objet `FormData` vous-même, en créer une instance, puis y ajouter des champs en appelant la méthode {{domxref("FormData.append","append()")}}, comme suit : - -```js -var formData = new FormData(); - -formData.append("username", "Groucho"); -formData.append("accountnum", 123456); // le numéro 123456 est converti immédiatement en chaîne "123456" - -// fichier HTML choisi par l'utilisateur -formData.append("userfile", fileInputElement.files[0]); - -// objet JavaScript de type fichier -var content = 'hey!'; // the body of the new file... -var blob = new Blob([content], { type: "text/xml" }); - -formData.append("webmasterfile", blob); - -var request = new XMLHttpRequest(); -request.open("POST", "http://foo.com/submitform.php"); -request.send(formData); -``` - -> **Note :** Les champs « userfile » et « webmasterfile » contiennent tous deux un fichier. Le numéro attribué au champ « accountnum » est immédiatement converti en chaîne par la méthode [`FormData.append()`](/fr/docs/Web/API/FormData/append) (la valeur du champ peut être un objet {{ domxref("Blob") }}, {{ domxref("File") }} ou une chaîne : **s'il ne s'agit ni d'un objet Blob, ni d'un objet File, la valeur est convertie en chaîne**). - -Dans cet exemple, une instance `FormData` contenant les valeurs des champs « username », « accountnum », « userfile » et « webmasterfile » est créée, puis la méthode `XMLHttpRequest` [`send()`](/fr/docs/Web/API/XMLHttpRequest/send) est utilisée pour envoyer les données du formulaire. Le champ « webmasterfile » est un objet {{domxref("Blob")}}. Un objet `Blob` représente un objet-fichier de données brutes immuables. Les Blobs représentent des données qui ne sont pas nécessairement dans un format JavaScript natif. L'interface {{ domxref("File") }} se base sur l'objet `Blob`, elle en hérite les fonctionnalités et les étend pour prendre en charge les fichiers du système de l'utilisateur. Pour construire un `Blob`, vous pouvez invoquer le {{domxref("Blob.Blob","constructeur Blob()")}}. - -## Récupération d'un objet FormData dans un formulaire HTML - -Pour construire un objet `FormData` contenant les données d'un élément HTML [`
`](/fr/docs/Web/HTML/Element/form) existant, spécifiez cet élément lors de la création de l'objet : - -```js -var formData = new FormData(someFormElement); -``` - -Par exemple : - -```js -var formElement = document.querySelector("form"); -var request = new XMLHttpRequest(); -request.open("POST", "submitform.php"); -request.send(new FormData(formElement)); -``` - -Vous pouvez également ajouter des données supplémentaires à l'objet `FormData` entre sa récupération dans un formulaire et son envoi, comme suit : - -```js -var formElement = document.querySelector("form"); -var formData = new FormData(formElement); -var request = new XMLHttpRequest(); -request.open("POST", "submitform.php"); -formData.append("serialnumber", serialNumber++); -request.send(formData); -``` - -Vous pouvez ainsi ajouter des données au formulaire avant de l'envoyer, pour y inclure des informations supplémentaires que les utilisateurs ne peuvent pas nécessairement modifier. - -## Envoi de fichiers via un objet FormData - -L'objet `FormData` vous permet également d'envoyer des fichiers. Il vous suffit d'inclure un élément HTML {{ HTMLElement("input") }} de type `file` dans votre élément {{htmlelement("form")}} : - -```html - - -
- -
- - - -
-
-``` - -Vous pouvez ensuite l'envoyer à l'aide du code suivant : - -```js -var form = document.forms.namedItem("fileinfo"); -form.addEventListener( - "submit", - function (ev) { - var oOutput = document.querySelector("div"), - oData = new FormData(form); - - oData.append("CustomField", "Données supplémentaires"); - - var oReq = new XMLHttpRequest(); - oReq.open("POST", "stash.php", true); - oReq.onload = function (oEvent) { - if (oReq.status == 200) { - oOutput.innerHTML = "Envoyé !"; - } else { - oOutput.innerHTML = - "Erreur " + - oReq.status + - " lors de la tentative d’envoi du fichier.
"; - } - }; - - oReq.send(oData); - ev.preventDefault(); - }, - false, -); -``` - -> **Note :** Si vous passez une référence dans le formulaire, la méthode spécifiée dans ce dernier sera utilisée au lieu de celle définie dans l'appel de la méthode open(). - -Vous pouvez également ajouter un objet {{ domxref("File") }} ou {{ domxref("Blob") }} directement dans l'objet {{ domxref("FormData") }} : - -```js -data.append("myfile", myBlob, "filename.txt"); -``` - -Avec la méthode {{domxref("FormData.append","append()")}}, vous pouvez utiliser le troisième paramètre facultatif pour passer un nom de fichier dans l'en-tête `Content-Disposition` envoyé au serveur. Si aucun nom de fichier n'est spécifié (ou si le paramètre n'est pas pris en charge), le nom « blob » est utilisé. - -Vous pouvez utiliser l'objet `FormData` avec jQuery si vous définissez les options appropriées : - -```js -var fd = new FormData(document.querySelector("form")); -fd.append("CustomField", "Données supplémentaires"); -$.ajax({ - url: "stash.php", - type: "POST", - data: fd, - processData: false, // dire à jQuery de ne pas traiter les données - contentType: false, // dire à jQuery de ne pas définir le contentType -}); -``` - -## Envoi de formulaires et de fichiers via AJAX sans objet `FormData` - -Si vous voulez en savoir plus sur la sérialisation des données et l'envoi d'un formulaire via [AJAX](/fr/docs/AJAX) _sans_ utiliser d'objets FormData, consultez [ce paragraphe](/fr/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Submitting_forms_and_uploading_files). - -## Voir aussi - -- [Utiliser XMLHttpRequest](/fr/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest) -- {{domxref("HTMLFormElement")}} -- {{domxref("Blob")}} -- [Tableaux typés](/fr/docs/Web/JavaScript/Typed_arrays) diff --git a/files/fr/web/api/xmlhttprequest_api/using_formdata_objects/index.md b/files/fr/web/api/xmlhttprequest_api/using_formdata_objects/index.md new file mode 100644 index 00000000000000..3af3ee881742b6 --- /dev/null +++ b/files/fr/web/api/xmlhttprequest_api/using_formdata_objects/index.md @@ -0,0 +1,203 @@ +--- +title: Utilisation des objets FormData +slug: Web/API/XMLHttpRequest_API/Using_FormData_Objects +l10n: + sourceCommit: 2024a508694208f0316c484fb41e2c5823deae88 +--- + +{{DefaultAPISidebar("XMLHttpRequest API")}} + +L'objet [`FormData`](/fr/docs/Web/API/FormData) vous permet de compiler un ensemble de paires clé/valeur à envoyer à l'aide de l'API [`XMLHttpRequest`](/fr/docs/Web/API/XMLHttpRequest). Il est principalement destiné à l'envoi de données de formulaire, mais il peut également être utilisé indépendamment des formulaires pour transmettre des données indexées. Le format des données transmises est le même que celui utilisé par la méthode [`submit()`](/fr/docs/Web/API/HTMLFormElement/submit) du formulaire pour envoyer les données lorsque l'encodage de ce dernier est défini sur `multipart/form-data`. + +## Créer un objet `FormData` de toutes pièces + +Vous pouvez construire un objet `FormData` vous-même, créer une instance, puis y ajouter des champs en appelant la méthode [`append()`](/fr/docs/Web/API/FormData/append), comme suit : + +```js +const formData = new FormData(); + +formData.append("username", "Groucho"); +formData.append("accountnum", 123456); // le numéro 123456 est converti immédiatement en chaîne "123456" + +// fichier HTML choisi par l'utilisateur +formData.append("userfile", fileInputElement.files[0]); + +// objet JavaScript de type fichier +const content = 'hey!'; // le corps du nouveau fichier… +const blob = new Blob([content], { type: "text/xml" }); + +formData.append("webmasterfile", blob); + +const request = new XMLHttpRequest(); +request.open("POST", "https://example.com/submitform.php"); +request.send(formData); +``` + +> **Note :** Les champs « userfile » et « webmasterfile » contiennent tous deux un fichier. Le numéro attribué au champ « accountnum » est immédiatement converti en chaîne par la méthode [`FormData.append()`](/fr/docs/Web/API/FormData/append) (la valeur du champ peut être un objet [`Blob`](/fr/docs/Web/API/Blob), [`File`](/fr/docs/Web/API/File) ou une chaîne : **s'il ne s'agit ni d'un objet `Blob`, ni d'un objet `File`, la valeur est convertie en chaîne**). + +Dans cet exemple, une instance `FormData` contenant les valeurs des champs « username », « accountnum », « userfile » et « webmasterfile » est créée, puis la méthode [`XMLHttpRequest.send()`](/fr/docs/Web/API/XMLHttpRequest/send) est utilisée pour envoyer les données du formulaire. Le champ « webmasterfile » est un objet [`Blob`](/fr/docs/Web/API/Blob). Un objet `Blob` représente un objet-fichier de données brutes immuables. Les blobs représentent des données qui ne sont pas nécessairement dans un format JavaScript natif. L'interface [`File`](/fr/docs/Web/API/File) se base sur l'objet `Blob`, elle en hérite les fonctionnalités et les étend pour prendre en charge les fichiers du système d'exploitation. Pour construire un `Blob`, vous pouvez invoquer [le constructeur `Blob()`](/fr/docs/Web/API/Blob/Blob). + +## Récupération d'un objet `FormData` dans un formulaire HTML + +Pour construire un objet `FormData` contenant les données d'un élément HTML [`
`](/fr/docs/Web/HTML/Element/form) existant, spécifiez cet élément lors de la création de l'objet : + +```js +const formData = new FormData(unElementDeFormulaire); +``` + +Par exemple : + +```js +const formElement = document.querySelector("form"); +const request = new XMLHttpRequest(); +request.open("POST", "submitform.php"); +request.send(new FormData(formElement)); +``` + +Vous pouvez également ajouter des données supplémentaires à l'objet `FormData` entre la récupération depuis le formulaire et son envoi, comme suit : + +```js +const formElement = document.querySelector("form"); +const formData = new FormData(formElement); +const request = new XMLHttpRequest(); +request.open("POST", "submitform.php"); +formData.append("serialnumber", serialNumber++); +request.send(formData); +``` + +Vous pouvez ainsi ajouter des données au formulaire avant de l'envoyer, pour y inclure des informations supplémentaires que les utilisatrices et utilisateurs ne peuvent pas nécessairement modifier. + +## Envoi de fichiers via un objet `FormData` + +L'objet `FormData` vous permet également d'envoyer des fichiers. Il vous suffit d'inclure un élément HTML [``](/fr/docs/Web/HTML/Element/input) de type `file` dans votre élément [``](/fr/docs/Web/HTML/Element/form) : + +```html + +

+ +

+

+ +

+

+ +

+

+ +

+
+
+``` + +Vous pouvez ensuite l'envoyer à l'aide du code suivant : + +```js +const form = document.forms.namedItem("fileinfo"); +form.addEventListener( + "submit", + (event) => { + const output = document.querySelector("#output"); + const formData = new FormData(form); + + formData.append("CustomField", "Des données supplémentaires"); + + const request = new XMLHttpRequest(); + request.open("POST", "stash.php", true); + request.onload = (progress) => { + output.innerHTML = + request.status === 200 + ? "Fichier téléversé !" + : `Erreur ${request.status} lors de la tentative de téléversement du fichier.
`; + }; + + request.send(formData); + event.preventDefault(); + }, + false, +); +``` + +> **Note :** Si vous passez une référence dans le formulaire, [la méthode HTTP spécifiée](/fr/docs/Web/HTTP/Methods) dans ce dernier sera utilisée au lieu de celle définie dans l'appel de la méthode `open()`. + +> **Attention :** Lors de l'utilisation de `FormData` pour envoyer des requêtes POST à l'aide de [`XMLHttpRequest`](/fr/docs/Web/API/XMLHttpRequest) ou de [l'API Fetch](/fr/docs/Web/API/Fetch_API) pour du contenu de type `multipart/form-data` (par exemple pour téléverser des fichiers ou des blobs vers le serveur), _il ne faut pas indiquer de façon explicite_ l'en-tête [`Content-Type`](/fr/docs/Web/HTTP/Headers/Content-Type) sur la requête. Si vous le faites, cela empêchera le navigateur de renseigner l'en-tête `Content-Type` avec l'expression de limite qui sera utilisée pour délimiter les champs du formulaire dans le corps de la requête. + +Vous pouvez également ajouter un objet [`File`](/fr/docs/Web/API/File) ou [`Blob`](/fr/docs/Web/API/Blob) directement dans l'objet [`FormData`](/fr/docs/Web/API/FormData) : + +```js +data.append("monfichier", monBlob, "nomFichier.txt"); +``` + +Avec la méthode [`FormData.append()`](/fr/docs/Web/API/FormData/append), vous pouvez utiliser le troisième paramètre facultatif pour passer un nom de fichier dans l'en-tête `Content-Disposition` envoyé au serveur. Si aucun nom de fichier n'est spécifié (ou si le paramètre n'est pas pris en charge), le nom « blob » est utilisé. + +## Utiliser un évènement `formdata` + +L'évènement [`formdata`](/fr/docs/Web/API/HTMLFormElement/formdata_event), apparu après [`FormData`](/fr/docs/Web/API/FormData), est déclenché sur un objet [`HTMLFormElement`](/fr/docs/Web/API/HTMLFormElement) après que la liste des données du formulaire a été construite. Cela se produit nativement lors de l'envoi du formulaire, mais peut aussi être déclenché par l'appel au constructeur [`FormData()`](/fr/docs/Web/API/FormData/FormData). + +On peut ainsi récupérer un objet [`FormData`](/fr/docs/Web/API/FormData) dès le déclenchement de l'évènement `formdata`, plutôt que de l'assembler soi-même. + +Dans [cette démo sur `formdata`](https://long-impatiens.glitch.me/), on fait référence au formulaire dans le code JavaScript : + +```js +const formElem = document.querySelector("form"); +``` + +Dans le gestionnaire d'évènement pour [l'évènement `submit`](/fr/docs/Web/API/HTMLFormElement/submit_event), on utilise [`preventDefault`](/fr/docs/Web/API/Event/preventDefault) afin d'interrompre l'envoi normal du formulaire, puis on invoque le constructeur [`FormData()`](/fr/docs/Web/API/FormData/FormData) afin de déclencher l'évènement `formdata` : + +```js +formElem.addEventListener("submit", (e) => { + // lors de l'envoi du formulaire, on empêche l'envoi + // normal + e.preventDefault(); + + // on construit un objet FormData qui déclenche + // l'évènement formdata + new FormData(formElem); +}); +``` + +Lorsque l'évènement `formdata` se déclenche, on peut accéder à l'objet [`FormData`](/fr/docs/Web/API/FormData) en utilisant [`FormDataEvent.formData`](/fr/docs/Web/API/FormDataEvent/formData). On peut alors le manipuler comme bon nous semble (ici, nous l'envoyons au serveur à l'aide de [`XMLHttpRequest`](/fr/docs/Web/API/XMLHttpRequest)). + +```js +formElem.addEventListener("formdata", (e) => { + console.log("formdata déclenché"); + + // On récupère les données du formulaire depuis + // l'objet représentant l'évènement + const data = e.formData; + for (const value of data.values()) { + console.log(value); + } + + // On envoie les données via XHR + const request = new XMLHttpRequest(); + request.open("POST", "/formHandler"); + request.send(data); +}); +``` + +## Points d'attention + +L'objet `FormData` n'inclut pas les données du formulaire pour les champs ou ensembles de champs ([`
`](/fr/docs/Web/HTML/Element/fieldset)) qui sont désactivés. + +## Voir aussi + +- [Utiliser `XMLHttpRequest`](/fr/docs/Web/API/XMLHttpRequest_API/Using_XMLHttpRequest) +- [`HTMLFormElement`](/fr/docs/Web/API/HTMLFormElement) +- [`Blob`](/fr/docs/Web/API/Blob) +- [Tableaux typés JavaScript](/fr/docs/Web/JavaScript/Guide/Typed_arrays) diff --git a/files/fr/web/api/xmlhttprequest/using_xmlhttprequest/index.md b/files/fr/web/api/xmlhttprequest_api/using_xmlhttprequest/index.md similarity index 83% rename from files/fr/web/api/xmlhttprequest/using_xmlhttprequest/index.md rename to files/fr/web/api/xmlhttprequest_api/using_xmlhttprequest/index.md index 0fcddf67b8546e..eb6e744484977a 100644 --- a/files/fr/web/api/xmlhttprequest/using_xmlhttprequest/index.md +++ b/files/fr/web/api/xmlhttprequest_api/using_xmlhttprequest/index.md @@ -1,11 +1,11 @@ --- title: Utiliser XMLHttpRequest -slug: Web/API/XMLHttpRequest/Using_XMLHttpRequest +slug: Web/API/XMLHttpRequest_API/Using_XMLHttpRequest l10n: - sourceCommit: c3a0924949863b43957b4ba2ad5e64558165672d + sourceCommit: 2024a508694208f0316c484fb41e2c5823deae88 --- -{{APIRef("XMLHttpRequest")}} +{{DefaultAPISidebar("XMLHttpRequest API")}} Dans ce guide, nous verrons comment utiliser [`XMLHttpRequest`](/fr/docs/Web/API/XMLHttpRequest) afin d'envoyer des requêtes [HTTP](/fr/docs/Web/HTTP) pour échanger des données entre le site web et un serveur. @@ -173,72 +173,6 @@ function loadEnd(e) { Il n'y a pas de certitude possible quant à l'information reçue par l'évènement `loadend` pour déterminer la condition de l'arrêt. Toutefois, cet évènement permet de gérer les tâches nécessaires à la fin des transferts. -## Soumettre des formulaires et envoyer des fichiers - -On peut utiliser `XMLHttpRequest` afin d'envoyer des formulaires de deux façons : - -- De façon autonome, sans autre API -- Avec l'API [`FormData`](/fr/docs/Web/API/FormData) - -Utiliser l'API `FormData` sera souvent la solution la plus efficace, à l'inconvénient près que les données récupérées ne peuvent pas être transformées en chaînes de caractères avec [`JSON.stringify()`](/fr/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). L'utilisation d'XHR seul est plus compliquée, mais également plus flexible et plus puissante. - -### Utiliser uniquement `XMLHttpRequest` - -Lorsqu'on soumet des formulaires sans utiliser `FormData`, on pourra ne pas utiliser d'autres API dans la plupart des cas. Le seul contre-exemple porte sur le téléversement de fichiers, où il faudra utiliser l'API [`FileReader`](/fr/docs/Web/API/FileReader). - -#### Une rapide introduction aux méthodes d'envoi - -On peut soumettre un formulaire HTML ([`
`](/fr/docs/Web/HTML/Element/Form)) de quatre façons : - -- En utilisant la méthode `POST` et avec l'attribut `enctype` qui vaut `application/x-www-form-urlencoded` (le comportement par défaut) -- En utilisant la méthode `POST` et avec l'attribut `enctype` qui vaut `text/plain` -- En utilisant la méthode `POST` et avec l'attribut `enctype` qui vaut `multipart/form-data` -- En utilisant la méthode `GET` (auquel cas, l'attribut `enctype` sera ignoré). - -Prenons comme un exemple un formulaire avec deux champs, intitulés `toto` et `machin`. Si on utilise la méthode `POST`, le serveur recevra une chaîne de caractères semblable aux trois qui suivent selon le type d'encodage utilisé : - -- Méthode : `POST` ; Type d'encodage : `application/x-www-form-urlencoded` (default) : - - ```plain - Content-Type: application/x-www-form-urlencoded - - toto=truc&machin=La+premiere+ligne.%0D%0ALa+seconde+ligne.%0D%0A - ``` - -- Méthode : `POST` ; Type d'encodage : `text/plain` : - - ```plain - Content-Type: text/plain - - toto=truc - machin=La premiere ligne. - La seconde ligne. - ``` - -- Méthode : `POST` ; Type d'encodage : [`multipart/form-data`](/fr/docs/Web/HTTP/Basics_of_HTTP/MIME_types#multipartform-data) : - - ```plain - Content-Type: multipart/form-data; boundary=---------------------------314911788813839 - - -----------------------------314911788813839 - Content-Disposition: form-data; name="toto" - - truc - -----------------------------314911788813839 - Content-Disposition: form-data; name="machin" - - La premiere ligne. - La seconde ligne. - - -----------------------------314911788813839-- - ``` - -En revanche, en utilisant la méthode `GET`, ce sera une chaîne de caractères comme celle-ci qui sera ajoutée à l'URL : - -```plain -?toto=truc&machin=La%20premiere%20ligne.%0ALa%20seconde%20ligne. -``` - ## Obtenir la date de dernière modification ```js @@ -342,7 +276,6 @@ Si votre requête XHR se termine avec `status=0` et `statusText=null`, cela sign ## Voir aussi -- [Introduction à AJAX](/fr/docs/Web/Guide/AJAX/Getting_Started) - [Utiliser l'API Fetch](/fr/docs/Web/API/Fetch_API/Using_Fetch) - [Prise en charge de HTML dans `XMLHttpRequest`](/fr/docs/Web/API/XMLHttpRequest/HTML_in_XMLHttpRequest) - [Contrôle d'accès HTTP (CORS)](/fr/docs/Web/HTTP/CORS) diff --git a/files/fr/web/javascript/reference/classes/private_class_fields/index.md b/files/fr/web/javascript/reference/classes/private_class_fields/index.md deleted file mode 100644 index abec7608676bdb..00000000000000 --- a/files/fr/web/javascript/reference/classes/private_class_fields/index.md +++ /dev/null @@ -1,198 +0,0 @@ ---- -title: Variables de classe privés -slug: Web/JavaScript/Reference/Classes/Private_class_fields ---- - -{{JsSidebar("Classes")}}Les propriétés de classe sont publiques par défaut et peuvent être lues et modifiées à l'extérieur de la classe. Cependant, [une proposition expérimentale](https://github.com/tc39/proposal-class-fields), permettant de définir des variables privées dans une classe avec le préfixe `#`, est disponible. - -## Syntaxe - -```js -class ClassWithPrivateField { - #privateField; -} - -class ClassWithPrivateMethod { - #privateMethod() { - return "hello world"; - } -} - -class ClassWithPrivateStaticField { - static #PRIVATE_STATIC_FIELD; -} -``` - -## Exemples - -### Champs privés statiques - -Les champs privés sont accessibles depuis le constructeur et depuis l'intérieur de la déclaration de la classe elle-même. - -La limitation des variables statiques ne pouvant être appelées que par des méthodes statiques tient toujours. - -```js -class ClassWithPrivateStaticField { - static #PRIVATE_STATIC_FIELD; - - static publicStaticMethod() { - ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD = 42; - return ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD; - } -} - -console.assert(ClassWithPrivateStaticField.publicStaticMethod() === 42); -``` - -Les champs statiques privés sont ajoutés au constructeur de la classe au moment de l'évaluation de classe.. - -Il y a une restriction de provenance sur les champs statiques privés. Seule la classe qui a défini un champ statique privé peut y accéder. - -Ceci peut conduire à un comportement inattendu lors de l'utilisation de **`this`**. - -```js -class BaseClassWithPrivateStaticField { - static #PRIVATE_STATIC_FIELD; - - static basePublicStaticMethod() { - this.#PRIVATE_STATIC_FIELD = 42; - return this.#PRIVATE_STATIC_FIELD; - } -} - -class SubClass extends BaseClassWithPrivateStaticField {} - -let error = null; - -try { - SubClass.basePublicStaticMethod(); -} catch (e) { - error = e; -} - -console.assert(error instanceof TypeError); -``` - -### Champs d'instance privés - -Les champs d'instance privés sont déclarés avec des **noms** à **#** (prononcés "_noms à hash_", "_hash names_" en anglais), qui sont des identifieurs préfixés par `#`. Le `#` fait partie du nom lui-même. Il est utilisé tant pour la déclaration que pour l'accès. - -L'encapsulation est forcée par le langage. C'est une erreur de syntaxe que de faire référence aux noms à `#` en dehors de leur portée. - -```js -class ClassWithPrivateField { - #privateField; - - constructor() { - this.#privateField = 42; - this.#randomField = 666; // Erreur de syntaxe - } -} - -const instance = new ClassWithPrivateField(); -instance.#privateField === 42; // Erreur de syntaxe -``` - -### Méthodes Privées - -#### Méthodes statiques privées - -Comme leur équivalents publics, les méthodes statiques privées sont appelées dans la classe elle-même, pas dans les instances de la classe. Comme les champs statiques privés, elles ne sont accessibles que depuis l'intérieur de la déclaration de la classe. - -Les méthodes statiques privées peuvent être des fonctions génératrices, asynchrones et génératrices asynchrones. - -```js -class ClassWithPrivateStaticMethod { - static #privateStaticMethod() { - return 42; - } - - static publicStaticMethod1() { - return ClassWithPrivateStaticMethod.#privateStaticMethod(); - } - - static publicStaticMethod2() { - return this.#privateStaticMethod(); - } -} - -console.assert(ClassWithPrivateStaticMethod.publicStaticMethod1() === 42); -console.assert(ClassWithPrivateStaticMethod.publicStaticMethod2() === 42); -``` - -Cela peut conduire à un comportement inattendu lors de l'utilisation de **`this`**. Dans l'exemple suivant, `this` fait référence à la classe `Derived` (pas à la classe `Base`) lorsqu'on essaie d'appeler `Derived.publicStaticMethod2()`, et fait ainsi apparaître la même "restriction de provenance" que mentionné ci-dessus : - -```js -class Base { - static #privateStaticMethod() { - return 42; - } - static publicStaticMethod1() { - return Base.#privateStaticMethod(); - } - static publicStaticMethod2() { - return this.#privateStaticMethod(); - } -} - -class Derived extends Base {} - -console.log(Derived.publicStaticMethod1()); // 42 -console.log(Derived.publicStaticMethod2()); // TypeError -``` - -#### Méthodes d'instance privées - -Les méthodes d'instance privées sont des méthodes disponibles dans les instances de classe privées, dont l'accès est restreint de la même manière que les champs d'instance privés. - -```js -class ClassWithPrivateMethod { - #privateMethod() { - return "hello world"; - } - - getPrivateMessage() { - return this.#privateMethod(); - } -} - -const instance = new ClassWithPrivateMethod(); -console.log(instance.getPrivateMessage()); -// expected output: "hello world" -``` - -Les méthodes d'instance privées peuvent être des fonctions génératrices, asynchones ou génératrices asynchrones. Des accesseurs (getters) et des mutateurs (setters) privés sont aussi posibles : - -```js -class ClassWithPrivateAccessor { - #message; - - get #decoratedMessage() { - return `✨${this.#message}✨`; - } - set #decoratedMessage(msg) { - this.#message = msg; - } - - constructor() { - this.#decoratedMessage = "hello world"; - console.log(this.#decoratedMessage); - } -} - -new ClassWithPrivateAccessor(); -// expected output: "✨hello world✨" -``` - -## Spécifications - -{{Specifications}} - -## Compatibilité des navigateurs - -{{Compat}} - -## Voir aussi - -- [Champs de classe publiques](/fr/docs/Web/JavaScript/Reference/Classes/Class_fields) -- [The Semantics of All JS Class Elements](https://rfrn.org/~shu/2018/05/02/the-semantics-of-all-js-class-elements.html) diff --git a/files/fr/web/javascript/reference/classes/private_properties/index.md b/files/fr/web/javascript/reference/classes/private_properties/index.md new file mode 100644 index 00000000000000..fa03196f3d62fb --- /dev/null +++ b/files/fr/web/javascript/reference/classes/private_properties/index.md @@ -0,0 +1,402 @@ +--- +title: Propriétés privées +slug: Web/JavaScript/Reference/Classes/Private_properties +l10n: + sourceCommit: 2024a508694208f0316c484fb41e2c5823deae88 +--- + +{{jsSidebar("Classes")}} + +Les **propriétés privées** sont les équivalents des propriétés de classe normales, qui sont publiques, comme [les champs de classe](/fr/docs/Web/JavaScript/Reference/Classes/Public_class_fields), les méthodes de classe, etc. Les propriétés privées sont créées en utilisant un croisillon `#` comme préfixe et ne peuvent pas être référencée légalement en dehors de la classe. L'encapsulation de cette isolation dans la classe est gérée par le moteur JavaScript. + +Les propriétés privées n'étaient pas disponibles de façon native en JavaScript avant l'apparition de cette syntaxe. En utilisant l'héritage prototypal, ce comportement pouvait être émulé avec des objets [`WeakMap`](/fr/docs/Web/JavaScript/Reference/Global_Objects/WeakMap#emulating_private_members), ou [des fermetures (closures)](/fr/docs/Web/JavaScript/Closures#émuler_des_méthodes_privées_avec_des_fermetures), mais cela n'était pas aussi pratique que la syntaxe avec `#`. + +## Syntaxe + +```js-nolint +class ClasseAvecProprietesPrivees { + #champPrive; + #champPriveAvecInitialisateur = 42; + + #methodePrivee() { + // … + } + + static #champPriveStatique; + static #champPriveStatiqueAvecInitialisateur = 42; + + static #methodePriveeStatique() { + // … + } +} +``` + +Des restrictions complémentaires s'appliquent : + +- Tous les identifiants privés déclarés au sein d'une classe doivent être uniques. L'espace de noms est partagé entre les propriétés statiques et celles des instances. La seule exception à cette règle est la définition d'une paire d'accesseur/mutateur (getter/setter). +- Un identifiant privé ne peut pas être `#constructor`. + +## Description + +Pour chaque type de propriété d'une classe, on a des équivalents privés : + +- Champs privés +- Méthodes privées +- Champs statiques privés +- Méthodes statiques privées +- Accesseurs privés +- Mutateurs privés +- Accesseurs privés statiques +- Mutateurs privés statiques + +Toutes ces fonctionnalités représentent des _propriétés privées_. Toutefois, [les constructeurs](/fr/docs/Web/JavaScript/Reference/Classes/constructor) ne peuvent pas être privés en JavaScript. Pour empêcher une classe d'être construite en dehors d'elle-même, il faudra [utiliser un marqueur privé](#simuler_des_constructeurs_privés). + +Les propriétés privées sont déclarées avec des identifiants préfixés par `#` (en anglais, on parle de hash names). Le préfixe avec le croisillon fait partie inhérente du nom de la propriété (on peut y voir une analogie avec l'ancienne convention utilisant un tiret bas comme préfixe `_champPrive`, mais il ne s'agit pas d'une propriété dont le nom est une chaîne de caractère classique et on ne peut donc pas y accéder dynamiquement en utilisant [la notation avec les crochets](/fr/docs/Web/JavaScript/Reference/Operators/Property_accessors#notation_avec_crochets)). + +Les cas suivants sont des erreurs de syntaxe : + +- Faire référence aux noms privés en dehors de la classe. +- Faire référence à des propriétés privées qui n'ont pas été déclarées dans le corps de la classe +- Tenter de supprimer une propriété privée avec [`delete`](/fr/docs/Web/JavaScript/Reference/Operators/delete). + +```js-nolint example-bad +class ClasseAvecChampPrive { + #champPrive; + + constructor() {; + delete this.#champPrive; // Erreur de syntaxe + this.#champNonDeclare = 42; // Erreur de syntaxe + } +} + +const instance = new ClasseAvecChampPrive(); +instance.#champPrive; // Erreur de syntaxe +``` + +JavaScript est un langage dynamique et peut faire cette vérification à la compilation grâce à la syntaxe particulière des propriétés privées. + +> **Note :** Le code exécuté dans la console Google Chrome permet d'accéder aux propriétés privées en dehors de la classe. Il s'agit d'une dérogation propre aux outils de développement. + +Si vous tentez d'accéder à une propriété privée sur un objet qui ne dispose pas de la propriété, vous obtiendrez une exception [`TypeError`](/fr/docs/Web/JavaScript/Reference/Global_Objects/TypeError) et non `undefined`, comme c'est le cas pour les propriétés normales (publiques). + +```js example-bad +class C { + #x; + + static getX(obj) { + return obj.#x; + } +} + +console.log(C.getX(new C())); // undefined +console.log(C.getX({})); // TypeError: Cannot read private member #x from an object whose class did not declare it +``` + +Cet exemple illustre également l'accès aux propriétés privées depuis les fonctions statiques et pour les instances de la classe définies par ailleurs. + +L'opérateur [`in`](/fr/docs/Web/JavaScript/Reference/Operators/in) peut être utilisé pour vérifier si un objet tiers possède une propriété privée. L'opérateur renverra `true` si le champ privé existe, `false` sinon. + +```js example-good +class C { + #x; + constructor(x) { + this.#x = x; + } + static getX(obj) { + if (#x in obj) return obj.#x; + + return "obj doit être une instance de C"; + } +} +console.log(C.getX(new C("toto"))); // "toto" +console.log(C.getX(new C(0.196))); // 0.196 +console.log(C.getX(new C(new Date()))); // la date/heure courante +console.log(C.getX({})); // "obj doit être une instance de C" +``` + +Un corollaire à cette déclaration préalable et à cette absence de suppression est que si on trouve un objet possédant au moins une propriété privée de la classe courante (via un `try...catch` ou une vérification `in`), cet objet en possèdera toutes les autres propriétés privées. Un objet possédant une propriété privée d'une classe signifie généralement qu'il a été construit par cette classe (ça [n'est pas forcément le cas](#renvoyer_un_objet_différent)). + +Les propriétés privées ne font par partie du modèle [d'héritage prototypal](/fr/docs/Web/JavaScript/Inheritance_and_the_prototype_chain), car elles ne sont accessibles qu'au sein du corps de la classe courante et ne sont pas héritées par les sous-classes. Les propriétés privées qui ont le même nom, mais des classes différentes sont totalement différentes et n'ont aucune relation entre elles. Il faut voir les propriétés privées comme des métadonnées externes rattachées à chaque instance, gérées par la classe. Pour cette raison, [`Object.freeze()`](/fr/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze) et [`Object.seal()`](/fr/docs/Web/JavaScript/Reference/Global_Objects/Object/seal) n'ont pas d'effet sur les propriétés privées. + +Pour plus d'informations sur la façon dont les champs privés sont initialisés, voir [la page sur les champs publics des classes](/fr/docs/Web/JavaScript/Reference/Classes/Public_class_fields). + +## Exemples + +### Champs privés + +Les champs privés regroupent les champs privés des instances et les champs privés statiques. Ils ne sont accessibles qu'au sein de la déclaration de la classe. + +#### Champs privés des instances + +À l'instar de leurs homologues publics, les champs privés des instances : + +- Sont ajoutés avant que le constructeur s'exécute pour une classe de base, ou immédiatement après l'appel à [`super()`](/fr/docs/Web/JavaScript/Reference/Operators/super) pour une sous-classe +- Uniquement disponible pour les instances de la classe. + +```js +class ClasseAvecChampPrive { + #champPrive; + + constructor() { + this.#champPrive = 42; + } +} + +class SousClasse extends ClasseAvecChampPrive { + #champPriveSousClasse; + + constructor() { + super(); + this.#champPriveSousClasse = 23; + } +} + +new SousClasse(); // Dans certains outils de développement, cela affichera SousClasse {#champPrive: 42, #champPriveSousClasse: 23} +``` + +> **Note :** La propriété `#champPrive`, provenant de la classe de base `ClasseAvecChampPrive` est privée et est donc uniquement accessible à l'intérieur de `ClasseAvecChampPrive` et est inaccessible depuis `SousClasse`. + +#### Renvoyer un objet différent + +Le constructeur d'une classe peut renvoyer un objet différent, qui sera alors utilisé comme nouveau `this` pour le constructeur de la classe dérivée. La classe dérivée pourra alors définir des champs privés sur l'objet qui a été renvoyé, permettant ainsi indirectement d'adjoindre des champs privés pour des objets qui ne sont pas des instances. + +```js +class Stamper extends class { + // Une classe de base dont le constructeur renvoie + // l'objet qui lui est fourni. + constructor(obj) { + return obj; + } +} { + // Cette déclaration rajoutera le champ privé + // sur l'objet renvoyé par le constructeur + // de la classe de base + #stamp = 42; + static getStamp(obj) { + return obj.#stamp; + } +} + +const obj = {}; +new Stamper(obj); +// `Stamper` appelle `Base`, qui renvoie `obj`, et `obj` est +// désormais la valeur `this`. `Stamper` définit alors +// `#stamp` sur `obj` + +console.log(obj); // Dans certains outils de développement, on verra {#stamp: 42} +console.log(Stamper.getStamp(obj)); // 42 +console.log(obj instanceof Stamper); // false + +// On ne peut pas ajouter ainsi deux fois des propriétés privées +new Stamper(obj); // Error: Initializing an object twice is an error with private fields +``` + +> **Attention :** Implémenter un tel fonctionnement sera source de confusion. Il est généralement recommandé de ne rien renvoyer à partir du constructeur, a fortiori, quelque chose qui n'a pas de lien avec `this`. + +#### Champs statiques privés + +À l'instar de leurs homologues publics, les champs statiques privés : + +- Sont ajoutés au constructeur de la classe au moment de l'évaluation de la classe +- Uniquement disponibles sur la classe elle-même (et non sur les instances) + +```js +class ClasseAvecChampStatiquePrive { + static #champStatiquePrive = 42; + + static methodeStatiquePublique() { + return ClasseAvecChampStatiquePrive.#champStatiquePrive; + } +} + +console.log(ClasseAvecChampStatiquePrive.methodeStatiquePublique()); // 42 +``` + +Pour les champs statiques privés, seule la classe qui définit le champ statique privé peut accéder au champ. Cela peut donner des comportements inattendus lorsque [`this`](/fr/docs/Web/JavaScript/Reference/Operators/this) est utilisé. Dans l'exemple suivant, `this` fait référence à la classe `SousClasse` (et non à la classe `ClasseAvecChampStatiquePrive`), et quand on essaie d'appeler `SousClasse.methodeStatiquePublique()`, cela déclenche une erreur `TypeError`. + +```js +class ClasseAvecChampStatiquePrive { + static #champStatiquePrive = 42; + + static methodeStatiquePublique() { + return this.#champStatiquePrive; + } +} + +class SousClasse extends ClasseAvecChampStatiquePrive {} + +SousClasse.methodeStatiquePublique(); // TypeError: Cannot read private member #champStatiquePrive from an object whose class did not declare it +``` + +Le même comportement se produira si la méthode est appelée avec `super`, car [les méthodes appelées avec `super` ne reçoivent pas la classe parente comme valeur pour `this`](/fr/docs/Web/JavaScript/Reference/Operators/super#appeler_des_méthodes_avec_super). + +```js +class ClasseAvecChampStatiquePrive { + static #champStatiquePrive = 42; + + static methodeStatiquePublique() { + // Même appelée avec super, `this` fera référence + // à SousClasse + return this.#champStatiquePrive; + } +} + +class SousClasse extends ClasseAvecChampStatiquePrive { + static appelleSuperMethode() { + return super.methodeStatiquePublique(); + } +} + +SousClasse.appelleSuperMethode(); // TypeError: Cannot read private member #champStatiquePrive from an object whose class did not declare it +``` + +Une bonne pratique consiste à toujours accéder aux champs privés statiques avec le nom de la classe plutôt qu'avec `this`, afin que l'héritage ne casse pas la méthode. + +### Méthodes privées + +Les méthodes privées incluent les méthodes privées des instances et les méthodes statiques privées. Les méthodes privées sont uniquement accessibles à l'intérieur de la déclaration de la classe. + +#### Méthodes privées des instances + +À la différence de leurs homologues publiques, les méthodes privées des instances : + +- Sont installées immédiatement avant que les champs des instances soient installés +- Sont uniquement disponibles pour les instances de la classe, et pas sur sa propriété `.prototype` + +```js +class ClasseAvecMethodePrivee { + #methodePrivee() { + return 42; + } + + methodePublique() { + return this.#methodePrivee(); + } +} + +const instance = new ClasseAvecMethodePrivee(); +console.log(instance.methodePublique()); // 42 +``` + +Les méthodes privées des instances peuvent être des générateurs, des méthodes asynchrones, des fonctions de génération asynchrone. Il est aussi possible de créer des accesseurs et mutateurs privés en suivant les mêmes règles de syntaxe que leurs homologues publiques ([accesseur](/fr/docs/Web/JavaScript/Reference/Functions/get) et [mutateur](/fr/docs/Web/JavaScript/Reference/Functions/set)). + +```js +class ClasseAvecAccesseurPrive { + #message; + + get #messageDecore() { + return `🎬${this.#message}🛑`; + } + set #messageDecore(msg) { + this.#message = msg; + } + + constructor() { + this.#messageDecore = "Coucou le monde"; + console.log(this.#messageDecore); + } +} + +new ClasseAvecAccesseurPrive(); // 🎬Coucou le monde🛑 +``` + +À la différence des méthodes publiques, les méthodes privées ne sont pas accessibles sur la propriété `.prototype` de leur classe. + +```js +class C { + #methode() {} + + static getMethode(x) { + return x.#methode; + } +} + +console.log(C.getMethode(new C())); // [Function: #methode] +console.log(C.getMethode(C.prototype)); // TypeError: Receiver must be an instance of class C +``` + +#### Méthodes privées statiques + +Comme leurs homologues publiques, les méthodes privées statiques : + +- Sont ajoutées au constructeur de la classe au moment de l'évaluation de la classe +- Sont uniquement disponibles sur la classe elle-même (et non sur les instances). + +```js +class ClasseAvecMethodePriveeStatique { + static #methodePriveeStatique() { + return 42; + } + + static methodeStatiquePublique() { + return ClasseAvecMethodePriveeStatique.#methodePriveeStatique(); + } +} + +console.log(ClasseAvecMethodePriveeStatique.methodeStatiquePublique()); // 42 +``` + +Les méthodes privées statiques peuvent être des générateurs, des fonctions asynchrones, ou des générateurs asynchrones. + +La même restriction évoquée pour les champs statiques privés s'applique et peut mener à des comportements inattendus lorsqu'on utilise `this`. Dans l'exemple suivant, quand on essaie d'appeler `SousClasse.methodeStatiquePublique()`, `this` fait référence à la classe `SousClasse` (et non à la classe `ClasseAvecMethodePriveeStatique`), ce qui entraîne une exception `TypeError`. + +```js +class ClasseAvecMethodePriveeStatique { + static #methodePriveeStatique() { + return 42; + } + + static methodeStatiquePublique() { + return this.#methodePriveeStatique(); + } +} + +class SousClasse extends ClasseAvecMethodePriveeStatique {} + +console.log(SousClasse.methodeStatiquePublique()); // TypeError: Cannot read private member #methodePriveeStatique from an object whose class did not declare it +``` + +### Simuler des constructeurs privés + +Dans d'autres langages, il est possible d'indiquer un constructeur comme privé, ce qui empêche d'instancier la classe en dehors d'elle-même. Seules des méthodes statiques de construction peuvent être utilisées pour créer des instances, voire il n'est pas possible de créer des instances. JavaScript ne dispose pas d'une syntaxe native pour ce faire, mais on peut y parvenir en utilisant un marqueur statique privé. + +```js +class ConstructeurPrive { + static #estUneConstructionInterne = false; + + constructor() { + if (!ConstructeurPrive.#estUneConstructionInterne) { + throw new TypeError("ConstructeurPrive n'est pas constructible"); + } + ConstructeurPrive.#estUneConstructionInterne = false; + // La suite de la logique d'initialisation… + } + + static create() { + ConstructeurPrive.#estUneConstructionInterne = true; + const instance = new ConstructeurPrive(); + return instance; + } +} + +new ConstructeurPrive(); // TypeError: ConstructeurPrive n'est pas constructible +ConstructeurPrive.create(); // ConstructeurPrive {} +``` + +## Spécifications + +{{Specifications}} + +## Compatibilité des navigateurs + +{{Compat}} + +## Voir aussi + +- [Le guide Utiliser les classes](/fr/docs/Web/JavaScript/Guide/Using_classes) +- [Classes](/fr/docs/Web/JavaScript/Reference/Classes) +- [Les champs de classe publics](/fr/docs/Web/JavaScript/Reference/Classes/Public_class_fields) +- [`class`](/fr/docs/Web/JavaScript/Reference/Statements/class) +- [La FAQ sur la syntaxe des champs privés (en anglais)](https://github.com/tc39/proposal-class-fields/blob/main/PRIVATE_SYNTAX_FAQ.md) dans la proposition TC39 relative aux champs de classe +- [La sémantique des différents éléments de classe JavaScript (en anglais)](https://rfrn.org/~shu/2018/05/02/the-semantics-of-all-js-class-elements.html), par Shu-yu Guo (2018) +- [Champs de classe publics et privés (en anglais)](https://v8.dev/features/class-fields) sur v8.dev (2018)