From 39f2114f9797eb51994966c6bb8ff1814c9a4da8 Mon Sep 17 00:00:00 2001 From: Florian Merz Date: Thu, 11 Feb 2021 12:36:08 +0100 Subject: unslug fr: move --- .../build_your_own_function/index.html | 241 ++++++ .../building_blocks/conditionals/index.html | 630 ++++++++++++++ .../javascript/building_blocks/events/index.html | 585 +++++++++++++ .../building_blocks/functions/index.html | 397 +++++++++ .../building_blocks/image_gallery/index.html | 163 ++++ .../fr/learn/javascript/building_blocks/index.html | 55 ++ .../building_blocks/looping_code/index.html | 873 +++++++++++++++++++ .../building_blocks/return_values/index.html | 182 ++++ .../client-side_storage/index.html | 881 ++++++++++++++++++++ .../drawing_graphics/index.html | 922 +++++++++++++++++++++ .../client-side_web_apis/fetching_data/index.html | 397 +++++++++ .../javascript/client-side_web_apis/index.html | 51 ++ .../client-side_web_apis/introduction/index.html | 307 +++++++ .../manipulating_documents/index.html | 332 ++++++++ .../third_party_apis/index.html | 440 ++++++++++ .../video_and_audio_apis/index.html | 518 ++++++++++++ .../learn/javascript/first_steps/arrays/index.html | 528 ++++++++++++ .../first_steps/methode_chaine_utile/index.html | 479 ----------- .../javascript/first_steps/tableaux/index.html | 528 ------------ .../test_your_skills_colon__arrays/index.html | 87 ++ .../index.html | 87 -- .../first_steps/useful_string_methods/index.html | 479 +++++++++++ files/fr/learn/javascript/index.html | 61 ++ .../adding_bouncing_balls_features/index.html | 208 +++++ .../index.html" | 208 ----- .../learn/javascript/objects/heritage/index.html | 260 ------ .../javascript/objects/inheritance/index.html | 260 ++++++ .../objects/js_orient\303\251-objet/index.html" | 278 ------- .../la_construction_d_objet_en_pratique/index.html | 316 ------- .../objects/object-oriented_js/index.html | 278 +++++++ .../objects/object_building_practice/index.html | 316 +++++++ .../objects/object_prototypes/index.html | 244 ++++++ .../javascript/objects/prototypes_objet/index.html | 244 ------ 33 files changed, 9435 insertions(+), 2400 deletions(-) create mode 100644 files/fr/learn/javascript/building_blocks/build_your_own_function/index.html create mode 100644 files/fr/learn/javascript/building_blocks/conditionals/index.html create mode 100644 files/fr/learn/javascript/building_blocks/events/index.html create mode 100644 files/fr/learn/javascript/building_blocks/functions/index.html create mode 100644 files/fr/learn/javascript/building_blocks/image_gallery/index.html create mode 100644 files/fr/learn/javascript/building_blocks/index.html create mode 100644 files/fr/learn/javascript/building_blocks/looping_code/index.html create mode 100644 files/fr/learn/javascript/building_blocks/return_values/index.html create mode 100644 files/fr/learn/javascript/client-side_web_apis/client-side_storage/index.html create mode 100644 files/fr/learn/javascript/client-side_web_apis/drawing_graphics/index.html create mode 100644 files/fr/learn/javascript/client-side_web_apis/fetching_data/index.html create mode 100644 files/fr/learn/javascript/client-side_web_apis/index.html create mode 100644 files/fr/learn/javascript/client-side_web_apis/introduction/index.html create mode 100644 files/fr/learn/javascript/client-side_web_apis/manipulating_documents/index.html create mode 100644 files/fr/learn/javascript/client-side_web_apis/third_party_apis/index.html create mode 100644 files/fr/learn/javascript/client-side_web_apis/video_and_audio_apis/index.html create mode 100644 files/fr/learn/javascript/first_steps/arrays/index.html delete mode 100644 files/fr/learn/javascript/first_steps/methode_chaine_utile/index.html delete mode 100644 files/fr/learn/javascript/first_steps/tableaux/index.html create mode 100644 files/fr/learn/javascript/first_steps/test_your_skills_colon__arrays/index.html delete mode 100644 files/fr/learn/javascript/first_steps/testes_vos_competence_colon__tableaux/index.html create mode 100644 files/fr/learn/javascript/first_steps/useful_string_methods/index.html create mode 100644 files/fr/learn/javascript/index.html create mode 100644 files/fr/learn/javascript/objects/adding_bouncing_balls_features/index.html delete mode 100644 "files/fr/learn/javascript/objects/ajouter_des_fonctionnalit\303\251s_\303\240_notre_d\303\251mo_de_balles_rebondissantes/index.html" delete mode 100644 files/fr/learn/javascript/objects/heritage/index.html create mode 100644 files/fr/learn/javascript/objects/inheritance/index.html delete mode 100644 "files/fr/learn/javascript/objects/js_orient\303\251-objet/index.html" delete mode 100644 files/fr/learn/javascript/objects/la_construction_d_objet_en_pratique/index.html create mode 100644 files/fr/learn/javascript/objects/object-oriented_js/index.html create mode 100644 files/fr/learn/javascript/objects/object_building_practice/index.html create mode 100644 files/fr/learn/javascript/objects/object_prototypes/index.html delete mode 100644 files/fr/learn/javascript/objects/prototypes_objet/index.html (limited to 'files/fr/learn/javascript') diff --git a/files/fr/learn/javascript/building_blocks/build_your_own_function/index.html b/files/fr/learn/javascript/building_blocks/build_your_own_function/index.html new file mode 100644 index 0000000000..6f53bebcd7 --- /dev/null +++ b/files/fr/learn/javascript/building_blocks/build_your_own_function/index.html @@ -0,0 +1,241 @@ +--- +title: Construire vos propres fonctions +slug: Apprendre/JavaScript/Building_blocks/Build_your_own_function +tags: + - Apprentissage + - Article + - Débutant + - Fonctions + - Guide + - I10n + - JavaScript + - Paramètres + - Scripting + - Tutoriel +translation_of: Learn/JavaScript/Building_blocks/Build_your_own_function +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Functions","Learn/JavaScript/Building_blocks/Return_values", "Learn/JavaScript/Building_blocks")}}
+ +

Dans l'article précédent, nous avons traité essentiellement de la théorie. Le présent article fournira une expérience pratique. Ici vous allez mettre en pratique ces connaissances en construisant vos propres fonctions. Tout au long, nous expliquerons également quelques détails supplémentaires concernant les fonctions.

+ + + + + + + + + + + + +
Prérequis :Savoir-faire de base, une compréhension minimale HTML et CSS, premiers pas en JavaScript, Fonctions — blocs de code réutilisables.
Objectif :Fournir quelques pratiques de création de fonctions, et expliquer un peu plus les détails associés.
+ +

Apprentissage actif : Construisons une fonction

+ +

La fonction que nous allons construire sera nommée displayMessage(). Elle affichera une boîte de message personnalisée sur une page web. Elle fonctionnera comme un substitut personnalisé de la fonction alert() du navigateur. Vous avez déjà vu cela avant, mais nous allons simplement nous rafraîchir la mémoire — essayez le code qui suit dans la console JavaScript de votre navigateur, sur n'importe quelle page que vous aimez :

+ +
alert('This is a message');
+ +

La fonction prend un seul argument en paramètre — la chaîne de caractères qui est affichée dans la boîte d'alerte. Vous pouvez essayer de varier la syntaxe de la chaîne pour modifier le message.

+ +

La fonction alert() est assez limitée : vous pouvez modifier le message, mais vous ne pouvez pas facilement faire varier autre chose, comme la couleur, une icône, ou autre chose. Nous en construirons une qui s'avérera plus amusante.

+ +
+

Note : Cet exemple devrait fonctionner correctement dans tous les navigateurs modernes, mais elle pourrait avoir un comportement un peu plus inattendu dans un navigateur ancien. Nous recommandons donc de faire cet exercice dans un navigateur moderne tel que Firefox, Opera, ou Chrome.

+
+ +

La fonction de base

+ +

Pour commencer, mettons en place une fonction de base.

+ +
+

Note : Pour les conventions de nommage des fonctions, vous devez suivre les mêmes règles que les conventions de noms de variables. Ce qui est bien, c'est que vous pouvez les différencier — les noms de fonctions se terminent par des parenthèses, pas les variables.

+
+ +
    +
  1. Commencez par faire une copie locale du fichier function-start.html. Vous pourrez voir que le code HTML est simple — l'élément body ne contient qu'un seul bouton. Nous avons également ajouté quelques règles CSS de base pour styliser la boîte de message personnalisée, et un élément {{htmlelement("script")}} pour écrire notre code JavaScript.
  2. +
  3. Ensuite, ajoutez le code ci-dessous à l'intérieur de l'élément <script> : +
    function displayMessage() {
    +
    +}
    + Nous commençons avec le mot-clé function, qui signifie que nous définissons une fonction. Celui-ci est suivi par le nom que nous voulons donner à notre fonction, des parenthèses et des accolades. Tous les paramètres que nous voulons donner à notre fonction vont à l'intérieur des parenthèses, et le code qui s'exécute lorsque nous appelons la fonction va à l'intérieur des accolades.
  4. +
  5. Enfin, ajoutez le code suivant à l'intérieur des accolades : +
    var html = document.querySelector('html');
    +
    +var panel = document.createElement('div');
    +panel.setAttribute('class', 'msgBox');
    +html.appendChild(panel);
    +
    +var msg = document.createElement('p');
    +msg.textContent = 'This is a message box';
    +panel.appendChild(msg);
    +
    +var closeBtn = document.createElement('button');
    +closeBtn.textContent = 'x';
    +panel.appendChild(closeBtn);
    +
    +closeBtn.onclick = function() {
    +  panel.parentNode.removeChild(panel);
    +}
    +
  6. +
+ +

Étant donné qu'il y a pas mal de code à analyser, allons-y pas à pas.

+ +

La première ligne utilise une fonction de l'API DOM appelée {{domxref("document.querySelector()")}} pour sélectionner l'élément {{htmlelement("html")}} et stocker une référence vers cet élément dans une variable appelée html, de façon à pouvoir l'utiliser plus tard :

+ +
var html = document.querySelector('html');
+ +

La section suivante utilise une autre fonction de l'API DOM appelée {{domxref("Document.createElement()")}} pour créer un élément {{htmlelement("div")}} et stocker une référence vers lui dans une variable appelée panel (Dans la suite de l'article, nous parlerons simplement du panneau <div>.). Cet élément sera le conteneur extérieur de notre boîte de message.

+ +

Puis, nous utilisons encore une autre fonction de l'API DOM appelée {{domxref("Element.setAttribute()")}} pour ajouter un attribut class à notre panneau qui aura pour valeur msgBox. Ceci rendra plus facile la mise en forme de l'élément — si vous regardez le CSS de la page, vous verrez que nous utilisons un sélecteur de classe .msgBox dans le but de styliser la boîte de message ainsi que son contenu.

+ +

Finallement, nous appelons une fonction du DOM nommée {{domxref("Node.appendChild()")}} sur la variable html créée précédemment, qui insère un élément, en tant qu'enfant, à l'intérieur d'un autre. Nous spécifions le panneau <div> (panel) comme l'enfant que nous voulons ajouter à l'intérieur de l'élément <html>. Nous avons besoin de le faire puisque l'élément que nous avons créé ne peut pas apparaître de lui-même sur la page — nous avons besoin de préciser où le mettre.

+ +
var panel = document.createElement('div');
+panel.setAttribute('class', 'msgBox');
+html.appendChild(panel);
+ +

Les deux sections suivantes font usage des mêmes fonctions createElement() et appendChild() que nous avons déjà vu pour créer deux nouveaux éléments — l'un {{htmlelement("p")}} et l'autre {{htmlelement("button")}} —  et pour les insèrer dans la page en tant qu'enfant du panneau <div>. On utilise leur propriété {{domxref("Node.textContent")}} — qui représente le contenu textuel d'un élément — pour insérer un message à l'intérieur du paragraphe, ainsi qu'un 'x' à l'intérieur du bouton. Ce bouton sera cliqué / activé quand l'utilisateur voudra fermer la boîte de message.

+ +
var msg = document.createElement('p');
+msg.textContent = 'This is a message box';
+panel.appendChild(msg);
+
+var closeBtn = document.createElement('button');
+closeBtn.textContent = 'x';
+panel.appendChild(closeBtn);
+ +

Finalement, nous utilisons un gestionnaire d'évènements {{domxref("GlobalEventHandlers.onclick")}} de sorte qu'un clic sur le bouton déclenche le bout de code chargé de supprimer la totalité du panneau de la page — c'est-à-dire fermer la boîte de message.

+ +

Le gestionnaire onclick est une propriété disponible sur le bouton (en fait, sur n'importe quel élément de la page) qui pourra se voir transmettre une fonction en paramètre pour spécifier quel morceau de code sera déclenché quand le bouton sera cliqué. Vous en apprendrez bien plus dans notre article sur les évènements. Nous avons passé à notre gestionnaire  onclick une fonction anonyme, qui contient le code exécuté quand le bouton est cliqué. L'instruction définie dans la fonction utilise la fonction de l'API DOM {{domxref("Node.removeChild()")}} pour indiquer que nous tenons à supprimer un élément enfant spécifique de l'élément HTML — dans notre cas le panneau <div>.

+ +
closeBtn.onclick = function() {
+  panel.parentNode.removeChild(panel);
+}
+ +

Au final, l'intégralité du bloc de code génère un bloc de code HTML et l'insère dans la page, ce qui ressemble à ça :

+ +
<div class="msgBox">
+  <p>This is a message box</p>
+  <button>x</button>
+</div>
+ +

Ça nous a fait beaucoup de code à passer en revue — ne vous inquiétez pas trop si vous ne vous souvenez pas exactement de comment chaque instruction fonctionne ! Bien que la partie principale sur laquelle nous voulions mettre l'accent ici est la structure de la fonction et son utilisation, nous avons voulu montrer quelque chose d'intéressant pour mettre en valeur cet exemple.

+ +

Appeler la fonction

+ +

À présent, nous avons notre fonction définie comme il faut dans notre balise <script>, mais il ne se passera rien si on laisse les choses en l'état.

+ +
    +
  1. Ajoutez la ligne suivante au-dessous de votre fonction pour l'appeler : +
    displayMessage();
    + Cette ligne appelle la fonction en la faisant fonctionner immédiatement. Lorsque vous enregistrez votre code et rechargez la page dans le navigateur, vous voyez la petite boîte de message apparaître immédiatement, une seule fois. Après tout, nous ne l'appelons bien qu'une fois.
  2. +
  3. +

    Maintenant, ouvrez vos outils de développement sur la page d'exemple, allez à la console JavaScript et tapez-y la ligne à nouveau, vous verrez qu'elle apparaît encore une fois ! C'est génial, nous avons maintenant une fonction réutilisable que nous pouvons appeler chaque fois que nous le voulons.

    + +

    Cela dit, nous voulons probablement qu'elle apparaisse en réponse aux actions de l'utilisateur ou du système. Dans une application réelle, une telle boîte de message serait probablement appelée en réponse à de nouvelles données disponibles, si une erreur s'est produite, si l'utilisateur essaie de supprimer son profil ("Êtes vous sûr de vouloir réaliser cette action ?"), ou encore si l'utilisateur ajoute un nouveau contact et que l'opération se termine avec succès, etc.

    + +

    Dans cette démo, nous faisons apparaître le message quand l'utilisateur clique sur le bouton.

    +
  4. +
  5. Supprimez la ligne précédente que vous avez ajoutée.
  6. +
  7. Ensuite, vous sélectionnerez le bouton et stockerez une référence vers celui-ci dans une variable. Ajoutez la ligne suivante à votre code, au-dessus de la définition de fonction : +
    var btn = document.querySelector('button');
    +
  8. +
  9. Enfin, ajoutez la ligne suivante à la précédente : +
    btn.onclick = displayMessage;
    + D'une manière similaire à notre ligne closeBtn.onclick... à l'intérieur de la fonction, ici, nous appelons un certain code en réponse à un clic sur un bouton. Mais dans ce cas, au lieu d'appeler une fonction anonyme contenant du code, nous appelons directement notre nom de fonction.
  10. +
  11. Essayez d'enregistrer et de rafraîchir la page, maintenant vous devriez voir la boîte de message s'afficher lorsque vous cliquez sur le bouton.
  12. +
+ +

Vous vous demandez peut-être pourquoi nous n'avons pas inclus les parenthèses après le nom de la fonction. C'est parce que nous ne voulons pas appeler la fonction immédiatement, seulement après que le bouton aura été cliqué. Si vous modifiez la ligne pour :

+ +
btn.onclick = displayMessage();
+ +

Enregistrez et rafraîchissez la page, vous verrez que la boîte de message apparaît sans que le bouton ait été cliqué ! Dans ce contexte, les parenthèses sont parfois appelées "opérateur d'appel / invocation de fonction". Vous ne les utilisez que lorsque vous souhaitez exécuter la fonction immédiatement dans la portée actuelle. Dans le même ordre d'idée, le code à l'intérieur de la fonction anonyme n'est pas exécuté immédiatement, car il se trouve à l'intérieur de la portée de la fonction.

+ +

Si vous avez essayé la dernière expérimentation, assurez-vous d'annuler la dernière modification avant de poursuivre.

+ +

Améliorer la fonction à l'aide de paramètres

+ +

En l'état, la fonction n'est pas très utile — on ne veut pas montrer le même message par défaut à chaque fois. Améliorons la en ajoutant quelques paramètres, ils permettront d'appeler la fonction avec différentes options.

+ +
    +
  1. Premièrement, mettons à jour la première ligne : +
    function displayMessage() {
    + par : + +
    function displayMessage(msgText, msgType) {
    + Maintenant, quand nous appelons la fonction, nous pouvons fournir deux valeurs de variables entre les parenthèses : une pour spécifier le message à afficher dans la boîte, l'autre pour le type de message.
  2. +
  3. Pour faire usage du premier paramètre, mettez à jour la ligne suivante à l'intérieur de votre fonction : +
    msg.textContent = 'This is a message box';
    + avec : + +
    msg.textContent = msgText;
    +
  4. +
  5. Vous devez maintenant mettre à jour votre appel de fonction pour inclure un texte de message mis à jour. Modifiez la ligne suivante : +
    btn.onclick = displayMessage;
    + par ce bloc : + +
    btn.onclick = function() {
    +  displayMessage('Woo, this is a different message!');
    +};
    + Si nous voulons spécifier des paramètres à l'intérieur des parenthèses pour la fonction que nous appelons, alors nous ne pouvons pas l'appeler directement — nous avons besoin de la mettre à l'intérieur d'une fonction anonyme de sorte qu'elle n'est pas dans la portée immédiate et n'est donc pas appelée immédiatement. Maintenant, elle ne sera pas appelée tant que le bouton ne sera pas cliqué.
  6. +
  7. Rechargez et essayez le code à nouveau et vous verrez qu'il fonctionne toujours très bien, sauf que maintenant vous pouvez également modifier le message à l'intérieur du paramètre pour obtenir des messages différents affichés dans la boîte !
  8. +
+ +

Un paramètre plus complexe

+ +

Passons au paramètre suivant. Celui-ci va demander un peu plus de travail — selon la valeur du paramètre msgType, la fonction affichera une icône et une couleur d'arrière-plan différentes.

+ +
    +
  1. Tout d'abord, téléchargez les icônes nécessaires à cet exercice (warning et chat) depuis GitHub. Enregistrez-les dans un nouveau dossier appelé icons dans le même répertoire que votre fichier HTML. + +
    Note : icônes warning et chat trouvés sur iconfinder.com, et créés par Nazarrudin Ansyari. Merci !
    +
  2. +
  3. Ensuite, trouvez le CSS à l'intérieur de votre fichier HTML. Nous ferons quelques changements pour faire place aux icônes. Tout d'abord, mettez à jour la largeur .msgBox en changeant : +
    width: 200px;
    + par : + +
    width: 242px;
    +
  4. +
  5. Ensuite, ajoutez les lignes à l'intérieur de la règle CSS .msgBox p { ... } : +
    padding-left: 82px;
    +background-position: 25px center;
    +background-repeat: no-repeat;
    +
  6. +
  7. Maintenant, nous devons ajouter du code à notre fonction displayMessage() pour gérer l'affichage de l'icône. Ajoutez le bloc suivant juste au dessus de l'accolade fermante "}" de votre fonction : +
    if (msgType === 'warning') {
    +  msg.style.backgroundImage = 'url(icons/warning.png)';
    +  panel.style.backgroundColor = 'red';
    +} else if (msgType === 'chat') {
    +  msg.style.backgroundImage = 'url(icons/chat.png)';
    +  panel.style.backgroundColor = 'aqua';
    +} else {
    +  msg.style.paddingLeft = '20px';
    +}
    + Ici, quand msgType a la valeur 'warning', l'icône d'avertissement est affichée et le fond du panneau prend la couleur rouge. Si msgType a la valeur 'chat', l'icône de chat est affichée et l'arrière-plan du panneau est bleu. Si le paramètre msgType n'a pas de valeur du tout (ou s'il a une valeur totalement différente), alors la partie du code contenue dans else { ... } est exécutée : le paragraphe prend un padding par défaut et il n'y a ni icône ni couleur d'arrière-plan. En fait, on fournit un état par défaut si aucun paramètre msgType n'est fourni, ce qui signifie qu'il s'agit d'un paramètre facultatif !
  8. +
  9. Nous allons tester notre fonction mise à jour, essayez de mettre à jour l'appel displayMessage() : +
    displayMessage('Woo, this is a different message!');
    + par soit l'un ou l'autre : + +
    displayMessage('Your inbox is almost full — delete some mails', 'warning');
    +displayMessage('Brian: Hi there, how are you today?','chat');
    + Vous pouvez voir à quel point notre petite (plus tant que cela maintenant) fonction est devenue utile :
  10. +
+ +
+

Note : Si vous avez des difficultés à mettre en œuvre cet exemple, n'hésitez pas à verifier votre code par rapport à la version définitive sur GitHub (aussi, vous pouvez tester la démo), ou nous demander de l'aide.

+
+ +

Conclusion

+ +

Vous êtes venu à bout de cette activité, félicitations ! Cet article vous a amené à travers tout le processus de construction d'une fonction pratique personnalisée, qui avec un peu plus de travail pourrait être transposée dans un projet réel. Dans l'article suivant, nous allons conclure l'apprentissage des fonctions en expliquant un autre concept connexe essentiel — les valeurs de retour.

+ + + +

{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Functions","Learn/JavaScript/Building_blocks/Return_values", "Learn/JavaScript/Building_blocks")}}

diff --git a/files/fr/learn/javascript/building_blocks/conditionals/index.html b/files/fr/learn/javascript/building_blocks/conditionals/index.html new file mode 100644 index 0000000000..b7fa0fa08c --- /dev/null +++ b/files/fr/learn/javascript/building_blocks/conditionals/index.html @@ -0,0 +1,630 @@ +--- +title: Prendre des décisions dans le code — conditions +slug: Apprendre/JavaScript/Building_blocks/conditionals +tags: + - Article + - CodingScripting + - Conditionnel + - Débutant + - JavaScript + - Switch + - conditions + - else + - if + - ternaire +translation_of: Learn/JavaScript/Building_blocks/conditionals +--- +

{{LearnSidebar}}

+ +

{{NextMenu("Apprendre/JavaScript/Building_blocks/Looping_code", "Apprendre/JavaScript/Building_blocks")}}

+ +

Dans tout langage de programmation, le code doit prendre des décisions et agir en fonction des différents paramètres. Par exemple dans un jeu, si le nombre de vies du joueur atteint 0, alors le jeu est terminé. Dans une application météo, si elle est consultée le matin, l'application montrera une image du lever de soleil ; l'application proposera des étoiles et la lune s'il fait nuit. Dans cet article nous allons découvrir comment ces instructions conditionnelles fonctionnent en JavaScript.

+ + + + + + + + + + + + +
Prérequis :Connaissances du vocabulaire informatique, compréhension des bases du HTML et des CSS, Premiers pas en JavaScript.
Objectif :Comprendre comment utiliser les structures conditionnelles en JavaScript.
+ +

Vous l'aurez à une condition !..

+ +

Les êtres humains (et d'autres animaux) prennent tout le temps des décisions qui affectent leur vie, de la plus insignifiante (« Est‑ce que je devrais prendre un biscuit ou deux ? ») à la plus importante (« Est‑ce que je dois rester dans mon pays natal et travailler à la ferme de mon père, ou déménager aux États-Unis et étudier l'astrophysique ? »)

+ +

Les instructions conditionnelles nous permettent de représenter ce genre de prise de décision en JavaScript, du choix qui doit être fait (par ex. « un biscuit ou deux »), à la conséquence de ces choix (il se peut que la conséquence de « manger un biscuit » soit « avoir encore faim », et celle de « manger deux biscuits » soit « se sentir rassasié, mais se faire gronder par maman pour avoir mangé tous les biscuits ».)

+ +

+ +

Instruction if ... else

+ +

Intéressons nous de plus près à la forme la plus répandue d'instruction conditionnelle que vous utiliserez en JavaScript — la modeste instruction if ... else.

+ +

Syntaxe élémentaire if ... else

+ +

La syntaxe élémentaire de if...else ressemble à cela en {{glossary("pseudocode")}}:

+ +
if (condition) {
+  code à exécuter si la condition est true
+} else {
+  sinon exécuter cet autre code à la place
+}
+ +

Ici nous avons:

+ +
    +
  1. Le mot‑clé if suivie de parenthèses.
  2. +
  3. Une condition à évaluer, placée entre les parenthèses (typiquement « cette valeur est‑elle plus grande que cet autre valeur ? » ou « cette valeur existe‑t‑elle ? »). Cette condition se servira des opérateurs de comparaison que nous avons étudié dans le précédent module, et renverra true ou false.
  4. +
  5. Une paire d'accolades, à l'intérieur de laquelle se trouve du code — cela peut être n'importe quel code voulu ; il sera exécuté seulement si la condition renvoie true.
  6. +
  7. Le mot‑clé else.
  8. +
  9. Une autre paire d'accolades, à l'intérieur de laquelle se trouve du code différent — tout code souhaité et il sera exécuté seulement si la condition ne renvoie pas true.
  10. +
+ +

Ce code est facile à lire pour une personne — il dit « si la condition renvoie true, exécuter le code A, sinon exécuter le code B ».

+ +

Notez qu'il n'est pas nécessaire d'inclure une instruction else et le deuxième bloc entre accolades — le code suivant est aussi parfaitement correct :

+ +
if (condition) {
+  code à exécuter si la condition est true
+}
+
+exécuter un autre code
+ +

Cependant, vous devez faire attention ici — dans ce cas, le deuxième bloc de code n'est pas controlé par l'instruction conditionnelle, donc il sera toujours exécuté, que la condition ait renvoyé true ou false. Ce n'est pas nécessairement une mauvaise chose, mais il se peut que ce ne soit pas ce que vous vouliez — le plus souvent vous voudrez exécuter un bloc de code ou l'autre, et non les deux.

+ +

Une dernière remarque, vous verrez quelques fois les instructions if...else écrites sans accolades, de manière abrégée, ainsi :

+ +
if (condition) code à exécuter si la condition est true
+else exécute un autre code à la place
+ +

Ce code est parfaitement valide, mais il n'est pas recommandé — il est nettement plus facile de lire le code et d'en déduire ce qui se passe si vous utilisez des accolades pour délimiter les blocs de code, des lignes séparées et des indentations.

+ +

Un exemple concret

+ +

Pour mieux comprendre cette syntaxe, prenons un exemple concret. Imaginez un enfant à qui le père ou la mère demande de l'aide pour une tâche. Le parent pourrait dire « Mon chéri, si tu m'aides en allant faire les courses, je te donnerai un peu plus d'argent de poche pour que tu puisses t'acheter ce jouet que tu voulais ». En JavaScript, on pourrait le représenter de cette manière :

+ +
let coursesFaites = false;
+
+if (coursesFaites === true) {
+  let argentDePoche = 10;
+} else {
+  let argentDePoche = 5;
+}
+ +

Avec un tel code, la variable coursesFaites renvoie toujours false, imaginez la déception de ce pauvre enfant. Il ne tient qu'à nous de fournir un mécanisme pour que le parent assigne true à la variable coursesFaites si l'enfant a fait les courses.

+ +
+

Note : Vous pouvez voir une version plus complète de cet exemple sur GitHub (ainsi qu'en version live.)

+
+ +

else if

+ +

Il n'y a qu'une alternative dans l'exemple précédent — mais qu'en est‑il si l'on souhaite plus de choix ?

+ +

Il existe un moyen d'enchaîner des choix / résultats supplémentaires à if...else — en utilisant else if entre. Chaque choix supplémentaire nécessite un bloc additionnel à placer entre if() { ... } et else { ... } — regardez l'exemple suivant plus élaboré, qui pourrait faire partie d'une simple application de prévisions météo:

+ +
<label for="weather">Select the weather type today: </label>
+<select id="weather">
+  <option value="">--Make a choice--</option>
+  <option value="sunny">Sunny</option>
+  <option value="rainy">Rainy</option>
+  <option value="snowing">Snowing</option>
+  <option value="overcast">Overcast</option>
+</select>
+
+<p></p>
+ +
const select = document.querySelector('select');
+const para = document.querySelector('p');
+
+select.addEventListener('change', setWeather);
+
+function setWeather() {
+  const choice = select.value;
+
+  if (choice === 'sunny') {
+    para.textContent = 'It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream.';
+  } else if (choice === 'rainy') {
+    para.textContent = 'Rain is falling outside; take a rain coat and a brolly, and don\'t stay out for too long.';
+  } else if (choice === 'snowing') {
+    para.textContent = 'The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman.';
+  } else if (choice === 'overcast') {
+    para.textContent = 'It isn\'t raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case.';
+  } else {
+    para.textContent = '';
+  }
+}
+ +

{{ EmbedLiveSample('else_if', '100%', 100) }}

+ +
    +
  1. Ici nous avons l'élément HTML {{htmlelement("select")}} nous permettant de sélectionner divers choix de temps et un simple paragraphe.
  2. +
  3. Dans le JavaScript, nous conservons une référence aussi bien à l'élément {{htmlelement("select")}} qu'à l'élément {{htmlelement("p")}}, et ajoutons un écouteur d'évènement à l'élément <select> de sorte que la fonction setWeather() soit exécutée quand sa valeur change.
  4. +
  5. Quand cette fonction est exécutée, nous commençons par assigner à la variable choice la valeur actuellement sélectionnée dans l'élément <select>. Nous utilisons ensuite une instruction conditionnelle pour montrer différents textes dans le paragraphe en fonction de la valeur de choice. Remarquez comment toutes les conditions sont testées avec des blocs else if() {...}, mis à part le tout premier testé avec un  bloc if() {...}.
  6. +
  7. Le tout dernier choix, à l'intérieur du bloc else {...}, est simplement une option de "secours" — le code qui s'y trouve ne sera exécuté que si aucune des conditions n'est true. Dans ce cas, il faut vider le texte du paragraphe si rien n'est sélectionné, par exemple si un utilisateur décide de resélectionner le texte à substituer « --Choisir-- » présenté au début.
  8. +
+ +
+

Note : Vous trouverez également cet exemple sur GitHub (ainsi qu'en version live ici.)

+
+ +

Une note sur les opérateurs de comparaison

+ +

Les opérateurs de comparaison sont utilisés pour tester les conditions dans nos instructions conditionnelles. Nous avons d'abord regardé les opérateurs de comparaison dans notre Mathématiques de base en JavaScript — nombres et opérateurs article. Nos choix sont :

+ + + +
+

Note : Revoyez le contenu du lien précédent si vous voulez vous rafraîchir la mémoire.

+
+ +

Nous souhaitons mentionner à propos des tests des valeurs booléennes (true/false) un modèle courant que vous rencontrerez souvent. Toute valeur autre que false, undefined, null, 0, NaN ou une chaîne vide  ('') renvoie true lorsqu'elle est testée dans une structure conditionnelle, vous pouvez donc simplement utiliser un nom de variable pour tester si elle est true, ou même si elle existe (c'est-à-dire si elle n'est pas undefined).
+ Par exemple :

+ +
const fromage = 'Comté';
+
+if (fromage) {
+  console.log('Ouaips ! Du fromage pour mettre sur un toast.');
+} else {
+  console.log('Pas de fromage sur le toast pour vous aujourd\'hui.');
+}
+ +

Et, revenant à notre exemple précédent sur l'enfant rendant service à ses parents, vous pouvez l'écrire ainsi :

+ +
let coursesFaites = false;
+
+if (coursesFaites) { // pas besoin d'écrire explicitement '=== true'
+  let argentDePoche = 10;
+} else {
+  let argentDePoche = 5;
+}
+ +

 if ... else imbriqué

+ +

Il est parfaitement correct d'ajouter une déclaration if...else à l'intérieur d'une autre — pour les imbriquer. Par exemple, nous pourrions mettre à jour notre application de prévisions météo pour montrer un autre ensemble de choix en fonction de la température :

+ +
if (choice === 'sunny') {
+  if (temperature < 86) {
+    para.textContent = 'Il fait ' + temperature + ' degrés dehors — beau et ensoleillé. Allez à la plage ou au parc et achetez une crème glacée.';
+  } else if (temperature >= 86) {
+    para.textContent = 'Il fait ' + temperature + ' degrés dehors — VRAIMENT CHAUD ! si vous voulez sortir, n\'oubliez pas de mettre de la crème solaire.';
+  }
+}
+ +

Même si tout le code fonctionne ensemble, chaque déclaration if...else fonctionne indépendamment de l'autre.

+ +

Opérateurs logiques AND, OR et NOT

+ +

Si vous voulez tester plusieurs conditions sans imbriquer des instructions if...else , les opérateurs logiques pourront vous rendre service. Quand ils sont utilisés dans des conditions, les deux premiers sont représentés comme ci dessous :

+ + + +

Pour vous donner un exemple de AND, le morceau de code précedent peut être réécrit ainsi :

+ +
if (choice === 'sunny' && temperature < 86) {
+  para.textContent = 'Il fait ' + temperature + ' degrés dehors — beau temps ensoleillé. Allez à la plage ou au parc et achetez une crème glacée.';
+} else if (choice === 'sunny' && temperature >= 86) {
+  para.textContent = 'Il fait ' + temperature + ' degrés dehors — VRAIMENT CHAUD ! Si vous voulez sortir, assurez‑vous d'avoir passé une crème solaire.';
+}
+ +

Ainsi, par exemple, le premier bloc de code ne sera exécuté que si choice === 'sunny' ET temperature < 86 renvoient tous deux true.

+ +

Voyons un petit exemple avec OR :

+ +
if (camionDeGlaces || etatDeLaMaison === 'on fire') {
+  console.log('Vous devriez sortir de la maison rapidement.');
+} else {
+  console.log('Vous pouvez probablement rester dedans.');
+}
+ +

Le dernier type d'opérateur logique, NOT, exprimé par l'opérateur !,  peut s'utiliser pour nier une expression. Combinons‑le avec OR dans cet exemple :

+ +
if (!(camionDeGlaces || etatDeLaMaison === 'on fire')) {
+  console.log('Vous pouvez probablement rester dedans.');
+} else {
+  console.log('Vous devriez sortir de la maison rapidement.');
+}
+ +

Dans cet extrait, si la déclaration avec OR renvoie true, l'opérateur NOT va nier l'ensemble : l'expression retournera donc false.

+ +

Vous pouvez combiner autant d'instructions logiques que vous le souhaitez, quelle que soit la structure. L'exemple suivant n'exécute le code entre accolades que si les deux instructions OR renvoient true, l'instruction AND recouvrante renvoie alors true :

+ +
if ((x === 5 || y > 3 || z <= 10) && (loggedIn || userName === 'Steve')) {
+  // exécuter le code
+}
+ +

Une erreur fréquente avec l'opérateur OR dans des instructions conditionnelles est de n'indiquer la variable dont vous testez la valeur qu'une fois, puis de donner une liste de valeurs sensées renvoyer true séparées par des || (OR) opérateurs. Par exemple :

+ +
if (x === 5 || 7 || 10 || 20) {
+  // exécuter le code
+}
+ +

Dans ce cas, la condition dans le if(...) sera toujours évaluée à vrai puisque 7 (ou toute autre valeur non nulle) est toujours true. Cette condition dit en réalité « si x est égal à 5, ou bien 7 est vrai » — ce qui est toujours le cas. Ce n'est pas ce que nous voulons logiquement ! Pour que cela fonctionne, vous devez définir un test complet entre chaque opérateur OR :

+ +
if (x === 5 || x === 7 || x === 10 ||x === 20) {
+  // exécuter le code
+}
+ +

Instruction switch

+ +

Les Instructions if...else  font bien le travail d'aiguiller la programmation selon des conditions, mais elles ne sont pas sans inconvénient. Elles sont principalement adaptées aux cas où vous avez un choix binaire, chacun nécessitant une quantité raisonnable de code à exécuter, et/ou au cas où les conditions sont complexes (par ex. plusieurs opérateurs logiques). Si vous voulez juste fixer la valeur d'une variable à un choix donné ou afficher une déclaration particulière en fonction d'une condition, cette syntaxe peut devenir un peu lourde, surtout si le nombre de choix est important.

+ +

Les instructions switch sont vos amies — elles prennent une seule valeur ou expression en entrée, puis examinent une palette de choix jusqu'à trouver celui qui correspond, et exécutent le code qui va avec. Voici un peu de pseudo-code, pour vous donner l'idée :

+ +
switch (expression) {
+  case choix1:
+    exécuter ce code
+    break;
+
+  case choix2:
+    exécuter ce code à la place
+    break;
+
+  // incorporez autant de case que vous le souhaitez
+
+  default:
+    sinon, exécutez juste ce code
+}
+ +

Ici nous avons

+ +
    +
  1. Le mot‑clé switch suivi de parenthèses.
  2. +
  3. Une expression ou une valeur mise entre les parenthèses.
  4. +
  5. Le mot‑clé case suivi d'une expression ou d'une valeur, et de deux‑points.
  6. +
  7. Le code exécuté si l'expression/valeur de case correspond à celles de switch.
  8. +
  9. Une déclaration break, suivie d'un point‑virgule. Si le choix précédent correspond à l'expression/valeur, le navigateur va stopper l'exécution du bloc de code ici et continuer après l'instruction switch.
  10. +
  11. Vous pouvez rajouter autant de cas que vous le souhaitez. (points 3–5)
  12. +
  13. Le mot‑clé default,  suivi d'une même structure de code qu'aux points 3-5, sauf que default n'a pas de choix après lui et n'a donc pas besoin de l'instruction break  puisqu'il n'y a plus rien à exécuter après ce bloc. C'est l'option default qui sera exécutée si aucun choix ne correspond.
  14. +
+ +
+

Note : Vous n'avez pas à inclure la section  default — elle peut être omise en toute sécurité s'il n'y a aucune chance que l'expression finisse par égaler une valeur inconnue. À contrario, vous devez l'inclure s'il est possible qu'il y ait des cas inconnus.

+
+ +

Un exemple de switch

+ +

Voyons un exemple concret — nous allons réécrire notre application de prévision météo en utilisant une instruction switch à la place :

+ +
<label for="weather">Select the weather type today: </label>
+<select id="weather">
+  <option value="">--Make a choice--</option>
+  <option value="sunny">Sunny</option>
+  <option value="rainy">Rainy</option>
+  <option value="snowing">Snowing</option>
+  <option value="overcast">Overcast</option>
+</select>
+
+<p></p>
+ +
const select = document.querySelector('select');
+const para = document.querySelector('p');
+
+select.addEventListener('change', setWeather);
+
+
+function setWeather() {
+  let choice = select.value;
+
+  switch (choice) {
+    case 'sunny':
+      para.textContent = 'It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream.';
+      break;
+    case 'rainy':
+      para.textContent = 'Rain is falling outside; take a rain coat and a brolly, and don\'t stay out for too long.';
+      break;
+    case 'snowing':
+      para.textContent = 'The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman.';
+      break;
+    case 'overcast':
+      para.textContent = 'It isn\'t raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case.';
+      break;
+    default:
+      para.textContent = '';
+  }
+}
+ +

{{ EmbedLiveSample('Un_exemple_de_switch', '100%', 100) }}

+ +
+

Note: Vous trouverez également cet exemple sur GitHub (voyez‑le en cours d'exécution ici aussi.)

+
+ +

Opérateur ternaire

+ +

Voici une dernière syntaxe que nous souhaitons vous présenter avant de nous amuser avec quelques exemples. L'opérateur ternaire ou conditionnel est un petit morceau de code qui teste une condition et renvoie une valeur ou expression si elle est true et une autre si elle est false — elle est utile dans certains cas, et occupe moins de place qu'un bloc if...else si votre choix est limité à deux possibilités à choisir via une condition true/false. Voici le pseudo‑code correspondant :

+ +
( condition ) ? exécuter ce code : exécuter celui‑ci à la place
+ +

Regardons cet exemple simple :

+ +
let formuleDePolitesse = ( est_anniversaire ) ? 'Bon anniversaire Mme Smith — nous vous souhaitons une belle journée !' : 'Bonjour Mme Smith.';
+ +

Ici, nous avons une variable nommée est_anniversaire — si elle est true, nous adressons à notre hôte un message de « Bon anniversaire » ; si ce n'est pas le cas, c'est-à-dire si est_anniversaire renvoie false, nous disons simplement « Bonjour ».

+ +

Exemple opérateur ternaire

+ +

L'opérateur ternaire ne sert pas qu'à définir des valeurs de variables ; vous pouvez aussi exécuter des fonctions, ou des lignes de code — ce que vous voulez. Voici un exemple concret de choix de thème où le style du site est déterminé grâce à un opérateur ternaire.

+ +
<label for="theme">Select theme: </label>
+<select id="theme">
+  <option value="white">White</option>
+  <option value="black">Black</option>
+</select>
+
+<h1>This is my website</h1>
+ +
const select = document.querySelector('select');
+const html = document.querySelector('html');
+document.body.style.padding = '10px';
+
+function update(bgColor, textColor) {
+  html.style.backgroundColor = bgColor;
+  html.style.color = textColor;
+}
+
+select.onchange = function() {
+  ( select.value === 'black' ) ? update('black','white') : update('white','black');
+}
+
+ +

{{ EmbedLiveSample('Exemple_opérateur_ternaire', '100%', 300, "", "", "hide-codepen-jsfiddle") }}

+ +

Nous mettons un élément {{htmlelement('select')}} pour choisir un thème (noir ou blanc), plus un simple élément {{htmlelement('h1')}} pour afficher un titre de site web. Nous avons aussi une fonction update(), qui prend deux couleurs en paramètre (entrées). La couleur de fond du site est déterminée par la couleur indiquée dans le premier paramètre fourni, et la couleur du texte par le deuxième.

+ +

Nous avons également mis un écouteur d'événement onchange qui sert à exécuter une fonction contenant un opérateur ternaire. Il débute par un test de condition — select.value === 'black'. Si le test renvoie true, nous exécutons la fonction update() avec les paramètres blanc et noir : cela signifie que le fond sera noir et le texte blanc. S'il renvoie false, nous exécutons update() avec les paramètres noir et blanc, les couleurs du site seront inversées.

+ +
+

Note: Vous trouverez également cet exemple sur GitHub (voyez‑le en cours d'exécution ici aussi.)

+
+ +

Apprentissage actif : un calendrier simple

+ +

Dans cet exemple nous allons vous aider à finaliser une application de calendrier simple. Dans le code, vous avez :

+ + + +

Vous aurez besoin d'écrire une instruction conditionnelle dans la fonction onchange, juste au dessous du commentaire // AJOUTER LA CONDITION ICI. Elle doit :

+ +
    +
  1. Noter le mois choisi (enregistré dans la variable choice. Ce doit être la valeur de l'élément <select> après un changement, "Janvier" par exemple).
  2. +
  3. Faire en sorte que la variable nommée days soit égale au nombre de jours du mois sélectionné. Pour ce faire, examinez le nombre de jours dans chaque mois de l'année. Vous pouvez ignorer les années bissextiles pour les besoins de cet exemple.
  4. +
+ +

Conseils :

+ + + +

Si vous faites une erreur, vous pouvez toujours réinitialiser l'exemple avec le bouton "Réinitialiser". Si vous êtes vraiment bloqué, pressez "Voir la solution".

+ + + +

{{ EmbedLiveSample('Playable_code', '100%', 1110, "", "", "hide-codepen-jsfiddle") }}

+ +

Activité : plus de choix de couleurs !

+ +

Nous allons reprendre l'exemple de l'opérateur ternaire vu plus haut et transformer cet opérateur ternaire en une directive switch  qui nous permettra une plus grande variété de choix pour le site web tout simple. Voyez l'élément {{htmlelement("select")}} — cette fois, il n'y a pas deux options de thème, mais cinq. Il vous faut ajouter une directive switch au dessous du commentaire  // AJOUT D'UNE DIRECTIVE SWITCH :

+ + + +

Si vous faites une erreur, vous pouvez toujours réinitialiser l'exemple avec le bouton « Réinitialiser ». Si vous êtes vraiment bloqué, pressez « Voir la solution ».

+ + + +

{{ EmbedLiveSample('Playable_code_2', '100%', 850) }}

+ +

Conclusion

+ +

C'est tout ce qu'il est nécessaire de connaître à propos des structures conditionnelles en JavaScript pour le moment ! Je pense que vous avez assurément compris ces concepts et travaillé les exemples aisément ; s'il y a quelque chose que vous n'avez pas compris, relisez cet article à nouveau, ou bien contactez‑nous pour une aide.

+ +

Voir aussi

+ + + +

{{NextMenu("Apprendre/JavaScript/Building_blocks/Looping_code", "Apprendre/JavaScript/Building_blocks")}}

+ +

Dans ce module

+ + diff --git a/files/fr/learn/javascript/building_blocks/events/index.html b/files/fr/learn/javascript/building_blocks/events/index.html new file mode 100644 index 0000000000..10f0118ecf --- /dev/null +++ b/files/fr/learn/javascript/building_blocks/events/index.html @@ -0,0 +1,585 @@ +--- +title: Introduction aux évènements +slug: Apprendre/JavaScript/Building_blocks/Evènements +tags: + - Article + - Codage + - Débutant + - Evènement + - Gestionnaire d'événement + - Guide + - JavaScript +translation_of: Learn/JavaScript/Building_blocks/Events +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Return_values","Learn/JavaScript/Building_blocks/Image_gallery", "Learn/JavaScript/Building_blocks")}}
+ +

Les événements sont des actions ou des occurrences qui se produisent dans le système que vous programmez et dont le système vous informe afin que vous puissiez y répondre d'une manière ou d'une autre si vous le souhaitez. Par exemple, si l'utilisateur clique sur un bouton d'une page Web, vous pouvez répondre à cette action en affichant une boîte d'information. Dans cet article, nous allons discuter de quelques concepts importants concernant les événements, et regarder comment ils fonctionnent dans les navigateurs. Ce ne sera pas une étude exhaustive; mais seulement ce que vous devez savoir à ce stade.

+ + + + + + + + + + + + +
Prérequis:Connaissances de base en informatique, une compréhension de base de HTML et CSS, Premiers pas en JavaScript.
Objectif:Comprendre la théorie fondamentale des événements, comment ils fonctionnent dans les navigateurs et comment les événements peuvent différer dans différents environnements de programmation.
+ +

Une série d'événements heureux

+ +

Comme mentionné ci-dessus, les événements sont des actions ou des occurrences qui se produisent dans le système que vous programmez le système déclenche un signal quelconque lorsqu'un événement se produit, et fournit également un mécanisme par lequel une  action est exécutée automatiquement (p.ex. un code en cours d'exécution) lorsque l'événement se produit. Par exemple, dans un aéroport, lorsque la piste est libre pour qu'un avion décolle, un signal est communiqué au pilote et, par conséquent, il commence à piloter l'avion.

+ +

+ +

Dans le cas du Web, les événements sont déclenchés à l'intérieur de la fenêtre du navigateur et tendent à être rattachés à un élément spécifique qui s'y trouve - il peut s'agir d'un élément unique, d'un ensemble d'éléments, du document HTML chargé dans l'onglet en cours ou toute la fenêtre du navigateur. Il y a beaucoup de types différents d'événements qui peuvent se produire, par exemple :

+ + + +

Vous vous en rendrez compte (notamment en jetant un coup d'œil à la section MDN Référence des événements ), il y a beaucoup d'événements auxquels vous pouvez répondre.
+
+ Chaque événement disponible a un gestionnaire d'événement, qui est un bloc de code (généralement une fonction JavaScript définie par l'utilisateur) qui sera exécuté lorsque l'événement se déclenchera. Lorsqu'un tel bloc de code est défini pour être exécuté en réponse à un déclenchement d'événement, nous disons que nous enregistrons un gestionnaire d'événements. Notez que les gestionnaires d'événements sont parfois appelés écouteurs d'événements - ils sont à peu près interchangeables pour ce qui nous concerne, même si à la rigueur, ils fonctionnent ensemble. L'écouteur écoute l'événement qui se produit et le gestionnaire est le code qui est exécuté en réponse à ce qui se passe.

+ +
+

Note: il est important de noter que les événements web ne font pas partie du langage du noyau JavaScript — ils sont définis comme faisant partie des APIs JavaScript intégrées du navigateur

+
+ +

Un exemple simple

+ +

Regardons un exemple simple pour expliquer ce que nous entendons ici. Vous avez déjà utilisé des événements et des gestionnaires d'événements dans de nombreux exemples de ce cours, mais récapitulons simplement pour consolider nos connaissances. Dans l'exemple suivant, nous avons un {{htmlelement ("bouton")}} unique, qui, lorsqu'il est pressé, fera passer l'arrière-plan à une couleur aléatoire:

+ +
<button>Change color</button>
+ + + +

Le JavaScript ressemblera à ça :

+ +
var btn = document.querySelector('button');
+
+function random(number) {
+  return Math.floor(Math.random()*(number+1));
+}
+
+btn.onclick = function() {
+  var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
+  document.body.style.backgroundColor = rndCol;
+}
+ +

 

+ +

Dans ce code, nous stockons une référence au bouton dans une variable appelée btn, en utilisant la fonction {{domxref ("Document.querySelector ()")}}. Nous définissons également une fonction qui renvoie un nombre aléatoire. La troisième partie du code est le gestionnaire d'événement. La variable btn pointe sur un élément <button> , et ce type d'objet a un certain nombre d'événements qui peuvent être déclenchés, et par conséquent, des gestionnaires d'événements sont disponibles. Nous sommes à l'écoute du déclenchement de l'événement click, en définissant la propriété onclick   du gestionnaire d'événements comme une fonction anonyme contenant du code qui génère une couleur RVB aléatoire et lui affecte la couleur d'arrière-plan <body> .
+
+ Ce code sera maintenant exécuté chaque fois que l'événement "click" se déclenchera sur l'élément <button>, c'est-à-dire chaque fois qu'un utilisateur cliquera dessus.

+ +

Vous pourrez voir cet exemple s'afficher sur toute la page en cliquant sur ce lien.

+ +

 

+ +

Ce ne sont pas que des pages web

+ +

Une autre chose qui mérite d'être mentionnée à ce stade est que les événements ne sont pas particuliers à JavaScript - la plupart des langages de programmation ont un certain type de modèle d'événement, et la façon dont cela fonctionne diffère souvent de celle de JavaScript. En fait, le modèle d'événement en JavaScript pour les pages Web diffère du modèle d'événement pour JavaScript tel qu'il est utilisé dans d'autres environnements.

+ +

Par exemple, Node.js est un runtime JavaScript très populaire qui permet aux développeurs d'utiliser JavaScript pour créer des applications réseau et serveur. Le modèle Node.js event model s'appuie sur des écouteurs pour écouter les événements et des émetteurs pour générer des événements périodiquement — bien qu'il ne le semble pas à première vue, le code est très différent, en particulier lorsqu'il utilise des fonctions comme on() pour enregistrer un écouteur d'événement, et once() pour enregistrer un écouteur d'événement qui s'efface après sa première exécution. le document HTTP connect event docs propose un bon exemple d'utilisation.

+ +

Comme autre exemple, vous pouvez désormais utiliser JavaScript pour créer des extensions inter-navigateurs comme améliorations de la fonctionnalité du navigateur à l'aide d'une technologie appelée WebExtensions. Le modèle d'événement est similaire au modèle d'événements Web, mais un peu différent — les écouteurs d'événements sont sensibles à la casse (p.ex.onMessage plutôt que onmessage), et doivent êtres combinés à la fonction addListener. Jetez un oeil à la page runtime.onMessage page pour voir un exemple.

+ +

Vous n'avez pas besoin de comprendre quoi que ce soit à propos d'autres environnements de ce type à ce stade de votre apprentissage; nous voulions juste préciser que les événements peuvent différer selon les environnements de programmation.

+ +

De quelle manière utiliser les événements Web ?

+ +

Il existe plusieurs façons d'ajouter un code d'écouteur d'événement aux pages Web afin qu'il soit exécuté lorsque l'événement associé se déclenche. Dans cette section, nous allons passer en revue les différents mécanismes et discuter de ceux que vous devriez utiliser.

+ +

Les propriétés du gestionnaire d'événement

+ +

Voici les propriétés qui existent pour contenir le code du gestionnaire d'événement que nous avons vu le plus fréquemment pendant le cours. Revenons à l'exemple ci-dessus :

+ +
var btn = document.querySelector('button');
+
+btn.onclick = function() {
+  var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
+  document.body.style.backgroundColor = rndCol;
+}
+ +

La propriété onclick est la propriété du gestionnaire d'événement utilisée dans cette situation. C'est essentiellement une propriété comme les autres disponibles sur le bouton (p.ex. btn.textContent, ou btn.style), mais d'un type spécial — lorsque vous la définissez comme étant égale à du code, ce code est exécuté lorsque l'événement se déclenche sur le bouton.

+ +

Vous pouvez également définir la propriété du gestionnaire d'événement comme étant égale au nom d'une fonction définie (comme nous l'avons vu dans Construire votre propre fonction). Le code suivant fonctionnera tout pareil:

+ +
var btn = document.querySelector('button');
+
+function bgChange() {
+  var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
+  document.body.style.backgroundColor = rndCol;
+}
+
+btn.onclick = bgChange;
+ +

De nombreuses propriétés de gestionnaire d'événement sont disponibles. Faisons une expérience.

+ +

Tout d'abord, faites une copie locale de random-color-eventhandlerproperty.html, et ouvrez-le dans votre navigateur. C'est juste une copie de l'exemple simple de couleur aléatoire avec lequel nous avons déjà joué dans cet article. Maintenant, changez btn.onclick pour lui attribuer, tour à tour, les différentes valeurs qui suivent, et observez le résultat:

+ + + +

Certains événements sont très généraux et disponibles presque partout (par exemple un gestionnaire onclick peut être enregistré sur presque n'importe quel élément), alors que certains sont plus spécifiques et seulement utiles dans certaines situations (par exemple, il est logique d'utiliser onplay seulement sur des éléments spécifiques, comme des {{htmlelement("video")}}).

+ +

Les gestionnaires d'événements en ligne : ne les utilisez pas !

+ +

Vous pourriez également voir un motif comme celui-ci dans votre code:

+ +
<button onclick="bgChange()">Press me</button>
+
+ +
function bgChange() {
+  var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
+  document.body.style.backgroundColor = rndCol;
+}
+ +
+

Note: Vous trouverez le code source complet de cet exemple sur GitHub (également le voir s'exécuter).

+
+ +

La première méthode d'enregistrement des gestionnaires d'événements trouvés sur le Web impliquait des attributs HTML du gestionnaire d'événement (c'est-à-dire les gestionnaires d'événements en ligne) comme celui présenté ci-dessus la valeur de l'attribut est littéralement le code JavaScript que vous souhaitez exécuter lorsque l'événement survient. L'exemple ci-dessus appelle une fonction définie dans un élément {{htmlelement("script")}} sur la même page, mais vous pouvez également insérer du JavaScript directement dans l'attribut comme par exemple :

+ +
<button onclick="alert('Hello, this is my old-fashioned event handler!');">Press me</button>
+ +

Vous trouverez des équivalents d'attributs HTML pour la plupart des propriétés du gestionnaire d'événement; cependant, vous ne devriez pas les utiliser ils sont considérés comme une mauvaise pratique. Il peut sembler facile d'utiliser un attribut de gestionnaire d'événement si vous voulez avancer rapidement, mais ils deviennent rapidement ingérables et inefficaces.
+
+ Pour commencer, ce n'est pas une bonne idée de mélanger votre HTML et votre JavaScript, car il deviennent difficile à analyser
garder votre JavaScript au même endroit est préférable; s'il se trouve dans un fichier séparé, vous pourrez l'appliquer à plusieurs documents HTML.

+ +

Même dans un fichier unique, les gestionnaires d'événement en ligne ne sont pas une bonne idée. Un bouton ça va, mais que faire si vous avez 100 boutons ? Vous devez ajouter 100 attributs au fichier; la maintenance se transformerait très vite en un cauchemar. Avec JavaScript, vous pouvez facilement ajouter une fonction de gestionnaire d'événement à tous les boutons de la page, peu importe leur nombre, en utilisant quelque chose comme ceci :

+ +
var buttons = document.querySelectorAll('button');
+
+for (var i = 0; i < buttons.length; i++) {
+  buttons[i].onclick = bgChange;
+}
+ +
+

Note: Séparer votre logique de programmation de votre contenu rend également votre site plus convivial pour les moteurs de recherche.

+
+ +

addEventListener() et removeEventListener()

+ +

Le dernier type de mécanisme d'événement est défini dans le Document Object Model (DOM) Level 2 Events , qui fournit aux navigateurs une nouvelle fonction: addEventListener(). Cela fonctionne de la même manière que les propriétés du gestionnaire d'événement, mais la syntaxe est évidemment différente. Nous pourrions réécrire notre exemple de couleur aléatoire comme ceci:

+ +
var btn = document.querySelector('button');
+
+function bgChange() {
+  var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
+  document.body.style.backgroundColor = rndCol;
+}
+
+btn.addEventListener('click', bgChange);
+ +
+

Note: Vous trouverez le code source complet de cet exemple sur GitHub (également le voir s'exécuter).

+
+ +

Dans la fonction addEventListener() , nous spécifions deux paramètres - le nom de l'événement pour lequel nous voulons enregistrer ce gestionnaire, et le code qui comprend la fonction du gestionnaire que nous voulons exécuter en réponse. Notez qu'il est parfaitement approprié de placer tout le code dans la fonction addEventListener(), dans une fonction anonyme, comme ceci:

+ +
btn.addEventListener('click', function() {
+  var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
+  document.body.style.backgroundColor = rndCol;
+});
+ +

Ce mécanisme a certains avantages par rapport aux mécanismes plus anciens discutés précédemment. Pour commencer, il existe une fonction réciproque, removeEventListener(), qui supprime un écouteur ajouté précédemment. Par exemple, cela supprimerait l'écouteur du premier bloc de code de cette section:

+ +
btn.removeEventListener('click', bgChange);
+ +

Ceci n'a pas beaucoup de sens pour les programmes simples et de petite taille, mais pour les programmes plus grands et plus complexes, cela peut améliorer l'efficacité, de nettoyer les anciens gestionnaires d'événements inutilisés. De plus, par exemple, cela vous permet d'avoir un même bouton qui effectue différentes actions dans des circonstances différentes - tout ce que vous avez à faire est d'ajouter / supprimer des gestionnaires d'événements convenablement.
+
+ D'autre part, vous pouvez également enregistrer plusieurs gestionnaires pour le même écouteur. Les deux gestionnaires suivants ne seraient pas appliqués:

+ +
myElement.onclick = functionA;
+myElement.onclick = functionB;
+ +

Comme la deuxième ligne remplacerait la valeur de onclick définie par le premier. Cependant, ceci fonctionnerait:

+ +
myElement.addEventListener('click', functionA);
+myElement.addEventListener('click', functionB);
+ +

Les deux fonctions seraient maintenant exécutées lorsque l'élément est cliqué.
+
+ En outre, il existe un certain nombre d'autres fonctionnalités et options puissantes disponibles avec ce mécanisme d'événement. Celles-ci sont un peu hors de propos pour cet article, mais si vous voulez en savoir plus sur elles, jetez un oeil aux pages de référence de 
addEventListener() et removeEventListener().

+ +

Quel mécanisme devrais-je utiliser ?

+ +

Parmi les trois mécanismes, vous ne devriez certainement pas utiliser les attributs du gestionnaire d'événement HTML - ceux-ci sont obsolètes et constituent une mauvaise pratique, comme mentionné ci-dessus.
+
+ Les deux autres sont relativement interchangeables, au moins pour des utilisations simples:

+  

+ + + +

Les principaux avantages du troisième mécanisme : vous pouvez supprimer le code du gestionnaire d'événement si nécessaire en utilisant removeEventListener(), et vous pouvez ajouter plusieurs écouteurs du même type aux éléments si nécessaire. Par exemple, vous pouvez appeler addEventListener('click', function() { ... }) sur un élément plusieurs fois, avec différentes fonctions spécifiées dans le deuxième argument. Cela est impossible avec les propriétés du gestionnaire d'événement car toute tentative ultérieure de définition d'une propriété remplacera les propriétés précédentes, par exemple:

+ +
element.onclick = function1;
+element.onclick = function2;
+etc.
+ +
+

Note: Si vous êtes appelé à prendre en charge des navigateurs plus anciens qu'Internet Explorer 8 dans votre travail, vous risquez de rencontrer des difficultés, car ces anciens navigateurs utilisent des modèles d'événements différents des nouveaux navigateurs. Mais n'ayez crainte, la plupart des bibliothèques JavaScript (par exemple jQuery) ont des fonctions intégrées qui permettent d'éliminer les différences entre navigateurs. Ne vous en faites pas trop à ce stade de votre parcours d'apprentissage.

+
+ +

D'autres concepts liés aux événements

+ +

Dans cette section, nous aborderons brièvement quelques concepts avancés relatifs aux événements. Il n'est pas important de les comprendre entièrement à ce stade, mais cela pourra servir à expliquer certains modèles de code que vous rencontrerez probablement de temps en temps.

+ +

L'objet événement

+ +

Parfois, dans une fonction de gestionnaire d'événement, vous pouvez voir un paramètre spécifié avec un nom tel que event, evt, ou simplement e . C'est ce qu'on appelle l'objet événement, qui est automatiquement transmis aux gestionnaires d'événements pour fournir des fonctionnalités et des informations supplémentaires. Par exemple, réécrivons légèrement notre exemple de couleur aléatoire:

+ +
function bgChange(e) {
+  var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
+  e.target.style.backgroundColor = rndCol;
+  console.log(e);
+}
+
+btn.addEventListener('click', bgChange);
+ +
+

Note: Vous trouverez le code source complet de cet exemple sur GitHub (également le voir s'exécuter).

+
+ +

Ici, vous pouvez voir que nous incluons un objet événement, e, dans la fonction, et dans la fonction définissant un style de couleur d'arrière-plan sur e.target - qui est le bouton lui-même. La propriété target de l'objet événement est toujours une référence à l'élément sur lequel l'événement vient de se produire. Donc, dans cet exemple, nous définissons une couleur d'arrière-plan aléatoire sur le bouton, pas sur la page.

+ +
+

Note: Vous pouvez utiliser n'importe quel nom pour l'objet d'événement - il vous suffit de choisir un nom que vous pouvez ensuite utiliser pour le référencer dans la fonction du gestionnaire d'événements. e/evt/event sont les plus couramment utilisés par les développeurs car ils sont courts et faciles à retenir. C'est toujours bon de s'en tenir à une norme.

+
+ +

e.targetest incroyablement utile lorsque vous voulez définir le même gestionnaire d'événements sur plusieurs éléments et affecter une action à chacun d'entre eux quand un événement se produit sur eux. Vous pourriez, par exemple, avoir un ensemble de 16 tuiles qui disparaissent quand on clique dessus. Il est utile de toujours pouvoir affecter une action à  e.target, plutôt que de devoir la sélectionner de manière plus difficile. Dans l'exemple suivant (voir useful-eventtarget.html pour le code source ; et ici pour le voir s'exécuter), nous avons créé 16 éléments {{htmlelement("div")}} avec JavaScript. Quand nous les sélectionnons tous en utilisant {{domxref("document.querySelectorAll()")}}, puis que nous faisons une boucle sur chacun d'eux, en ajoutant un gestionnaire onclick à chacun de sorte qu'une couleur aléatoire est appliquée lorsque l'élément est cliqué:

+ +
var divs = document.querySelectorAll('div');
+
+for (var i = 0; i < divs.length; i++) {
+  divs[i].onclick = function(e) {
+    e.target.style.backgroundColor = bgChange();
+  }
+}
+ +

Le résultat est le suivant (essayez de cliquer dessus - amusez-vous):

+ + + +

{{ EmbedLiveSample('Hidden_example', '100%', 400, "", "", "hide-codepen-jsfiddle") }}

+ +

La plupart des gestionnaires d'événements que vous rencontrerez ne disposent que d'un ensemble standard de propriétés et de fonctions (méthodes) disponibles sur l'objet événement (voir la liste complète sur {{domxref("Event")}} ). Cependant, certains gestionnaires plus avancés ajoutent des propriétés spécialisées contenant des données supplémentaires dont ils ont besoin pour fonctionner. Le Media Recorder API, par exemple, a un événement dataavailable , qui se déclenche quand un fichier audio ou vidéo a été enregistré et est disponible pour être utilisé (par exemple, pour l'enregistrer ou le lire). L'objet événement du gestionnaire ondataavailable correspondant dispose d'une propriété data contenant les données audio ou vidéo enregistrées pour vous permettre d'y accéder et de l'utiliser.

+ +

Éviter le comportement par défaut

+ +

Parfois, vous rencontrerez une situation où vous voudrez arrêter un événement qui adopte son comportement par défaut. L'exemple le plus courant est celui d'un formulaire Web, par exemple un formulaire d'inscription personnalisé. Lorsque vous remplissez les détails et appuyez sur le bouton "Soumettre", le comportement naturel consiste à soumettre les données à une page spécifiée sur le serveur pour traitement, et le navigateur redirige vers une page de "message de réussite" quelconque (ou la même page, si une autre n'est pas spécifiée.).
+
+ Le problème survient lorsque l'utilisateur n'a pas soumis les données correctement. En tant que développeur, vous devez arrêter la soumission au serveur et lui envoyer un message d'erreur indiquant ce qui ne va pas et ce qui doit être fait pour corriger les erreurs. Certains navigateurs prennent en charge les fonctions de validation automatique des données de formulaire, mais comme beaucoup ne le font pas, il est conseillé de ne pas vous y fier et d'implémenter vos propres contrôles de validation. Regardons un exemple simple.
+
+ Tout d'abord, un simple
formulaire HTML qui vous oblige à entrer votre nom et votre prénom:

+ +
<form>
+  <div>
+    <label for="fname">First name: </label>
+    <input id="fname" type="text">
+  </div>
+  <div>
+    <label for="lname">Last name: </label>
+    <input id="lname" type="text">
+  </div>
+  <div>
+     <input id="submit" type="submit">
+  </div>
+</form>
+<p></p>
+ + + +

Maintenant un peu de JavaScript - ici nous implémentons une vérification très simple dans un gestionnaire d'événement onsubmit (l'événement submit est renvoyé sur un formulaire quand il est soumis) qui vérifie si les champs de texte sont vides. Si c'est le cas, nous appelons la fonction preventDefault() sur l'objet événement - ce qui stoppe la soumission du formulaire - puis nous affichons un message d'erreur dans le paragraphe sous notre formulaire pour indiquer à l'utilisateur ce qui ne va pas :

+ +
var form = document.querySelector('form');
+var fname = document.getElementById('fname');
+var lname = document.getElementById('lname');
+var submit = document.getElementById('submit');
+var para = document.querySelector('p');
+
+form.onsubmit = function(e) {
+  if (fname.value === '' || lname.value === '') {
+    e.preventDefault();
+    para.textContent = 'You need to fill in both names!';
+  }
+}
+ +

Évidemment, cette validation est assez faible - cela n'empêcherait pas l'utilisateur de valider le formulaire avec des espaces ou des nombres entrés dans les champs, par exemple - mais cela est acceptable. Le résultat est le suivant :

+ +

{{ EmbedLiveSample('Preventing_default_behavior', '100%', 140, "", "", "hide-codepen-jsfiddle") }}

+ +
+

Note: pour le code source, voir preventdefault-validation.html (et le voir s'exécuter ici.)

+
+ +

Le bouillonnement et la capture

+ +

Le dernier sujet à aborder ici est quelque chose que vous ne rencontrerez pas souvent, mais cela peut être une vraie difficulté si vous ne le comprenez pas. Le bouillonnement et la capture d'événements sont deux mécanismes qui décrivent ce qui se passe lorsque deux gestionnaires du même type d'événement sont activés sur un même élément. Regardons un exemple pour faciliter cela - ouvrez l'exemple show-video-box.html dans un nouvel onglet (et le code source dans un autre). C'est également disponible en live ci-dessous.

+ + + +

{{ EmbedLiveSample('Hidden_video_example', '100%', 500, "", "", "hide-codepen-jsfiddle") }}

+ +

Ceci est un exemple assez simple qui montre et cache une balise {{htmlelement("div")}} avec une balise {{htmlelement("video")}} à l'intérieur:

+ +
<button>Display video</button>
+
+<div class="hidden">
+  <video>
+    <source src="rabbit320.mp4" type="video/mp4">
+    <source src="rabbit320.webm" type="video/webm">
+    <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p>
+  </video>
+</div>
+ +

Quand le {{htmlelement("button")}} est cliqué, la vidéo est affichée, en changeant l'attribut de classe sur la balise <div> de hidden à showing ( le CSS de l'exemple contient ces deux classes, qui positionnent respectivement la boîte hors de l'écran et sur l'écran.) :

+ +
btn.onclick = function() {
+  videoBox.setAttribute('class', 'showing');
+}
+ +

Nous ajoutons ensuite quelques gestionnaires d'événements onclick supplémentaires - le premier à <div> et le second à <video>. L'idée est que lorsque l'on clique sur la zone du <div> en dehors de la vidéo, la boîte doit être masquée à nouveau; Lorsque la vidéo elle-même est cliquée, la vidéo devrait commencer à jouer.

+ +
videoBox.onclick = function() {
+  videoBox.setAttribute('class', 'hidden');
+};
+
+video.onclick = function() {
+  video.play();
+};
+ +

Mais il y a un problème - actuellement, lorsque vous cliquez sur la vidéo, elle commence à jouer, mais cela entraîne le fait que <div> est également caché en même temps. C'est parce que la vidéo est dans le <div> - elle en fait partie - alors que cliquer sur la vidéo lance les deux gestionnaires d'événements ci-dessus.

+ +

Explication du bouillonnement et de la capture

+ +

Quand un événement se déclenche sur un élément qui a des éléments parents (p.ex. l'élément {{htmlelement("video")}} dans notre cas), les navigateurs modernes utilisent deux phases différentes: la phase de capture et la phase de bouillonnement.
+
+ Dans la phase de capture:

+ + + +

Dans la phase de bouillonnement, l'opposé exact se produit:
+
+      Le navigateur vérifie si l'élément qui a été cliqué a un gestionnaire d'événement
onclick enregistré dans la phase de bouillonnement et l'exécute si c'est le cas.
+      Ensuite, il passe à l'élément ancêtre immédiat et fait la même chose, puis le suivant, et ainsi de suite jusqu'à ce qu'il atteigne l'élément
<html>.

+ +

+ +

(Cliquez sur l'image pour l'agrandir et la voir traduite en français.)

+ +

Dans les navigateurs modernes, par défaut, tous les gestionnaires d'événements sont enregistrés dans la phase de bouillonnement. Ainsi, dans notre exemple actuel, lorsque vous cliquez sur la vidéo, l'événement click fait un bouillonnement de l'élément <video> vers l'élément <html>. Comme ceci :

+ + + +

Régler le problème avec stopPropagation()

+ +

C'est un comportement ennuyeux, mais il y a un moyen de l'éviter ! L'objet événement standard dispose d'une fonction appelée stopPropagation(), qui, lorsqu'il est invoqué sur l'objet événement d'un gestionnaire, fait en sorte que le gestionnaire soit exécuté, mais l'événement ne remonte pas plus haut dans la chaîne, et donc plus aucun autre gestionnaire ne sera exécuté.
+
+ Nous pouvons donc résoudre notre problème actuel en changeant la fonction du deuxième gestionnaire dans le bloc de code précédent comme ceci:

+ +
video.onclick = function(e) {
+  e.stopPropagation();
+  video.play();
+};
+ +

Vous pouvez faire une copie locale du code source show-video-box.html et le modifier vous-même ou regarder le résultat ici :  show-video-box-fixed.html (ou voir le code source).

+ +
+

Note: Pourquoi s'embêter à capturer et bouillonner ? Eh bien, aux heures sombres où les navigateurs étaien peu compatibles entre eux qu'ils ne le sont aujourd'hui, Netscape n'utilisait que la capture d'événements, et Internet Explorer n'utilisait que les bouillonnements. Quand le W3C a décidé d'essayer de normaliser le comportement et de parvenir à un consensus, ils en sont arrivés à ce système qui inclue les deux, qui est celui implémenté dans les navigateurs modernes.

+
+ +
+

Note: Comme mentionné ci-dessus, par défaut, tous les gestionnaires d'événements sont enregistrés dans la phase de bouillonnement, ce qui est plus logique la plupart du temps. Si vous voulez vraiment enregistrer un événement dans la phase de capture, vous pouvez le faire en enregistrant votre gestionnaire avec addEventListener(), et en positionnant la troisième propriété, qui est optionnelle, surtrue.

+
+ +

Délégation d'événement

+ +

Le bouillonnement nous permet également de tirer parti de la délégation d'événements - ce concept repose sur le fait que si vous voulez exécuter du code lorsque vous cliquez sur l'un des nombreux éléments enfants, vous pouvez définir l'écouteur d'événement sur leur parent et ainsi leur répercuter les événement, plutôt que de devoir définir l'écouteur d'événement sur chaque enfant individuellement.
+
+ Un bon exemple est une série d'éléments de liste - si vous voulez que chacun d'eux fasse apparaître un message lorsque vous cliquez dessus, vous pouvez définir l'écouteur d'événement
click sur la balise parente <ul>, et il apparaîtra sur les éléments de la liste.

+ +

Ce concept est expliqué plus loin sur le blog de David Walsh, avec de multiples exemples - voir How JavaScript Event Delegation Works.

+ +

Conclusion

+ +

Vous devriez maintenant maîtriser tout ce que vous devez savoir sur les événements Web à ce stade de votre apprentissage. Comme mentionné ci-dessus, les événements ne font pas vraiment partie du langage du noyau JavaScript principal - ils sont définis dans les API Web du navigateur.
+
+ En outre, il est important de comprendre que les différents contextes dans lesquels JavaScript est utilisé tendent à avoir des modèles d'événements différents - des API Web à d'autres domaines tels que WebExtensions du navigateur et Node.js (JavaScript côté serveur). Nous ne nous attendons pas à ce que vous compreniez tous ces domaines maintenant, mais cela aide certainement à comprendre les bases des événements à mesure que vous avancez dans l'apprentissage du développement Web.

+ +

S'il y a quelque chose que vous n'avez pas compris, n'hésitez pas à relire l'article, ou contactez-nous pour demander de l'aide.

+ +

Voir aussi

+ + + +

{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Return_values","Learn/JavaScript/Building_blocks/Image_gallery", "Learn/JavaScript/Building_blocks")}}

+ +

 

+ +

Dans ce module

+ + + +

 

diff --git a/files/fr/learn/javascript/building_blocks/functions/index.html b/files/fr/learn/javascript/building_blocks/functions/index.html new file mode 100644 index 0000000000..43f3e916e1 --- /dev/null +++ b/files/fr/learn/javascript/building_blocks/functions/index.html @@ -0,0 +1,397 @@ +--- +title: Fonctions — des blocs de code réutilisables +slug: Apprendre/JavaScript/Building_blocks/Fonctions +translation_of: Learn/JavaScript/Building_blocks/Functions +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Looping_code","Learn/JavaScript/Building_blocks/Build_your_own_function", "Learn/JavaScript/Building_blocks")}}
+ +

Les fonctions sont un autre concept essentiel de la programmation, qui permettent de stocker dans un bloc défini une partie de code qui effectue une seule tâche afin de l'appeler plus tard lorsque nous en avons besoin en utilisant une seule commande courte — au lieu de ré-écrire l'intégralité de ce code à chaque fois. Dans cet article nous explorons les concepts fondamentaux inhérents aux fonctions tels que la syntaxe de base, comment les définir et les invoquer, leur portée et leurs paramètres.

+ + + + + + + + + + + + +
Prerequis:Culture informatique basique, compréhension basique du HTML et du CSS, Premiers pas en JavaScript...
Objectif:Comprendre les concepts fondamentaux des fonctions JavaScript.
+ +

Où trouve-t'on des fonctions ?

+ +

En JavaScript, vous trouverez des fonctions partout. En fait, nous avons utilisé des fonctions depuis le début du cours ; nous n'en avons simplement pas beaucoup parlé. Toutefois, il est maintenant temps de parler des fonctions de manière explicite et d'explorer réellement leur syntaxe.

+ +

Presque à chaque fois que vous utilisez une structure de JavaScript qui utilise une paire de parenthèses — () — et que vous n'utilisez pas une structure usuelle et intégrée du langage telle que les boucles for, while ou do...while , ou une déclaration if...else , vous utilisez une fonction.

+ +

Les fonctions intégrées du navigateur

+ +

Nous avons beaucoup utilisé les fonctions intégrées du navigateur dans ce cours. Comme par exemple à chaque fois que nous avons manipulé une chaîne de caractères :

+ +
var myText = 'I am a string';
+var newString = myText.replace('string', 'sausage');
+console.log(newString);
+// La fonction replace () sélectionne une chaîne,
+// remplace une sous-chaîne par une autre, et renvoie
+// la nouvelle chaîne avec les modifications effectuées.
+ +

Ou à chaque fois que nous avons manipulé un tableau :

+ +
var myArray = ['I', 'love', 'chocolate', 'frogs'];
+var madeAString = myArray.join(' ');
+console.log(madeAString);
+// La fonction join() sélectionne un tableau, rassemble
+// tous les éléments du tableau dans une chaîne,
+// et renvoie cette nouvelle chaîne.
+ +

Ou à chaque fois que nous avons généré un nombre aléatoire :

+ +
var myNumber = Math.random();
+// la fonction random() génère un nombre aléatoire
+// entre 0 et 1, et renvoie
+// ce nombre
+ +

... nous avons utilisé une fonction !

+ +
+

Note : N'hésitez pas à copier ces lignes dans la console JavaScript de votre navigateur afin de vous familiariser à nouveau avec leur fonctionnalité si vous en ressentez le besoin.

+
+ +

Le langage Javascript a de nombreuses fonctions intégrées pour vous permettre de faire des choses utiles sans devoir écrire tout le code vous-même. En fait, certains codes que vous appelez quand invoquez (un mot sophistiqué pour dire lancer ou exécuter) une fonction intégrée du navigateur ne pourraient pas être écrits en JavaScript — la plupart de ces fonctions appellent des parties de code interne du navigateur qui est très majoritairement écrit en langages de bas niveau comme le C++, et non pas en langage web comme JavaScript.

+ +

Gardez à l'esprit que certaines fonctions intégrées du navigateur ne font pas partie du noyau du langage JavaScript — certaines font partie des APIs du navigateur qui sont construites à partir du langage par défaut pour apporter encore plus de fonctionnalités ( consultez cette section antérieure de notre cours pour une description plus détaillée ). Nous aborderons l'utilisation des APIs du navigateur plus en détail dans un module ultérieur.

+ +

Fonctions versus méthodes

+ +

Une chose que nous devons éclaircir avant d'aller plus loin — d'un point de vue technique les fonctions intégrées du navigateur ne sont pas des fonctions mais des méthodes. Cela peut vous effrayer ou vous désorienter mais n'ayez crainte — les mots fonction et méthode sont largement interchangeables, du moins pour ce qui nous concerne, à ce niveau de votre apprentissage.

+ +

La distinction réside dans le fait que les méthodes sont des fonctions définies à l'intérieur d'objets. Les fonctions intégrées au navigateur (méthodes) et les variables (que l'on appelle propriétés) sont stockées dans des objets structurés, pour rendre le code plus efficace et facile à manier.

+ +

Vous n'aurez pas besoin d'apprendre les rouages des objets structurés du JavaScript pour le moment — vous pouvez attendre un module ultérieur qui vous en apprendra tous les rouages internes et comment les créer par vous même. Pour le moment, nous souhaitons simplement éviter toute confusion possible entre méthode et fonction — car vous êtes susceptibles de rencontrer les deux termes si vous en recherchez les ressources disponibles sur le Web. 

+ +

Fonctions personnalisées

+ +

Nous avons également rencontré beaucoup de fonctions personnalisées dans le cours jusqu'ici — fonctions définies dans votre code, et non pas dans le navigateur. À chaque fois que vous voyez un nom personnalisé suivi de parenthèses, vous utilisez une fonction personnalisée. Dans notre exemple random-canvas-circles.html tiré de l'article les boucles dans le code (voir aussi le code source complet), nous avons inclus une fonction personnalisée draw()qui ressemblait à ça :

+ +
function draw() {
+  ctx.clearRect(0,0,WIDTH,HEIGHT);
+  for (var i = 0; i < 100; i++) {
+    ctx.beginPath();
+    ctx.fillStyle = 'rgba(255,0,0,0.5)';
+    ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
+    ctx.fill();
+  }
+}
+ +

Cette fonction dessine 100 cercles aléatoires dans un élément {{htmlelement("canvas")}}. À chaque fois que nous voulons faire cela, il suffit d'invoquer la fonction comme suit :

+ +
draw();
+ +

au lieu de devoir ré-écrire tout le code à chaque fois que nous voulons la répéter. De plus, les fonctions peuvent contenir tous les codes qu'il vous plaira — vous pouvez même appeler d'autres fonctions à l'intérieur d'une fonction. Par exemple, la fonction ci-dessus appelle la fonction random() trois fois, comme définie par le code suivant :

+ +
function random(number) {
+  return Math.floor(Math.random()*number);
+}
+ +

Nous avions besoin de cette fonction car la fonction intégrée du navigateur Math.random() génère uniquement un nombre décimal aléatoire compris entre 0 et 1 alors que nous voulions un nombre entier compris entre 0 et un nombre défini.

+ +

Invoquer des fonctions

+ +

Vous êtes probablement au clair avec cela maintenant, mais juste au cas où... pour utiliser une fonction après qu'elle ait été définie, vous devez la lancer - ou l'invoquer. Pour ce faire, vous devez inclure le nom de la fonction quelque part dans le code suivi par des parenthèses.

+ +
function myFunction() {
+  alert('hello');
+}
+
+myFunction()
+// appelle la fonction une fois
+ +

Fonctions anonymes

+ +

Vous pouvez rencontrer des fonctions définies et invoquées de manière légèrement différentes. Nous venons juste de créer une fonction comme celle-ci :

+ +
function myFunction() {
+  alert('hello');
+}
+ +

Mais vous pouvez également créer une fonction qui n'a pas de nom :

+ +
function() {
+  alert('hello');
+}
+ +

Ceci est une fonction anonyme — elle n'a pas de nom ! De plus, elle ne produira pas d'effet par elle-même. Les fonctions anonymes sont généralement utilisées en association avec un gestionnaire d'évènement, comme dans l'exemple suivant qui lance le code inscrit dans la fonction lorsque le bouton associé est cliqué :

+ +
var myButton = document.querySelector('button');
+
+myButton.onclick = function() {
+  alert('hello');
+}
+ +

Cet exemple ci-dessus nécessite qu'il y ait un élément HTML {{htmlelement("button")}} disponible sur la page afin qu'il puisse être cliqué. Vous avez déjà rencontré ce type de structure plusieurs fois dans ce cours et vous en apprendrez plus à son sujet lorsque vous en étudierez l'utilisation dans l'article suivant.

+ +

Vous pouvez également assigner une fonction anonyme en tant que valeur d'une variable, comme par exemple :

+ +
var myGreeting = function() {
+  alert('hello');
+}
+ +

Cette fonction peut désormais être invoquée en utilisant :

+ +
myGreeting();
+ +

Cela a pour effet d'attribuer un nom à la fonction ; vous pouvez également utiliser la fonction anonyme en tant que valeur de variables multiples, comme par exemple :

+ +
var anotherGreeting = function() {
+  alert('hello');
+}
+ +

Cette fonction peut désormais être invoquée en utilisant au choix :

+ +
myGreeting();
+anotherGreeting();
+ +

Cela peut toutefois générer de la confusion, donc ne le faites pas ! Lorsque l'on crée des fonctions, il vaut mieux se contenter de cette forme :

+ +
function myGreeting() {
+  alert('hello');
+}
+ +

Vous utiliserez principalement des fonctions anonymes simplement pour lancer une partie de code en réponse à un évènement — comme lorsqu'un bouton est cliqué — en utilisant un gestionnaire d'évènement. Cela devrait ressembler à ça :

+ +
myButton.onclick = function() {
+  alert('hello');
+  // Je peux mettre ici autant
+  // de code que je le souhaite
+}
+ +

Paramètres des fonctions

+ +

Certaines fonctions nécessitent que l'on définisse des paramètres lorsqu'on les appelle — ce sont des valeurs qui doivent êtres inclues dans les parenthèses de la fonction pour que celle-ci fonctionne correctement.

+ +
+

Note : Les paramètres sont parfois appelés arguments, propriétés ou encore attributs.

+
+ +

Par exemple, la fonction intégrée du navigateur Math.random() ne nécessite pas de paramètres. lorsqu'elle est appelée, elle renvoie toujours un nombre aléatoire compris entre 0 et 1 : 

+ +
var myNumber = Math.random();
+ +

La fonction de chaîne intégrée du navigateur replace() nécessite toutefois deux paramètres — la sous-chaîne qu'elle doit remplacer à l'intérieur de la chaîne, et la sous-chaîne par laquelle elle doit la remplacer :

+ +
var myText = 'I am a string';
+var newString = myText.replace('string', 'sausage');
+ +
+

Note : Quand vous devez définir plusieurs paramètres, ils doivent être séparés par des virgules.

+
+ +

Il est également à noter que parfois les paramètres sont optionnels — vous n'avez pas à les spécifier. Si vous ne le faites pas, la fonction va généralement adopter un comportement par défaut. Par exemple, la fonction de tableau join() a des paramètres optionnels :

+ +
var myArray = ['I', 'love', 'chocolate', 'frogs'];
+var madeAString = myArray.join(' ');
+// renvoie 'I love chocolate frogs'
+var madeAString = myArray.join();
+// renvoie 'I,love,chocolate,frogs'
+ +

Si aucun paramètre n'est inclus pour spécifier un caractère de jointure / délimitation, une virgule est utilisée par défaut.

+ +

La portée des fonctions et les conflits.

+ +

Parlons un peu de la {{glossary("portée")}} — un concept très important lorsque l'on a affaire à des fonctions. Lorsque vous créez une fonction, les variables et les autres choses qui sont définies à l'intérieur de la fonction ont leur propre portée, ce qui signifie qu'elles sont enfermées dans leur propre compartiment séparé et qu'elles ne peuvent pas être affectées par d'autres fonctions ou par le code en dehors de la fonction.

+ +

Le plus haut niveau en dehors de toutes vos fonctions est appelé la portée globale. Les valeurs définies dans la portée globale sont accessibles à partir de n'importe qu'elle partie du code.

+ +

Le JavaScript est construit de cette façon pour plusieurs raisons —  mais principalement à cause de la sécurité et de l'organisation. Parfois, vous ne voulez pas que vos variables soient accessibles depuis toutes les autres parties du code — des script externes appelés depuis l'extérieur de la fonction pourraient interférer avec votre code et causer des problèmes parce qu'ils utilisent les mêmes noms de variables que d'autres parties du code, provoquant des conflits. Cela peut être fait de manière malveillante ou simplement par accident.

+ +

Par exemple, disons que vous avez un fichier HTML qui appelle deux fichiers JavaScript externes, et que les deux ont une variable et une fonction définie qui utilisent le même nom :

+ +
<!-- Excerpt from my HTML -->
+<script src="first.js"></script>
+<script src="second.js"></script>
+<script>
+  greeting();
+</script>
+ +
// first.js
+var name = 'Chris';
+function greeting() {
+  alert('Hello ' + name + ': welcome to our company.');
+}
+ +
// second.js
+var name = 'Zaptec';
+function greeting() {
+  alert('Our company is called ' + name + '.');
+}
+ +

Les deux fonctions que vous voulez appeler s'appellent greeting(), mais vous ne pouvez accéder qu'à la fonction greeting() du second fichier second.js  — car celui-ci est appliqué au code HTML plus tard dans le code source, de sorte que sa variable et sa fonction écrasent celles du premier fichier first.js.

+ +
+

Note : Vous pouvez voir cet exemple s'exécuter sur GitHub (voir aussi le code source).

+
+ +

En conservant des parties de votre code enfermées dans des fonctions, vous évitez de tels problèmes. Cette procédure est considérée comme une bonne pratique.

+ +

C'est un peu comme au zoo. Les lions, zèbres, tigres et pingouins sont enfermés dans leurs propres enclos, et n'ont accès qu'aux éléments se trouvant à l'intérieur de leur enclos — de la même manière que la portée des fonctions. S'il leur était possible de pénétrer dans les autres enclos, des problèmes se produiraient. Au mieux, des animaux différents seraient dans l'inconfort au sein d'un habitat étranger — un lion ou un tigre se sentirait très mal dans l'environnement humide et glacé des pingouins. Au pire, les lions et les tigres pourraient essayer de manger les pingouins !

+ +

+ +

Le gardien du zoo est comme la portée globale — il ou elle a les clefs pour accéder à chaque enclos, pour l'approvisionner en nourriture, soigner les animaux malades, ...etc.

+ +

Apprentissage actif : Jouer avec la portée

+ +

Jetons un coup d'oeil à un exemple réel pour démontrer les effets de la portée.

+ +
    +
  1. Tout d'abord, faisons un copie locale de notre exemple function-scope.html. Celui-ci contient deux fonctions appelées a() et b(), et trois variables — x, y, and z — deux d'entre elles sont définies à l'intérieur de la fonction, et l'autre dans la portée globale. Il contient également une troisième fonction appelée output(), qui prend un seul paramètre et le renvoie dans un paragraphe de la page.
  2. +
  3. Ouvrez l'exemple ci-dessus dans un navigateur et dans un éditeur de texte.
  4. +
  5. Ouvrez la console JavaScript dans les outils de développement de votre navigateur et entrez la commande suivante : +
    output(x);
    + Vous devriez voir la valeur de la variable x renvoyée à l'écran.
  6. +
  7. Maintenant essayez d'entrer les commandes suivantes : +
    output(y);
    +output(z);
    + +

    Toutes les deux devraient vous renvoyer un message d'erreur du type : "ReferenceError: y is not defined". Pourquoi ? À cause de la portée de la fonction — y and z sont enfermées dans les fonctions a() et b(), donc output() ne peut pas les atteindre lorsqu'elles sont appelées depuis la portée globale.

    +
  8. +
  9. +

    Néanmoins, que se passe-t-il losqu'elles sont appelées de l'intérieur d'une autre fonction ? Essayer d'éditer a() et b() pour qu'elles aient la forme suivante :

    + +
    function a() {
    +  var y = 2;
    +  output(y);
    +}
    +
    +function b() {
    +  var z = 3;
    +  output(z);
    +}
    + Sauvegardez le code et rechargez-le dans votre navigateur, puis essayez d'appeler les fonctions a() et b() depuis la console JavaScript : + +
    a();
    +b();
    + Vous devriez voir les valeurs y and z renvoyées sur la page. Cela fonctionne très bien car la fonction output() est applée à l'intérieur des autres fonctions — dans la portée dans laquelle les variables qu'elle renvoie sont définies. La fonction output() est elle-même disponible n'importe où dans le code, car elle est définie dans la portée globale.
  10. +
  11. Maintenant essayer de mettre à jour le code comme ceci : +
    function a() {
    +  var y = 2;
    +  output(x);
    +}
    +
    +function b() {
    +  var z = 3;
    +  output(x);
    +}
    + Sauvegardez et rechargez à nouveau dans la console JavaScript :
  12. +
  13. +
    a();
    +b();
    + Les deux fonctions a() et b() appelées devraient renvoyer la valeur x — 1. Cela fonctionne très bien car même si la fonction output() n'est pas dans la même portée que celle dans laquelle  x est définie, x est une variable globale et donc elle est disponible dans n'importe quelle partie du code.
  14. +
  15. Pour finir, essayez de mettre à jour le code comme ceci : +
    function a() {
    +  var y = 2;
    +  output(z);
    +}
    +
    +function b() {
    +  var z = 3;
    +  output(y);
    +}
    +
  16. +
  17. Sauvegardez et rechargez à nouveau dans la console JavaScript : +
    a();
    +b();
    + Cette fois l'appel de a() et b() renverra l'erreur "ReferenceError: z is not defined"  — parce que l'appel de la fonction output() et des variables qu'elle essaie d'afficher ne sont pas définis dans les mêmes portées — les variables sont en effet invisibles pour cet appel de fonction.
  18. +
+ +
+

Note : Ces règles de portée ne s'appliquent pas aux boucles (ex. for() { ... }) ni aux instructions conditionnelles (ex. if() { ... }) — elles semblent très similaires, mais ce n'est pas la même chose ! Prenez garde de ne pas les confondre.

+
+ +
+

Note : Le message d'erreur ReferenceError: "x" is not defined est l'un des plus courant que vous pourrez rencontrer. S'il s'affiche et que vous êtes sûr d'avoir défini la variable en question, vérifiez quelle est sa portée.

+
+ + + +

Des fonctions à l'intérieur de fonctions

+ +
+
Gardez à l'esprit que vous pouvez appeler une fonction de n'importe où, même à l'intérieur d'une autre fonction. Ceci est souvent utilisé comme un moyen de garder le code bien organisé  si vous avez une grande fonction complexe, elle est plus facile à comprendre si vous la divisez en plusieurs sous-fonctions :
+
+ +
function myBigFunction() {
+  var myValue;
+
+  subFunction1();
+  subFunction2();
+  subFunction3();
+}
+
+function subFunction1() {
+  console.log(myValue);
+}
+
+function subFunction2() {
+  console.log(myValue);
+}
+
+function subFunction3() {
+  console.log(myValue);
+}
+
+ +

Assurez-vous simplement que les valeurs utilisées dans la fonction ont une portée correcte. L'exemple ci-dessus entraînerait une erreur ReferenceError: myValue is not defined, car bien que la valeur myValue  est définie dans la même portée que les appels de fonction, elle n'est pas définie dans les définitions de fonctions - le code réel qui est exécuté lorsque les fonctions sont appelées. Pour que cela fonctionne, vous devez passer la valeur dans la fonction en tant que paramètre, comme ceci :

+ +
function myBigFunction() {
+  var myValue = 1;
+
+  subFunction1(myValue);
+  subFunction2(myValue);
+  subFunction3(myValue);
+}
+
+function subFunction1(value) {
+  console.log(value);
+}
+
+function subFunction2(value) {
+  console.log(value);
+}
+
+function subFunction3(value) {
+  console.log(value);
+}
+ +

Conclusion

+ +

Cet article a exploré les concepts fondamentaux inhérents aux fonctions, ouvrant la voie au suivant dans lequel nous passerons à la pratique et vous guiderons à travers les étapes pour construire votre propre fonction personnalisée.

+ +

Voir aussi

+ + + + + +

{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Looping_code","Learn/JavaScript/Building_blocks/Build_your_own_function", "Learn/JavaScript/Building_blocks")}}

+ +

Dans ce module

+ + diff --git a/files/fr/learn/javascript/building_blocks/image_gallery/index.html b/files/fr/learn/javascript/building_blocks/image_gallery/index.html new file mode 100644 index 0000000000..07a51499fd --- /dev/null +++ b/files/fr/learn/javascript/building_blocks/image_gallery/index.html @@ -0,0 +1,163 @@ +--- +title: Galerie d'images +slug: Apprendre/JavaScript/Building_blocks/Image_gallery +tags: + - Apprendre + - Boucles + - Débutant + - Evaluation + - Gestionnaire d'événement + - JavaScript + - conditions + - 'l10n:priority' + - Écriture de code + - évènements +translation_of: Learn/JavaScript/Building_blocks/Image_gallery +--- +
{{LearnSidebar}}
+ +
{{PreviousMenu("Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}
+ +

Maintenant que nous avons examiné les blocs fondamentaux de construction de JavaScript,  nous allons tester vos connaissances sur les boucles, les fonctions, les conditions et les événements  en vous aidant à créer un élément assez commun que vous verrez  sur de nombreux sites web. Une galerie JavaScript animée.

+ + + + + + + + + + + + +
Conditions préalables:Avant de tenter cette évaluation, vous devriez avoir parcouru tous les articles de ce module. 
Objectif:Tester la compréhension des boucles, des fonctions, des conditions et des événements JavaScript.
+ +

Point de départ

+ +

Pour réaliser cette évaluation, vous devez récupérer le fichier ZIP et le décompresser quelque par sur votre ordinateur.

+ +

Vous pouvez également utiliser un site comme JSBin ou  Thimble pour effectuer votre évalution. Vous pouvez copier le code HTML,CSS et JavaScript dans l'un de ces éditeurs en ligne. Si l'éditeur en ligne que vous utilisez ne dispose pas de panneaux JavaScript/CSS séparés, n'hésitez pas à utiliser les éléments <script>/<style> dans la page HTML.

+ +
+

Note: Si vous êtes bloqué, demandez-nous de l'aide — voir la section {{anch("Évaluation ou aide supplémentaire")}} au bas de cette page.

+
+ +

Résumé du projet

+ +

Vous avez reçu des fichiers HTML, CSS, des images et quelques lignes de code JavaScript; vous devez écrire le code JavaScript nécessaire pour en faire un programme fonctionnel. Le corps HTML ressemble à ceci:

+ +
<h1>Image gallery example</h1>
+
+<div class="full-img">
+  <img class="displayed-img" src="images/pic1.jpg">
+  <div class="overlay"></div>
+  <button class="dark">Darken</button>
+</div>
+
+<div class="thumb-bar">
+
+</div>
+ +

L'exemple ressemble à ceci:

+ +

+ + + +

Les parties les plus intéressantes du fichier CSS de l'exemple:

+ + + +

Votre JavaScript doit:

+ + + +

Pour vous donner une idée, regardez l'exemple (Ne regardez pas le code source!).

+ +

Les différentes étapes

+ +

Les sections suivantes décrivent ce que vous avez à faire.

+ +

Itération sur les images

+ +

Nous vous avons fourni des lignes qui storent une référence à thumb-bar <div> dans une variable nommée thumbBar, créent un nouvel élément <img>, définissent son attribut src à un emplacement de valueur xxx, et ajoutent ce nouvel élément <img> dans thumbBar.

+ +

Vous avez besoin de:

+ +
    +
  1. Ajouter votre code en-dessous du commentaire Looping through images à l'intérieur d'une boucle qui itère sur les 5 images — vous n'avez besoin que de 5 itérations, chacune représentant une image.
  2. +
  3. Remplacez, pour chaque itération,  la valeur xxx de l'emplacement par une chaîne de caractères qui correspond au chemin de l'image considérée. Il faut définir la valeur de l'attribut src dans chaque cas. Gardez à l'esprit que, à chaque fois, l'image est dans le répertoire des images et que son nom est pic1.jpg, pic2.jpg, etc.
  4. +
+ +

Ajout d'un gestionnaire onclick à chaque miniature

+ +

À chaque itération, vous devez ajouter un gestionnaire onclick au newImage courant. Il doit:

+ +
    +
  1. Trouver la valeur de l'attribut src de l'image courante. Cela peut être fait avec la fonction getAttribute() sur <img>, en lui passant le paramètre "src" à chaque fois. Mais comment avoir l'image? Utiliser newImage ne marche pas du fait que la boucle est finie avant que le gestionnaire d'événement ne soit appelé; de cette manière, la valeur de src sera toujours celle du dernier <img>. Pour résoudre cela, gardez à l'esprit que, pour chaque gestionnaire d'événement, c'est <img> qui en est la cible. Pourquoi ne pas récupérer l'information de l'objet événement?
  2. +
  3. Exécuter une fonction, en lui passant en paramètre la fameuse valeur de src. Vous pouvez nommer la fonction à votre guise.
  4. +
  5. Cette fonction du gestionnaire d'événement doit définir la valeur de l'attribut src de displayed-img <img> à la valeur du src passé en paramètre. Nous vous avons fourni une ligne qui stocke une référence de l'<img> concerné dans une variable nommée displayedImg. Notez que nous voulons une fonction nommée.
  6. +
+ +

Écrire le gestionnaire du bouton d'assombrissement

+ +

Il ne reste que notre <button> d'assombrissement — nous vous avons fourni une ligne qui stocke une référence au <button> dans une variable appelée btn. Vous devez ajouter un gestionnaire onclick qui:

+ +
    +
  1. Vérifie la classe appliquée à <button> — à nouveau, vous pouvez utiliser getAttribute().
  2. +
  3. Si le nom de classe est "dark", changer la classe du <button> pour "light" (avec setAttribute()), son contenu textuel par "Lighten", et le {{cssxref("background-color")}} du voile d'assombrissement <div> par "rgba(0,0,0,0.5)".
  4. +
  5. Si le nom de classe n'est pas "dark", changer la classe du <button> pour "dark", son contenu textuel par "Darken", et le {{cssxref("background-color")}} du voile d'assombrissement <div> par "rgba(0,0,0,0)".
  6. +
+ +

Les lignes suivantes fournissent une base pour réaliser les changements  décrits aux points 2 et 3.

+ +
btn.setAttribute('class', xxx);
+btn.textContent = xxx;
+overlay.style.backgroundColor = xxx;
+ +

Conseil

+ + + +

Évaluation ou aide supplémentaire

+ +

Si vous souhaitez que votre travail soit évalué, ou si vous êtes bloqué et que vous voulez demander de l'aide :

+ +
    +
  1. Mettez votre travail dans un éditeur partageable en ligne tel que CodePen, jsFiddle, ou Glitch.
  2. +
  3. Rédiger un sujet pour demander une évaluation et/ou une aide à le forum Discourse du MDN. Ajoutez la balise "learning" à votre message pour que nous puissions le trouver plus facilement. Votre message doit inclure : +
      +
    • Un titre descriptif tel que "Évaluation demandée pour la galerie d'images".
    • +
    • Des détails sur ce que vous souhaitez que nous fassions — par exemple ce que vous avez déjà essayé, si vous êtes bloqué et avez besoin d'aide.
    • +
    • Un lien vers l'exemple que vous souhaitez faire évaluer ou pour lequel vous avez besoin d'aide, dans un éditeur en ligne. C'est une bonne pratique à adopter — il est très difficile d'aider une personne ayant un problème de codage si on ne peut pas voir son code.
    • +
    • Un lien vers la page de la tâche ou de l'évaluation proprement dite, afin que nous puissions trouver la question pour laquelle vous souhaitez de l'aide.
    • +
    +
  4. +
+ +

Si vous suivez cette évaluation dans le cadre d'un cours organisé, vous devriez pouvoir donner votre travail à votre professeur ou mentor pour la notation. Si vous apprenez en autodidacte, vous pouvez obtenir le guide de notation simplement en le demandant sur le fil de discussion de cet exercice, ou sur #mdn du canal IRC de Mozilla IRC. Faites d'abord l'exercice, vous ne gagnerez rien à tricher!

+ +

{{PreviousMenu("Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}

+ +

Dans ce module

+ + diff --git a/files/fr/learn/javascript/building_blocks/index.html b/files/fr/learn/javascript/building_blocks/index.html new file mode 100644 index 0000000000..7efffb563e --- /dev/null +++ b/files/fr/learn/javascript/building_blocks/index.html @@ -0,0 +1,55 @@ +--- +title: Principaux blocs en JS +slug: Apprendre/JavaScript/Building_blocks +tags: + - Auto-évaluation + - Boucles + - Débutant + - Fonctions + - Guide + - Modules + - conditions + - évènements +translation_of: Learn/JavaScript/Building_blocks +--- +
{{JsSidebar}}
+ +
{{PreviousNext("Learn/JavaScript/First_steps", "Learn/JavaScript/Objects")}}
+ +

Dans ce module nous allons continuer à voir l'ensemble des fonctionnalités clefs du JavaScript en nous concentrant plus particulièrement sur les structures les plus répandues telles que les conditions, les boucles, les fonctions et les événements. Nous avons déjà vu ces notions dans le cours mais sans nous y attarder, nous allons maintenant les étudier en détails.

+ +

Prérequis

+ +

Avant de commencer ce module, vous devriez connaître les bases du HTML et du CSS et avoir suivi le module précédent, JavaScript Premiers Pas.

+ +
+

Note : Si vous travaillez depuis un ordinateur, une tablette ou depuis un autre appareil sur lequel vous ne pouvez pas créer vos propres fichiers, ce n'est pas un problème, vous pourrez essayer la plupart des exemples en lignes grâce à des outils comme JSBin ou Thimble .

+
+ +

Guides

+ +
+
Prendre des décisions dans votre code — les conditions
+
Quelque soit le langage de programmation, notre programme doit prendre des décisions et effectuer des actions différentes selon les valeurs traitées. Dans un jeu par exemple, si le nombre de vies du joueur est égal à 0, le jeu s'achève. Sur le même principe, une application météo affiche un fond d'aube si elle est lancée le matin, des étoiles et la Lune si, au contraire, elle est lancée la nuit. Dans cet article, nous allons voir comment les structures conditionnelles fonctionnent en JavaScript.
+
Les boucles
+
Parfois une action doit être réalisée plusieurs fois d'affilée. Par exemple, parcourir une liste de noms. En programmation, les boucles effectuent ce genre de tâches à merveille. Ici, nous allons examiner les structures de boucles en JavaScript.
+
Les fonctions — réutiliser des blocs de code
+
Un autre concept essentiel en programmation est celui de fonctions. Les fonctions permettent de définir un morceau de code réalisant une tâche particulière qui pourra être appelé ultérieurement dans le reste du programme par une simple ligne, ce qui évite d'écrire plusieurs fois le même code. Dans cet article, nous allons voir les concepts qui se cachent derrière les fonctions tels que la syntaxe de base, la définition et l'appel d'une fonction, sa portée et ses paramètres.
+
Créez votre propre fonction
+
L'essentiel sur la théorie des fonctions a été traité dans le chapitre précédent, cet article va vous permettre de mettre en pratique vos connaissances avec un exercice. Nous allons construire notre propre fonction et nous en profiterons pour expliquer quelques notions plus avancées, utiles pour travailler avec les fonctions.
+
Les valeurs de retour des fonctions
+
Il reste un dernier point à vous présenter avant de terminer cette partie sur les fonctions, il s'agit des valeurs retournées. Une fois leur exécution finie, les fonctions renvoient des valeurs, pour certaines d'entre-elles ce retour nous est utile. Il est important de bien comprendre ce que sont ces valeurs, comment les utiliser dans notre programme et comment faire en sorte que nos fonctions renvoient des valeurs qui nous soient utiles.
+
Introduction aux événements
+
Les événements sont des actions ou occurences qui surviennent au cours de l'exécution de votre programme, auxquels vous pouvez répondre de la manière que vous souhaitez. Par exemple, si l'utilisateur clique sur une page web, vous pourriez vouloir répondre à cette action en affichant un élément d'information. Dans ce dernier article, nous allons voir des concepts importants se rapportant aux événements et voir la manière dont ils fonctionnent au sein des navigateurs.
+
+ +

Auto-évaluation

+ +

L'auto-évaluation suivante teste votre compréhension des bases du JavaScript vues dans le guide ci-dessus.

+ +
+
Galerie de photos
+
Maintenant que vous avez fini ce chapitre sur la construction de blocs en JavaScript, vous allez pouvoir tester vos connaissances sur les boucles, les fonctions, les conditions et les événements en codant un élément que l'on retrouve sur de très nombreux sites web, une galerie de photos en JavaScript.
+
+ +

{{PreviousNext("Learn/JavaScript/First_steps", "Learn/JavaScript/Objects")}}  

diff --git a/files/fr/learn/javascript/building_blocks/looping_code/index.html b/files/fr/learn/javascript/building_blocks/looping_code/index.html new file mode 100644 index 0000000000..820a4d09e2 --- /dev/null +++ b/files/fr/learn/javascript/building_blocks/looping_code/index.html @@ -0,0 +1,873 @@ +--- +title: Les boucles dans le code +slug: Apprendre/JavaScript/Building_blocks/Looping_code +tags: + - Article + - CodingScripting + - DO + - Débutant + - Guide + - JavaScript + - Learn + - Loop + - break + - continue + - for + - 'l10n:priority' + - while +translation_of: Learn/JavaScript/Building_blocks/Looping_code +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Building_blocks/conditionals","Learn/JavaScript/Building_blocks/Functions", "Learn/JavaScript/Building_blocks")}}
+ +

Les langages de programmation sont très utiles pour effectuer des tâches répétitives, allant de calculs basiques à à peu près n'importe quelle autre situation où vous avez un certain nombre d'actions similaires à répéter. Ici, nous allons étudier les structures de boucle disponible dans JavaScript qui répondent à un tel besoin.

+ + + + + + + + + + + + +
Prérequis :Culture informatique basique, compréhension basique du HTML et du CSS, Premiers pas en JavaScript...
Objectif :Comprendre comment utiliser les boucles dans JavaScript.
+ +

Laissez-moi dans la boucle

+ +

Boucles, boucles, boucles. Alors qu'elles sont associées aux cheveux d'une célèbre héroïne de fiction, elles sont également un concept extrêmement important en programmation. Les boucles de programmation ne font que faire la même action encore et toujours – ce qui se traduit par itérer en langage de programmeur.

+ +

Commençons par examiner le cas d'un fermier qui doit s'assurer d'avoir assez de nourriture pour nourrir sa famille pour la semaine. Il pourrait ainsi utiliser la boucle suivante :

+ +


+

+ +

Une boucle a normalement un ou plusieurs des composants suivants :

+ + + +

En {{glossary("pseudocode")}}, cela ressemblerait à ce qui suit :

+ +
loop(nourriture = 0; besoinNourriture = 10) {
+  if (nourriture = besoinNourriture) {
+    exit loop;
+    // Nous avons assez de nourriture, on rentre
+  } else {
+    nourriture += 2; // On doit rester 1 heure de plus
+    // La boucle se répète ensuite
+  }
+}
+ +

La quantité de nourriture dont le fermier a besoin est donc initialisée à 10, et la quantité dont il dispose est initialisée à 0. A chaque itération de la boucle, on vérifie si la quantité de nourriture dont le fermier dispose est égale à la quantité requise. Si c'est le cas, on peut sortir de la boucle. Sinon, le fermier passe une heure de plus à récolter de la nourriture, et la boucle itère à nouveau.

+ +

À quoi ça sert ?

+ +

Arrivé à ce stade, vous avez sans doute compris le concept global des boucles, mais vous vous dites probablement : "Ok, bien, mais comment cela va-t-il m'aider à améliorer mes codes en JavaScript ?". Comme nous l'avons dit plus tôt, les boucles ne font rien d'autre que répéter la même action encore et encore, ce qui peut s'avérer utile pour effectuer rapidement des tâches répétitives.

+ +

Souvent, le code sera légèrement différent à chaque itération successive, ce qui signifie que vous pouvez effectuer une certaine quantité de tâches similaires, mais néanmoins quelque peu différentes - si vous avez beaucoup de calculs différents à effectuer, vous n'allez pas effectuer le même calcul encore et encore !

+ +

Regardons maintenant un exemple qui illustre parfaitement en quoi les boucles sont si intéressantes. Disons que nous voulons dessiner 100 cercles aléatoirement sur un <canvas> (appuyez sur le bouton Update pour lancer le programme à nouveau et voir différentes dispositions aléatoires).

+ + + +

{{ EmbedLiveSample('Hidden_code', '100%', 400) }}

+ +

Vous n'avez pas besoin de comprendre entièrement le code pour l'instant, mais regardons plus en détail la partie du code qui trace les 100 cercles :

+ +
for (let i = 0; i < 100; i++) {
+  ctx.beginPath();
+  ctx.fillStyle = 'rgba(255,0,0,0.5)';
+  ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
+  ctx.fill();
+}
+ +

Vous devriez comprendre l'idée basique - nous utilisons une boucle pour effectuer 100 itérations de ce code, chacune dessinant un cercle à une position quelconque sur la page. La quantité de lignes de code nécessaire serait identique si l'on voulait tracer 100 cercles, 1000 ou même 100000. Seul le nombre d'itérations devrait changer.

+ +

Si nous n'utilisions pas de boucle ici, nous aurions du répéter le code suivant pour chaque cercle que nous aurions voulu dessiner :

+ +
ctx.beginPath();
+ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
+ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
+ctx.fill();
+ +

Mais cela prend du temps inutilement, et rend le code difficilement maintenable. Les boucles sont vraiment les meilleures.

+ +

La boucle standard

+ +

Commençons maintenant à voir quelques formes de boucles spécifiques. La première, celle que vous utiliserez le plus souvent, est la boucle for. Elle a la syntaxe suivante :

+ +
for (initialisation; condition de sortie; expression finale) {
+  // code à exécuter
+}
+ +

Nous avons ici :

+ +
    +
  1. Le mot-clé for, suivi par des parenthèses.
  2. +
  3. A l'intérieur des parenthèses, on a trois objets : +
      +
    1. Une initialisation — il s'agit souvent d'une variable initialisée à une certaine valeur, qui est incrémentée afin de compter le nombre de fois où la boucle s'est exécutée. On peut également la nommer compteur.
    2. +
    3. Une condition de sortie — comme mentionné précédemment, cela définit le moment où la boucle doit arrêter de s'exécuter. C'est généralement une expression contenant un opérateur de comparaison, un test pour voir si la condition de sortie est atteinte.
    4. +
    5. Une expression finale — Elle est toujours évaluée (ou exécutée) chaque fois que la boucle a effectué une itération complète. Cela sert souvent à incrémenter (ou dans certains cas décrémenter) le compteur, pour le rapprocher de la valeur de la condition de sortie.
    6. +
    +
  4. +
  5. Des accolades contenant un bloc de code — ce code sera exécuté chaque fois que la boucle itère.
  6. +
+ +

Regardons maintenant un vrai exemple, afin de visualiser leurs actions plus clairement.

+ +
const chats = ['Bill', 'Jeff', 'Pete', 'Biggles', 'Jasmin'];
+let info = "Mes chat s'appellent ";
+const paragraphe = document.querySelector('p');
+
+for (let i = 0; i < chats.length; i++) {
+  info += chats[i] + ', ';
+}
+
+paragraphe.textContent = info;
+ +

Cela nous donne la sortie suivante :

+ + + +

{{ EmbedLiveSample('Hidden_code_2', '100%', 60) }}

+ +
+

Note: Vous pouvez trouver aussi cet exemple de code sur GitHub (et le voir tourner en live).

+
+ +

Cela montre une boucle utiliser pour itérer sur les éléments d'un tableau et faire quelque chose avec chacun d'eux — un schéma très commun en JavaScript. Ici :

+ +
    +
  1. L'itérateur, i, commence à 0 (let i = 0).
  2. +
  3. On lui a demandé de s'exécuter jusqu'à ce que sa valeur ne soit plus inférieure à la longueur du tableau chats. C'est important  — la condition de sortie montre la condition à laquelle la boucle continue de s'exécuter. C'est à dire dans ce cas, tant que i < chats.length est vrai, la boucle continuera à s'exécuter.
  4. +
  5. Au sein de la boucle, on concatène les élèments présents dans cette boucle (cats[i] est cats[quelque soit la valeur de i lors de l'iteration]) avec une virgule et un espace, à la fin de la variable info. Donc : +
      +
    1. Pendant le premier lancement, i = 0, donc cats[0] + ', ' sera concaténé à ("Bill, ")
    2. +
    3. Au second lancement, i = 1, donc cats[1] + ', ' et sera concaténé à  ("Jeff, ")
    4. +
    5. Et ainsi de suite. Aprés chaque tour de boucle, 1 est ajouté à i (i++), et alors le processus recommence encore.
    6. +
    +
  6. +
  7. Quand i devient égal à cats.length, la boucle s'arrête, et le navigateur va bouger au prochain bout de code aprés la boucle.
  8. +
+ +
+

Note: Nous avons fait sortir la condition i < cats.length, et pas i <= cats.length, parce que les ordinateurs comptent à partir de 0, pas 1 — nous avons démarré i à 0, et allons allers jusqu'à i = 4 (l'index du dernier item de la table/tableau). cats.length retourne 5, comme il y a 5 items dans la table, nous n'allont pas aller à i = 5, cela retournerai undefined pour le dernier item (il n'y a pas de item de table avec un index de 5). Par conséquent, nous voulons aller de 1 à moins que cats.length (i <), ce n'est pas la même chose que cats.length (i <=).

+
+ +
+

Note: Une erreur commune avec les conditions de sortie est de les faire utiliser "égal à" plutôt que de dire "inférieur ou égal à". Si nous voulions faire tourner notre boucle jusqu'à i = 5, la condition de sortie aurait besoin d'être i <= cats.length / Si nous la mettons à i = cats.length, la boucle ne fonctionnerait pas du tout parce que i n'est pas égal à 5 sur la première itération de la boucle, de sorte que cela s'arrête immédiatement.

+
+ +

Un petit problème est que nous avons laissé la phrase de sortie mal formée :

+ +
+

Mes chats s'appellent Bill, Jeff, Pete, Biggles, Jasmin,

+
+ +

Idéalement, nous voulons changer la concaténation sur l'itération de la boucle finale de sorte que nous n'ayons pas de virgule à la fin de la phrase. Bien, pas de problème – nous pouvons heureusement insérer une structure conditionnelle dans notre boucle for pour gérer ce cas particulier :

+ +
for (let i = 0; i < cats.length; i++) {
+  if (i === cats.length - 1) {
+    info += 'and ' + cats[i] + '.';
+  } else {
+    info += cats[i] + ', ';
+  }
+}
+ +
+

Note: Vous pouvez trouver cet exemple de code sur GitHub (et aussi le voir en ligne).

+
+ +
+

Important: Avec for — comme avec toutes les boucles  — vous devez vous assurer que l'initialiseur est itéré de sorte qu'il finisse par atteindre la condition de sortie. Si ce n'est pas le cas, la boucle continuera indéfiniment, et soit le navigateur l'arrêtera, soit il se bloquera. C'est ce qu'on appelle une boucle infinie.

+
+ +

Quitter une boucle avec break

+ +

Si vous voulez quitter une boucle avant que toutes les itérations aient été terminées, vous pouvez utiliser l'instruction break. Nous l'avons déjà rencontré dans l'article précédent lorsque nous examinions les instructions switch : lorsqu'un argument est rencontré dans une instruction switch qui correspond à l'expression d'entrée, l'instruction break quitte immédiatement l'instruction switch et passe au code après elle.

+ +

C'est la même chose avec les boucles – un break quittera immédiatement la boucle et fera passer le navigateur sur n'importe quel code qui le suit.

+ +

Supposons que nous voulions effectuer une recherche parmi une liste de contacts et de numéros de téléphone et que nous ne renvoyions que le nombre que nous voulions trouver. Tout d'abord, du HTML simple - un texte {{htmlelement ("input")}} nous permettant d'entrer un nom à rechercher, un élément {{htmlelement ("button")}} pour soumettre une recherche, et un {{htmlelement ("p")}} élément pour afficher les résultats dans :

+ +
<label for="search">Search by contact name: </label>
+<input id="search" type="text">
+<button>Search</button>
+
+<p></p>
+ +

Maintenant sur le JavaScript :

+ +
const contacts = ['Chris:2232322', 'Sarah:3453456', 'Bill:7654322', 'Mary:9998769', 'Dianne:9384975'];
+const paragraphe = document.querySelector('p');
+const input = document.querySelector('input');
+const bouton = document.querySelector('button');
+
+bouton.addEventListener('click', function() {
+  let searchName = input.value;
+  input.value = '';
+  input.focus();
+  for (let i = 0; i < contacts.length; i++) {
+    let splitContact = contacts[i].split(':');
+    if (splitContact[0] === searchName) {
+      paragraphe.textContent = splitContact[0] + '\'s number is ' + splitContact[1] + '.';
+      break;
+    } else {
+      paragraphe.textContent = 'Contact not found.';
+    }
+  }
+});
+ + + +

{{ EmbedLiveSample('Hidden_code_3', '100%', 100) }}

+ +
    +
  1. Tout d'abord, nous avons quelques définitions de variables — nous avons un tableau d'informations de contact, avec chaque élément étant une chaîne contenant un nom et un numéro de téléphone séparés par deux points.
  2. +
  3. Ensuite, nous attachons un écouteur d'événement au bouton (bouton), de sorte que quand il est pressé, du code est exécuté pour effectuer la recherche et renvoyer les résultats.
  4. +
  5. Nous stockons la valeur saisie dans l'input dans une variable appelée searchName, , avant de vider l'input et le recentrer, prêt pour la recherche suivante.
  6. +
  7. Maintenant sur la partie intéressante, la boucle for : +
      +
    1. Nous commençons le compteur à 0, exécutons la boucle jusqu'à ce que le compteur ne soit plus inférieur à contacts.length, et incrémentons i par 1 après chaque itération de la boucle.
    2. +
    3. À l'intérieur de la boucle, nous divisons d'abord le contact actuel (contacts[i]) au caractère deux-points et stockons les deux valeurs résultantes dans un tableau appelé splitContact.
    4. +
    5. Nous utilisons ensuite une instruction conditionnelle pour tester si splitContact[0] (le nom du contact) est égal au searchName entré. Si c'est le cas, nous introduisons une string / chaîne de caractère dans le paragraphe pour indiquer quel est le numéro du contact et utiliser break pour terminer la boucle.
    6. +
    +
  8. +
  9. Si le nom du contact ne correspond pas à la recherche entrée, le texte du paragraphe est défini sur "Contact not found." et la boucle continue son itération.
  10. +
+ +
+

Note : Vous pouvez trouver cet exemple de code sur GitHub (aussi voir en ligne).

+
+ +

Passer des itérations avec continue

+ +

L'instruction continue fonctionne d'une manière similaire à break, mais au lieu de sortir complètement de la boucle, elle passe à l'itération suivante de la boucle. Regardons un autre exemple qui prend un nombre comme une entrée, et retourne seulement les nombres qui sont des carrés d'entiers (nombres entiers).

+ +

Le HTML est fondamentalement le même que le dernier exemple — une entrée de texte simple, et un paragraphe pour la sortie. Le JavaScript est la plupart du temps identique, même si la boucle elle-même est un peu différente :

+ +
let num = input.value;
+
+for (let i = 1; i <= num; i++) {
+  let sqRoot = Math.sqrt(i);
+  if (Math.floor(sqRoot) !== sqRoot) {
+    continue;
+  }
+
+  paragraphe.textContent += i + ' ';
+}
+ +

Ici la sortie :

+ + + +

{{ EmbedLiveSample('Hidden_code_4', '100%', 100) }}

+ +
    +
  1. Dans ce cas, l'entrée doit être un nombre (num). La boucle for est dotée d'un compteur commençant à 1 (car nous ne sommes pas intéressés par 0 dans ce cas), une condition de sortie indiquant que la boucle s'arrêtera lorsque le compteur deviendra plus grand que l'entrée num, et un itérateur ajoutera 1 au compteur à chaque fois.
  2. +
  3. À l'intérieur de la boucle, nous trouvons la racine carrée de chaque nombre en utilisant Math.sqrt(i), , puis vérifions si la racine carrée est un entier en vérifiant si elle est identique à elle-même lorsqu'elle a été arrondie à l'entier le plus proche (ceci est ce que Math.floor() fait au nombre auquel il est passé).
  4. +
  5. Si la racine carrée et la racine carrée arrondie ne sont pas égales les unes aux autres (! ==), cela signifie que la racine carrée n'est pas un entier, donc cela ne nous intéresse pas. Dans un tel cas, nous utilisons l'instruction continue pour passer à l'itération de la boucle suivante sans enregistrer le numéro n'importe où.
  6. +
  7. Si la racine carrée est un entier, nous passons complètement le bloc if pour que l'instruction continue ne soit pas exécutée; à la place, nous concaténons la valeur i actuelle plus un espace sur la fin du contenu du paragraphe.
  8. +
+ +
+

Note: Vous pouvez trouver cet exemple de code sur GitHub (aussi voir en ligne).

+
+ +

while et do ... while

+ +

for n'est pas le seul type de boucle disponible en JavaScript. Il y en a beaucoup d'autres et, même si vous n'avez pas besoin de comprendre tout cela maintenant, il vaut mieux jeter un coup d'œil à la structure de quelques autres pour pouvoir reconnaître les mêmes caractéristiques au travail d'une manière légèrement différente.

+ +

D'abord, regardons la boucle while. La syntaxe de cette boucle ressemble à ceci:

+ +
initializer
+while (exit-condition) {
+  // code to run
+
+  final-expression
+}
+ +

Cela fonctionne de manière très similaire à la boucle for, sauf que la variable de départ est définie avant la boucle, et l'expression finale est incluse dans la boucle après le code à exécuter — plutôt que ces deux éléments soient inclus dans les parenthèses. La condition de sortie est incluse dans les parenthèses, précédées du mot-clé while au lieu de for.

+ +

Les mêmes trois éléments sont toujours présents, et ils sont toujours définis dans le même ordre que dans la boucle for - cela est logique, car vous devez toujours définir un initialiseur avant de pouvoir vérifier s'il a atteint la condition de sortie ; la condition finale est ensuite exécutée après l'exécution du code à l'intérieur de la boucle (une itération a été effectuée), ce qui ne se produira que si la condition de sortie n'a pas encore été atteinte.

+ +

Jetons un coup d'oeil à notre exemple de liste de chats, mais réécrit pour utiliser une boucle while:

+ +
let i = 0;
+
+while (i < cats.length) {
+  if (i === cats.length - 1) {
+    info += 'and ' + cats[i] + '.';
+  } else {
+    info += cats[i] + ', ';
+  }
+
+  i++;
+}
+ +
+

Note: Cela fonctionne toujours comme prévu regardez le ici GitHub (Voir en ligne le code complet).

+
+ +

La boucle do...while est très similaire, mais dénote une variation par rapport à la structure de la boucle while :

+ +
initializer
+do {
+  // code to run
+
+  final-expression
+} while (exit-condition)
+ +

Dans ce cas, l'initialiseur vient en premier, avant que la boucle ne commence. Le mot-clé do précède directement les accolades contenant le code à exécuter et l'expression finale.

+ +

Le différentiateur ici est que la condition de sortie vient après tout, enveloppée entre parenthèses et précédée d'un mot-clé while. Dans une boucle do ... while, le code à l'intérieur des accolades est toujours exécuté une fois avant que la vérification ne soit effectuée pour voir si elle doit être exécutée à nouveau (dans while et for, la vérification arrive en premier, donc le code pourrait ne jamais être exécuté ).

+ +

Réécrivons notre exemple de listing de chat pour utiliser une boucle do ... while :

+ +
let i = 0;
+
+do {
+  if (i === cats.length - 1) {
+    info += 'and ' + cats[i] + '.';
+  } else {
+    info += cats[i] + ', ';
+  }
+
+  i++;
+} while (i < cats.length);
+ +
+

Note: Encore, cela fonctionne toujours comme prévu — regardez le ici GitHub (Voir en ligne le code complet).

+
+ +
+

Important: Avec while et do ... while – comme avec toutes les boucles – vous devez vous assurer que l'initialiseur est itéré pour qu'il atteigne finalement la condition de sortie. Si ce n'est pas le cas, la boucle continuera indéfiniment, et soit le navigateur l'arrêtera, soit il se bloquera. C'est ce qu'on appelle une boucle infinie.

+
+ +

Apprentissage actif : Lancer le compte à rebours !

+ +

Dans cet exercice, nous vous proposons d'écrire un compte à rebours de lancement dans la boîte de sortie, de 10 jusqu'à "Blast Off." Plus précisément, il s'agit de :

+ + + +

Si vous faites une erreur, vous pourrez toujours réinitialiser l'exemple avec le bouton "Reset". Si vous êtes vraiment bloqué, appuyez sur le bouton "Show solution" pour voir une solution.

+ + + +

{{ EmbedLiveSample('Active_learning', '100%', 780) }}

+ +

Apprentissage actif : remplir une liste d'invités.

+ +

Dans cet exercice, nous vous proposons de prendre une liste d'invités stockée dans un tableau et de la mettre sur une liste d'invités. Mais cela n'est pas si simple — nous ne voulons pas laisser entrer Phil et Lola parce que ce sont des goinfres et qu'ils sont mal élevés, et ils mangent toujours toute la nourriture ! Nous avons deux listes, une pour les invités admis, une pour ceux que l'on refuse.

+ +

Plus précisément, nous attendons de vous :

+ + + +

Nous vous avons déjà fourni les éléments suivants :

+ + + +

Question bonus — après avoir accompli les tâches ci-dessus, il vous restera deux listes de noms séparées par des virgules, mais elles seront mal présentées— il y aura des virgules à la fin de chacune d'elles. Pouvez-vous faire en sorte d'écrire des lignes de code qui coupent les dernières virgules dans chacune d'elles, et ajoute un arrêt total à la fin ? Jetez un oeil à l'article Méthodes utiles pour les chaînes de caractères pour obtenir de l'aide.

+ +

Si vous faites une erreur, vous pourrez toujours ré-initialiser l'exemple avec le bouton "Reset". Si vous êtes vraiment bloqué, appuyez sur le bouton "Show solution" pour voir une solution.

+ + + +

{{ EmbedLiveSample('Active_learning_2', '100%', 580) }}

+ +

Quel type de boucle utiliser ?

+ +

Pour des usages basiques les boucles for, while, et do...while sont largement interchangeables. Elles résolvent toutes le même problème et celle que vous utiliserez dépendra de vos préférences personnelles — celle que vous trouverez le plus facile à mémoriser ou la plus intuitive. Jetons-y un coup d'oeil à nouveau.

+ +

Premièrement for:

+ +
for (initialisation; condition de sortie; expression finale) {
+  // code à exécuter
+}
+ +

while:

+ +
initialisation
+while (condition de sortie) {
+  // code à exécuter
+
+  expression finale
+}
+ +

et enfin do...while:

+ +
initialisation
+do {
+  // code à exécuter
+
+  expression finale
+} while (condition de sortie)
+ +

Nous recommandons for, au moins pour commencer, car elle est probablement la plus facile pour tout se remémorer — l'initialisation, la condition de sortie, l'expression finale, le tout soigneusement placé entre des parenthèses. De cette façon, il est facile de voir où elles se trouvent et de vérifier qu'on ne les a pas oubliées.

+ +
+

Note: Il y a d'autres types de boucles et de particularités, qui sont très utiles pour des situations spéciales et qui ne sont pas décrites dans cet article. Si vous voulez aller plus loin dans l'apprentissage des boucles, lisez le guide Boucles et itérations.

+
+ +

Conclusion

+ +

Cet article vous a révélé les concepts basiques et les différentes options disponibles pour créer des boucles en JavaScript. Vous devriez à présent être en mesure de comprendre en quoi les boucles constituent un bon mécanisme lorsqu'il s'agit de répéter une action dans le code, et vous devez être impatient de les utiliser dans vos propres exemples !

+ +

S'il y a quelque chose que vous n'avez pas compris, n'hésitez pas à relire l'article ou à nous contacter pour demander de l'aide.

+ +

Voir aussi

+ + + +

{{PreviousMenuNext("Learn/JavaScript/Building_blocks/conditionals","Learn/JavaScript/Building_blocks/Functions", "Learn/JavaScript/Building_blocks")}}

diff --git a/files/fr/learn/javascript/building_blocks/return_values/index.html b/files/fr/learn/javascript/building_blocks/return_values/index.html new file mode 100644 index 0000000000..72ed199a4c --- /dev/null +++ b/files/fr/learn/javascript/building_blocks/return_values/index.html @@ -0,0 +1,182 @@ +--- +title: Valeurs de retour des fonctions +slug: Apprendre/JavaScript/Building_blocks/Return_values +tags: + - Apprendre + - Article + - Débutant + - Fonctions + - Guide + - JavaScript + - Return + - Valeurs de retour + - Écriture de code +translation_of: Learn/JavaScript/Building_blocks/Return_values +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Build_your_own_function","Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}
+ +

Il y a un concept essentiel que nous devons aborder dans ce cours, pour être complet sur les fonctions: les valeurs de retour. Certaines fonctions ne retournent pas de valeur significative après avoir été exécutées, mais d'autres oui, il est important de comprendre ces valeurs, comment les utiliser dans votre code et comment faire pour que vos propres fonctions retournent des valeurs utiles. Nous aborderons tout cela dans cet article.

+ + + + + + + + + + + + +
Prérequis: +

Base en langage informatique, une compréhension basic de HTML et CSS, Premiers pas en JavaScript, Fonctions — blocks de code réutilisable.

+
Objectif:Comprendre les valeurs de retour, et comment les utiliser.
+ +

Qu'est-ce que les valeurs de retour?

+ +

Les valeurs de retour sont, comme leur nom l'indique, les valeurs retournées par une fonction après son exécution. Vous en avez déjà rencontré plusieurs fois sans y avoir pensé explicitement. Revenons à notre code:

+ +
var myText = 'I am a string';
+var newString = myText.replace('string', 'sausage');
+console.log(newString);
+// the replace() string function takes a string,
+// replaces one substring with another, and returns
+// a new string with the replacement made
+ +

Nous avons vu ce bloc de code dans notre premier article sur les fonctions. Nous appelons la fonction replace() sur la chaîne de caractères myText , et lui passons deux paramètres: la chaîne à trouver ('string'), et la chaîne de remplacement ('sausage'). Lorsque cette fonction a fini de s'exécuter, elle retourne une valeur qui est une chaîne avec le remplacement effectué. Dans le code ci-dessus, nous sauvegardons cette valeur avec la variable newString.

+ +

Si vous regardez la page de référence MDN sur le remplacement de fonction, vous verrez une section intitulée Valeur retournée. Il est utile de savoir et de comprendre quelles sont les valeurs retournées par les fonctions, nous avons donc essayé d'inclure cette information partout où cela était possible.

+ +

Certaines fonctions ne retournent pas de valeur comme telle (dans nos pages de référence, la valeur de retour est définie comme void ou undefined dans de tels cas). Par exemple, dans la fonction displayMessage()  construite dans l'article précédent, aucune valeur spécifique n'est retournée comme résultat de la fonction appelée. Il y a seulement une boîte qui apparaît, c'est tout !

+ +

Généralement, une valeur de retour est utilisée lorsque la fonction est une étape intermédiaire dans un programme. Ces valeurs intermédiaires doivent être d'abord évaluées par une fonction, le résultat renvoyé pourra être ensuite utilisé dans l'étape suivante du programme.

+ +

Utiliser des valeurs de retour dans vos fonctions

+ +

Pour retourner une valeur d'une fonction que vous avez créée, vous devez utiliser... suspense... le mot-clef return . Nous avons vu son utilisation dans l'exemple random-canvas-circles.html. Notre fonction draw() dessine 100 cercles aléatoires en HTML. {{htmlelement("canvas")}}:

+ +
function draw() {
+  ctx.clearRect(0,0,WIDTH,HEIGHT);
+  for (var i = 0; i < 100; i++) {
+    ctx.beginPath();
+    ctx.fillStyle = 'rgba(255,0,0,0.5)';
+    ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
+    ctx.fill();
+  }
+}
+ +

À chaque itération de la boucle, on fait trois fois appel à la fonction random() pour générer respectivement une valeur aléatoire pour les coordonnées x et y du cercle, ainsi que pour son rayon. La fonction random() prend un seul paramètre — un nombre entier — et elle retourne un nombre entier aléatoire compris entre 0 et ce nombre. Voici à quoi cela ressemble:

+ +
function random(number) {
+  return Math.floor(Math.random()*number);
+}
+ +

Cela peut aussi s'écrire ainsi:

+ +
function random(number) {
+  var result = Math.floor(Math.random()*number);
+  return result;
+}
+ +

Mais la première version est plus rapide à écrire, et plus compacte.

+ +

La fonction retourne le résultat de Math.floor(Math.random()*number) chaque fois qu'elle est appelée. Cette valeur de retour apparaît à l'endroit où la fonction a été appelée, puis le code continue. Si, par exemple, nous exécutons la ligne suivante:

+ +
ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
+ +

et que les trois appels random() retournent respectivement les valeurs 500, 200 et 35, la ligne pourrait être écrite de cette façon:

+ +
ctx.arc(500, 200, 35, 0, 2 * Math.PI);
+ +

Les fonctions de la ligne sont évaluées en premières, et leurs valeurs de retour viennent remplacer les appels de fonctions avant que la ligne elle-même ne soit exécutée.

+ +

Apprentissage actif: notre propre fonction avec valeur de retour

+ +

Allons-y, écrivons nos propres fonctions avec des valeurs de retour.

+ +
    +
  1. Pour commencer, faites une copie locale du fichier function-library.html à partir de GitHub. Il s'agit d'une simple page HTML contenant un champ texte  {{htmlelement("input")}} et un paragraphe. Il y a également un élément {{htmlelement("script")}} qui référence ces éléments HTML dans deux variables. Cette page vous permettra d'entrer un nombre dans le champ texte, et affichera, dans le paragraphe au-dessous, différents nombres en lien avec celui entré.
  2. +
  3. Ajoutons quelques fonctions dans <script> . Sous les deux lignes existantes de JavaScript, ajoutez les définitions des fonctions suivantes: +
    function squared(num) {
    +  return num * num;
    +}
    +
    +function cubed(num) {
    +  return num * num * num;
    +}
    +
    +function factorial(num) {
    +  var x = num;
    +  while (x > 1) {
    +    num *= x-1;
    +    x--;
    +  }
    +  return num;
    +}
    + Les fonctions squared() et cubed() sont plutôt évidentes, elle retournent le carré et le cube du nombre donné en paramètre. La fonction factorial() retourne la factorielle du nombre donné.
  4. +
  5. Ensuite, nous allons ajouter un moyen d'afficher des informations sur le nombre entré dans le champ texte. Ajoutez le gestionnaire d'événement suivant à la suite des fonctions: +
    input.onchange = function() {
    +  var num = input.value;
    +  if (isNaN(num)) {
    +    para.textContent = 'You need to enter a number!';
    +  } else {
    +    para.textContent = num + ' squared is ' + squared(num) + '. ' +
    +                       num + ' cubed is ' + cubed(num) + '. ' +
    +                       num + ' factorial is ' + factorial(num) + '.';
    +  }
    +}
    + +

    Ici nous créons un gestionnaire d'événement onchange qui s'exécute chaque fois que l'événement change se déclenche sur le champ de saisie de texte, c'est-à-dire lorsqu'une nouvelle valeur est entrée dans le champ de saisie de texte, puis qu'elle est soumise (par exemple lorsqu'on entre une valeur puis qu'on appuie sur Tab). Quand cette fonction anonyme s'exécute, la valeur entrée dans le champ de saisie est stockée dans la variable num.

    + +

    Ensuite, nous faisons un test: Si la valeur entrée n'est pas un nombre, un message d'erreur s'affiche dans le paragraphe. Le test vérifie si l'expression isNaN(num) retourne true. Nous utilisons la fonction isNaN() pour vérifier si la valeur num est un nombre — si c'est le cas, elle retourne false, sinon true.

    + +

    Si le test retourne false, la valeur num est un nombre, alors une phrase s'affiche dans le paragraphe indiquant le carré, le cube et la factorielle du nombre. La phrase appelle les fonctions squared(), cubed() et factorial() pour obtenir les valeurs désirées.

    +
  6. +
  7. Sauvegardez votre code, chargez-le dans votre navigateur et testez-le.
  8. +
+ +
+

Note: Si vous rencontrez des difficultés pour faire fonctionner cet exemple, vous pouvez vérifier le code en le comparant à la Version final sur GitHub (également Démonstration en direct), ou demandez-nous de l'aide.

+
+ +

À ce stade, nous aimerions que vous essayiez d'écrire quelque fonctions de votre choix et que vous les ajoutiez à la bibliothèque. Que diriez-vous des racines carré et cubique du nombre, ou de la circonférence d'un cercle de rayon num?

+ +

Cet exercice a soulevé quelques points importants en plus de nous avoir permis d'étudier l'utilisation de la déclaration return. De plus, nous avons:

+ + + +

Conclusion

+ +

Nous l'avons vu, les fonctions sont amusantes, très utiles et, bien qu'il y ait beaucoup à dire en termes de syntaxe et de fonctionnalités, elles sont assez compréhensibles si elles sont étudiés correctement.

+ +

Si vous n'avez pas compris quelque chose, n'hésitez pas à relire l'article, ou contactez-nous pour obtenir de l'aide.

+ +

Voir aussi

+ + + +

{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Build_your_own_function","Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}

+ +

 

+ +

Dans ce module

+ + + +

 

diff --git a/files/fr/learn/javascript/client-side_web_apis/client-side_storage/index.html b/files/fr/learn/javascript/client-side_web_apis/client-side_storage/index.html new file mode 100644 index 0000000000..e5226ffa24 --- /dev/null +++ b/files/fr/learn/javascript/client-side_web_apis/client-side_storage/index.html @@ -0,0 +1,881 @@ +--- +title: Stockage côté client +slug: Apprendre/JavaScript/Client-side_web_APIs/Client-side_storage +tags: + - API + - Apprendre + - Codage + - Débutant + - Guide + - IndexedDB + - JavaScript + - Storage +translation_of: Learn/JavaScript/Client-side_web_APIs/Client-side_storage +--- +

{{LearnSidebar}}

+ +
{{PreviousMenu("Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs", "Learn/JavaScript/Client-side_web_APIs")}}
+ +
+ +

Les navigateurs web modernes permettent aux sites web de stocker des données sur l'ordinateur de l'utilisateur — avec sa permission — puis de les récupérer au besoin. Cela permet d'enregistrer des données pour du stockage à long terme, de sauvegarder des documents ou des sites hors-ligne, de conserver des préférences spécifiques à l'utilisateur et plus encore. Cet article explique les fondamentaux pour y parvenir.

+ + + + + + + + + + + + +
Prérequis:Notions de bases de JavaScript (voir premiers pas, les briques JavaScript, les objets JavaScript), les notions de base des APIs côté client
Objectif:Apprendre à utiliser les APIs de stockage côté client pour stocker des données de l'application.
+ +

Stockage côté client ?

+ +

Ailleurs dans la zone d'apprentissage de MDN, nous avons parlé de la différence entre les sites statiques et les sites dynamiques — ces derniers stockent des données côté serveur en utilisant une base de données. Ensuite, ils exécutent du code pour récupérer les données et les insérer dans des templates de page statique. Finalement, le HTML résultant est envoyé au client, qui est alors affiché par le navigateur de l'utilisateur.

+ +

Le stockage côté client fonctionne sur des principes similaires, mais pour une utilisation différente. Le stockage côté client repose sur des APIs JavaScript qui permettent de stocker des données sur la machine de l'utilisateur et de les récupérer au besoin. Cela peut se révéler utile dans différents cas comme :

+ + + +

Souvent, le stockage côté client et côté serveur sont utilisés ensemble. Par exemple, vous pouvez télécharger à partir d'une base de données côté serveur une série de fichiers mp3 utilisés par un site web (comme un jeu ou une application de musique) vers une base de données côté client et ainsi pouvoir les lire quand vous le voulez. Avec cette stratégie, l'utilisateur n'a à télécharger le fichier qu'une seule fois — les visites suivantes, ils sont récupérés à partir de la base de données locale.

+ +
+

Note : La quantité de données que l'on peut stocker à l'aide des APIs de stockage côté client est limitée (limite par API et limite globale), la limite exacte dépend du navigateur et des configurations. Voir Limites de stockage du navigateur et critères d'éviction pour plus d'informations.

+
+ +

À l'ancienne : les cookies

+ +

Le concept de stockage côté client existe depuis longtemps. Au début du web, les sites utilisaient des cookies pour stocker des informations et personnaliser l'expérience utilisateur. C'est la méthode de stockage côté client la plus couramment utilisée et la plus ancienne.

+ +

De par leur histoire, les cookies souffrent d'un certain nombre de problèmes — tant techniques qu'au niveau de l'expérience utilisateur. Ces problèmes sont suffisamment importants pour imposer un message d'information aux utilisateurs habitant en Europe lors de leur première visite si le site utilise des cookies pour stocker des informations sur eux. Cela est dû à une loi de l'Union Européenne connue sous le nom de directive Cookie.

+ +

+ +

Pour ces raisons, nous ne verrons pas dans cet article comment utiliser les cookies. Entre le fait qu'ils sont dépassés, les problèmes de sécurité qu'ils présentent et l'incapacité de stocker des données complexes, les cookies ne sont pas la meilleure manière pour stocker des données. Il y a de meilleures alternatives, modernes, permettant de stocker des données variées sur l'ordinateur de l'utilisateur.

+ +

Le seul avantage des cookies est qu'ils sont supportés par des navigateurs anciens : si votre projet requiert le support de navigateurs obsolètes (comme Internet Explorer 8 et inférieur), les cookies peuvent se révéler utiles. Pour la plupart des projets, vous ne devriez pas avoir besoin d'y recourir.

+ +
+

Note : Pourquoi existe-t-il encore de nouveaux sites crées à l'aide de cookies? Principalement de par les habitudes des développeurs, l'utilisation de bibliothèques anciennes qui utilisent encore des cookies et l'existence de nombreux sites web fournissant des formations et références dépassées pour apprendre à stocker des données.

+
+ +

La nouvelle école : Web Storage et IndexedDB

+ +

Les navigateurs modernes ont des APIs beaucoup plus efficaces et faciles d'utilisation pour stocker des données côté client.

+ + + +

Vous en apprendrez plus sur ces APIs ci-dessous.

+ +

Le futur : l'API Cache

+ +

Certains navigateurs modernes prennent en charge la nouvelle API {{domxref("Cache")}}. Cette API a été conçue pour stocker les réponses HTTP de requêtes données et est très utile pour stocker des ressources du site afin qu'il soit accessible sans connexion réseau par exemple. Le cache est généralement utilisé avec l'API Service Worker, mais ce n'est pas obligatoire.

+ +

L'utilisation du Cache et des Service Workers est un sujet avancé, nous ne le traiterons pas en détail dans cet article, nous ne montrerons qu'un simple exemple dans la section {{anch("Stockage hors-ligne de ressources")}} plus bas.

+ +

Stocker des données simples — web storage

+ +

L'API Web Storage est très facile à utiliser — on stocke une simple paire clé/valeur de données (limité aux données scalaires) et on les récupére au besoin.

+ +

Syntaxe basique

+ +

Nous allons vous guider pas à pas :

+ +
    +
  1. +

    Tout d'abord, ouvez notre template vide de web storage sur GitHub dans un nouvel onglet.

    +
  2. +
  3. +

    Ouvrez la console JavaScript de votre navigateur.

    +
  4. +
  5. +

    Toutes les données du web storage sont contenues dans deux structures de type objet : {{domxref("Window.sessionStorage", "sessionStorage")}} et {{domxref("Window.localStorage", "localStorage")}}. Le premier conserve les données aussi longtemps que le navigateur est ouvert (elles sont perdues lorsque le navigateur est fermé) et le second conserve les données même après que le navigateur ait été fermé puis ré-ouvert. Nous allons utiliser le second dans cet article car il est généralement plus utile.

    + +

    La méthode {{domxref("Storage.setItem()")}} permet de sauvegarder des données dans le storage — elle prend deux paramètres : le nom de l'entrée à enregistrer et sa valeur. Essayez de taper ce qui suit dans votre console JavaScript (changez le nom et la valeur si vous le voulez !) :

    + +
    localStorage.setItem('name','Chris');
    +
  6. +
  7. +

    La méthode {{domxref("Storage.getItem()")}} prend un paramètre — le nom de l'entrée que vous voulez récupérer — et retourne la valeur de l'entrée. Maintenant, tapez ces lignes dans votre console JavaScript :

    + +
    var myName = localStorage.getItem('name');
    +myName
    + +

    En tapant la deuxième ligne, vous devriez voir que la variable myName contient la valeur de l'entrée name.

    +
  8. +
  9. +

    La méthode {{domxref("Storage.removeItem()")}} prend un paramètre — le nom de l'entrée de vous voulez supprimer — et supprime l'entrée du web storage. Tapez les lignes suivantes dans votre console JavaScript :

    + +
    localStorage.removeItem('name');
    +var myName = localStorage.getItem('name');
    +myName
    + +

    La troisième ligne devrait maintenant retourner null — l'entrée name n'existe plus dans le web storage.

    +
  10. +
+ +

Les données persistent !

+ +

Une caractéristique clé du web storage est que les données persistent entre les différents chargements de page (et même lorsque le navigateur est arrêté dans le cas du localStorage). Regardons ça en action :

+ +
    +
  1. +

    Ouvrez notre template vide une fois de plus, mais cette fois dans un navigateur différent de celui dans lequel vous avez ouvert ce tutoriel. Cela rendra la suite plus facile.

    +
  2. +
  3. +

    Tapez ces lignes dans la console JavaScript du navigateur que vous venez d'ouvrir :

    + +
    localStorage.setItem('name','Chris');
    +var myName = localStorage.getItem('name');
    +myName
    + +

    Vous devriez voir que l'entrée name est bien là.

    +
  4. +
  5. +

    Maintenant, fermez le navigateur et ouvrez-le de nouveau.

    +
  6. +
  7. +

    Entrez les lignes suivantes :

    + +
    var myName = localStorage.getItem('name');
    +myName
    + +

    Vous devriez voir que la valeur est toujours accessible, quand bien même le navigateur a été redémarré.

    +
  8. +
+ +

Stockage séparé pour chaque domaine

+ +

Il existe un système de stockage distinct pour chaque domaine (chaque adresse web chargée dans le navigateur a accès à son propre storage et pas aux autres). Vous verrez que si vous chargez deux sites web (disons google.com et amazon.com) et essayez de stocker un élément, il ne sera pas disponible sur l'autre site.

+ +

C'est plutôt logique — imaginez les problèmes de sécurité qui se poseraient si les sites web pouvaient voir les données d'un autre !

+ +

Un exemple plus impliqué

+ +

Appliquons cette nouvelle connaissance pour écrire un exemple, cela vous donnera une idée de la façon dont le web storage peut être utilisé. Notre exemple permettra d'envoyer un nom, à la suite de quoi la page sera mise à jour pour donner un accueil personnalisé. Cet état persistera également après un rechargement de la page ou redémarrage du navigateur, puisqu'il sera stocké dans le web storage.

+ +

Le HTML de l'exemple est disponible à personal-greeting.html — il s'agit d'un site web très simple avec entête, contenu et pied de page, ainsi qu'un formulaire pour entrer votre nom.

+ +

+ +

Nous allons construire cet exemple pas à pas, cela vous permettra de comprendre comment ça marche.

+ +
    +
  1. +

    D'abord, copiez notre fichier personal-greeting.html dans un nouveau répertoire sur votre ordinateur.

    +
  2. +
  3. +

    Ensuite, créez un fichier index.js dans le même répertoire que le fichier HTML — le fichier HTML inclut ce script (voir ligne 40).

    +
  4. +
  5. +

    Nous allons commencer par récupérer les références de tous les éléments HTML qu'on manipulera dans cet exemple — nous les créons en tant que constantes car ces références n'ont pas besoin d'être modifiées au cours de l'exécution de l'application. Ajoutez les lignes suivantes à votre fichier JavaScript:

    + +
    // créer les constantes nécessaires
    +const rememberDiv = document.querySelector('.remember');
    +const forgetDiv = document.querySelector('.forget');
    +const form = document.querySelector('form');
    +const nameInput = document.querySelector('#entername');
    +const submitBtn = document.querySelector('#submitname');
    +const forgetBtn = document.querySelector('#forgetname');
    +
    +const h1 = document.querySelector('h1');
    +const personalGreeting = document.querySelector('.personal-greeting');
    +
  6. +
  7. +

    Ensuite, on doit ajouter un gestionnaire d'événement pour empêcher le formulaire d'être véritablement soumis lorsque le bouton de soumission est cliqué, puisque ce n'est pas le comportement que l'on veut. Ajoutez le bout de code suivant à la suite de du code précédent :

    + +
    // Empêcher le form d'être soumis
    +form.addEventListener('submit', function(e) {
    +  e.preventDefault();
    +});
    +
  8. +
  9. +

    Maintenant, on doit ajouter un gestionnaire d'événement pour gérer le clic sur le bouton "Say hello" (dire bonjour). Les commentaires expliquent ce que chaque instruction fait, mais, en substance, on prend le nom que l'utilisateur a entré dans le champs texte et on l'enregistre dans le web storage avec setItem(). Ensuite, on exécute une fonction appelée nameDisplayCheck() qui se charge de mettre à jour le contenu du site web. Ajoutez ceci au bas de votre code :

    + +
    // exécuter la fonction quand le bouton 'Say hello' est cliqué
    +submitBtn.addEventListener('click', function() {
    +  // stocker le nom entré dans le web storage
    +  localStorage.setItem('name', nameInput.value);
    +  // exécuter nameDisplayCheck() pour afficher la
    +  // page personnalisée et changer le formulaire
    +  nameDisplayCheck();
    +});
    +
  10. +
  11. +

    On doit maintenant gérer l'événement lorsque le bouton "Forget" (oublier) est cliqué — il est affiché une fois que le bouton "Say hello" a été cliqué (les deux boutons permettent de basculer d'un état à l'autre). Dans cette fonction, on supprime l'élément name du web storage en utilisant removeItem(), puis on exécute nameDisplayCheck() pour mettre à jour l'affichage. Ajoutez ceci au bas de votre code :

    + +
    // exécuter la fonction quand le bouton 'Forget' est cliqué
    +forgetBtn.addEventListener('click', function() {
    +  // supprimer l'item name du web storage
    +  localStorage.removeItem('name');
    + // exécuter nameDisplayCheck() pour afficher la
    + // page personnalisée et changer le formulaire
    +  nameDisplayCheck();
    +});
    +
  12. +
  13. +

    Il est maintenant temps de définir la fonction nameDisplayCheck() elle-même. Ici, on vérifie si l'élément name est stocké dans le web storage en utilisant localStorage.getItem('name') comme condition. S'il existe, la valeur retournée sera évaluée à true; sinon, comme false. S'il existe, on affiche un message d'accueil personnalisé et le bouton "Forget" du formulaire, tout en masquant le bouton "Say hello" du formulaire. Sinon, on affiche un message d'accueil générique et le bouton "Say hello". Encore une fois, mettez les lignes suivantes au bas de votre code :

    + +
    // définit la fonction nameDisplayCheck()
    +function nameDisplayCheck() {
    +  // vérifie si l'élément 'name' est stocké dans le web storage
    +  if(localStorage.getItem('name')) {
    +    // Si c'est le cas, affiche un accueil personnalisé
    +    let name = localStorage.getItem('name');
    +    h1.textContent = 'Welcome, ' + name;
    +    personalGreeting.textContent = 'Welcome to our website, ' + name + '! We hope you have fun while you are here.';
    +    // cache la partie 'remember' du formulaire et affiche la partie 'forget'
    +    forgetDiv.style.display = 'block';
    +    rememberDiv.style.display = 'none';
    +  } else {
    +    // Sinon, affiche un accueil générique
    +    h1.textContent = 'Welcome to our website ';
    +    personalGreeting.textContent = 'Welcome to our website. We hope you have fun while you are here.';
    +    // cache la partie 'forget' du formulaire et affiche la partie 'remember'
    +    forgetDiv.style.display = 'none';
    +    rememberDiv.style.display = 'block';
    +  }
    +}
    +
  14. +
  15. +

    Dernier point, mais non des moindres, on exécute la fonction nameDisplayCheck() à chaque fois que la page est chargée. Si on ne le faisait pas, l'accueil personnalisé ne serait pas affiché après qu'on ait rafraichit la page. Ajoutez ce qui suit au bas de votre code :

    + +
    document.body.onload = nameDisplayCheck;
    +
  16. +
+ +

Notre exemple est terminé — bien joué ! Il ne vous reste plus qu'à enregistrer votre code et tester votre page HTML dans un navigateur. Vous pouvez voir notre version terminée en direct ici (ou le code JavaScript terminé).

+ +
+

Note : Vous pouvez trouver un exemple un peu plus complexe dans l'article Utiliser l'API de stockage web.

+
+ +
+

Note : Dans la ligne <script src="index.js" defer></script> de notre version finie, l'attribut defer spécifie que le contenu de l'élément {{htmlelement("script")}} ne doit pas s'exécuter avant que la page ait fini de charger.

+
+ +

Stocker des données complexes — IndexedDB

+ +

L'API IndexedDB (parfois abrégé IDB) est un système de base de données complet disponible dans le navigateur. Vous pouvez y stocker des données complexes, les types ne sont pas limités à des valeurs simples de type chaînes ou nombres. Vous pouvez stocker des vidéos, des images et à peu près tout ce que vous voulez, dans une instance IndexedDB.

+ +

Cependant, cela a un coût : IndexedDB est beaucoup plus complexe à utiliser que l'API Web Storage. Dans cette section, nous ne ferons qu'égratigner la surface de ce qu'IndexedDB peut faire, mais nous vous en donnerons assez pour débuter.

+ +

Un exemple de stockage de notes

+ +

Nous allons voir un exemple qui vous permettra de stocker des notes dans votre navigateur, les voir et les supprimer, quand vous le souhaitez. Vous apprendrez à le construire par vous-même au fur et à mesure des explications et cela vous permettra de comprendre les parties fondamentales d'IDB.

+ +

L'application ressemble à ceci :

+ +

+ +

Chaque note a un titre et une description, chacun éditables individuellement. Le code JavaScript que nous allons voir ci-dessous contient des commentaires détaillés pour vous aider à comprendre ce qu'il se passe.

+ +

Pour commencer

+ +
    +
  1. Tout d'abord, copiez les fichiers index.html, style.css, et index-start.js dans un nouveau répertoire sur votre ordinateur.
  2. +
  3. Jetez un coup d'oeil aux fichiers. +
      +
    • Vous verrez que le HTML est assez simple : un site web avec une entête et un pied de page, ainsi qu'une zone de contenu principal contenant un emplacement pour afficher les notes et un formulaire pour en ajouter.
    • +
    • Le CSS fournit un style simple pour rendre plus clair ce qu'il se passe.
    • +
    • Le fichier JavaScript contient cinq constantes déclarées — des références à l'élément {{htmlelement("ul")}} dans lequel seront affichées les notes, les {{htmlelement("input")}} title et body, le {{htmlelement("form")}} lui-même, et un {{htmlelement("button")}}.
    • +
    +
  4. +
  5. Renommez votre fichier JavaScript en index.js. Vous êtes maintenant prêt pour y ajouter du code.
  6. +
+ +

Configuration initiale de la base de données

+ +

Voyons maintenant la première chose à faire, mettre en place la base de données.

+ +
    +
  1. +

    À la suite des déclarations de constantes, ajoutez les lignes suivantes :

    + +
    // Objet db pour stocker la BDD ouverte
    +let db;
    + +

    Ici, on déclare une variable appelée db — on l'utilisera plus tard pour stocker un objet permettant d'accéder à la base de données. On l'utilisera à plusieurs endroits, on l'a donc déclaré globablement ici pour faciliter les choses.

    +
  2. +
  3. +

    Ensuite, ajoutez ce qui suit au bas de votre code :

    + +
    window.onload = function() {
    +
    +};
    + +

    On écrira tout notre code dans le gestionnaire d'événement window.onload, appelé quand l'événement {{event("load")}} de la fenêtre est chargé, pour s'assurer qu'on n'essaiera pas d'utiliser IndexedDB avant que l'application ne soit complètement chargée (ça ne marcherait pas sinon).

    +
  4. +
  5. +

    À l'intérieur de window.onload, ajoutez ce qui suit :

    + +
    // Ouvrir la BDD; elle sera créée si elle n'existe pas déjà
    +// (voir onupgradeneeded)
    +let request = window.indexedDB.open('notes', 1);
    + +

    Cette ligne crée une requête request pour ouvrir la version 1 de la base de données appelée notes. Si elle n'existe pas déjà, on devra la créer via un gestionnaire d'événement.

    + +

    Vous verrez très souvent ce format dans IndexedDB. Les opérations de base de données prennent du temps et on ne veut pas suspendre le navigateur le temps de récupérer le résultat, les opérations sur la base de données sont donc {{Glossary("asynchronous", "asynchrones")}} — ce qui signifie qu'au lieu d'arriver immédiatement, elles se produiront à un moment ultérieur et un événement sera déclenché lorsque cela arrivera.

    + +

    Pour gérer cela dans IndexedDB, on crée d'abord une requête (que vous pouvez appeler comme vous le voulez — on l'appelle request pour que ce soit plus explicite). On utilise ensuite des gestionnaire d'événement pour exécuter du code lorsque les requêtes sont terminées, échouent, etc, ce que l'on va voir ci-dessous.

    + +
    +

    Note : Le numéro de version est important. Si vous voulez mettre à jour votre base de données (par exemple, pour modifier la structure de la table), vous devez ré-exécuter votre code avec un numéro de version supérieur et spécifier le schéma de la base de données avec le gestionnaire d'événement onupgradeneeded. Nous ne verrons pas la mise à jour de base de données dans ce tutoriel.

    +
    +
  6. +
  7. +

    Maintenant, ajoutez les gestionnaires d'événement suivants, juste en dessous des lignes précédentes — toujours à l'intérieur de window.onload :

    + +
    // la base de données n'a pas pu être ouverte avec succès
    +request.onerror = function() {
    +  console.log('Database failed to open');
    +};
    +
    +// la base de données a été ouverte avec succès
    +request.onsuccess = function() {
    +  console.log('Database opened successfully');
    +
    +  // Stocke la base de données ouverte dans la variable db. On l'utilise par la suite
    +  db = request.result;
    +
    +  // Exécute la fonction displayData() pour afficher les notes qui sont dans la BDD
    +  displayData();
    +};
    + +

    Le gestionnaire d'événement {{domxref("IDBRequest.onerror", "request.onerror")}} s'exécutera si la requête échoue. Cela vous permet de gérer le problème si cela arrive. Dans notre exemple, on affiche simplement un message dans la console JavaScript.

    + +

    Le gestionnare d'événement {{domxref("IDBRequest.onsuccess", "request.onsuccess")}}, d'autre part, s'exécutera si la requête aboutit, que la base de données a été ouverte avec succès. Lorsque cela arrive, la propriété {{domxref("IDBRequest.result", "request.result")}} contient alors un objet représentant la base de données ouverte, qui nous permet de la manipuler. On stocke cette valeur dans la variable db qu'on a crée plus tôt pour pouvoir l'utiliser ensuite. On exécute également une fonction appelée displayData(), qu'on définira plus tard — elle affiche les données de la base de données dans le {{HTMLElement("ul")}}. On l'exécute dès à présent pour que les notes en base de données soient affichées dès que la page est chargée.

    +
  8. +
  9. +

    Pour en finir avec cette section, on ajoute le gestionnaire d'événement qui est  probablement le plus important, {{domxref("IDBOpenDBRequest.onupgradeneeded", "request.onupdateneeded")}}. Il est exécuté si la base de données n'a pas déjà été créée ou si on veut ouvrir la base de données avec un numéro de version supérieur à celle qui existe (pour faire une mise à jour). Ajoutez le code suivant en dessous de votre gestionnaire précédent :

    + +
    // Spécifie les tables de la BDD si ce n'est pas déjà pas fait
    +request.onupgradeneeded = function(e) {
    +  // Récupère une référence à la BDD ouverte
    +  let db = e.target.result;
    +
    +  // Crée un objectStore pour stocker nos notes (une table)
    +  // Avec un champ qui s'auto-incrémente comme clé
    +  let objectStore = db.createObjectStore('notes', { keyPath: 'id', autoIncrement:true });
    +
    +  // Définit les champs que l'objectStore contient
    +  objectStore.createIndex('title', 'title', { unique: false });
    +  objectStore.createIndex('body', 'body', { unique: false });
    +
    +  console.log('Database setup complete');
    +};
    + +

    C'est ici qu'on définit le schéma (la structure) de notre base de données; c'est à dire l'ensemble des champs (ou colonnes) qu'il contient.

    + +
      +
    1. +

      On récupère une référence à la base de données existante depuis e.target.result (la propriété result de la cible de l'événement, c'est à dire l'objet request). C'est l'équivalent de la ligne db = request.result; du gestionnaire d'événement onsuccess, mais on doit le faire de cette manière ici puisque le gestionnaire d'événement onupgradeneeded est exécuté avant onsuccess — la valeur de db n'est pas encore disponible.

      +
    2. +
    3. +

      Ensuite, on utilise {{domxref("IDBDatabase.createObjectStore()")}} pour créer un object store (un container pour une collection d'objets) à l'intérieur de notre base de données. C'est l'équivalent d'une table dans un système de base de données traditionnel. On lui a donné le nom notes, et un champs id avec autoIncrement — pour chaque nouvelle entrée dans cette table, une valeur auto-incrementée sera attributée au champ id sans que le développeur n'ait à le définir. Le champ id est la clé de l'object store: il sera utilisé pour identifier de manière unique les entrées, permettant de les mettre à jour ou les supprimer.

      +
    4. +
    5. +

      On crée deux autres index (champs) en utilisant la méthode {{domxref("IDBObjectStore.createIndex()")}}: title (qui contiendra le titre de chaque note), et body (qui contiendra la description de chaque note).

      +
    6. +
    +
  10. +
+ +

Avec ce simple schéma de base de données en place, on va pouvoir ajouter des entrées à la base de données, des objets qui ressembleront à ça :

+ +
{
+  title: "Acheter du lait",
+  body: "Lait de vache et de soja.",
+  id: 8
+}
+ +

Ajouter des données à la base de données

+ +

Maintenant, voyons comment ajouter des entrées dans la base de données. On le fera en utilisant le formulaire de notre page.

+ +
    +
  1. +

    À la suite du gestionnaire d'événement précédent (mais toujours dans window.onload), ajoutez la ligne suivante — elle définit un gestionnaire d'événement onsubmit pour exécuter la fonction addData() quand le formulaire est soumis (que le {{htmlelement("button")}} envoyer est pressé et que les champs du formulaire sont valides) :

    + +
    // Créer un gestionnaire onsubmit pour appeler la fonction addData() quand le formulaire est soumis
    +form.onsubmit = addData;
    +
  2. +
  3. +

    Maintenant, définissons la fonction addData(). Ajoutez ce qui suit après la ligne précédente :

    + +
    // Définit la fonction addData()
    +function addData(e) {
    +  // empêcher le formulaire d'être soumis vers le serveur
    +  e.preventDefault();
    +
    +  // récupérer les valeurs entrées dans les champs du formulaire
    +  // et les stocker dans un objet qui sera inséré en BDD
    +  let newItem = { title: titleInput.value, body: bodyInput.value };
    +
    +  // ouvrir une transaction en lecture/écriture
    +  let transaction = db.transaction(['notes'], 'readwrite');
    +
    +  // récupérer l'object store de la base de données qui a été ouvert avec la transaction
    +  let objectStore = transaction.objectStore('notes');
    +
    +  // demander l'ajout de notre nouvel objet à l'object store
    +  var request = objectStore.add(newItem);
    +  request.onsuccess = function() {
    +    // vider le formulaire, pour qu'il soit prêt pour un nouvel ajout
    +    titleInput.value = '';
    +    bodyInput.value = '';
    +  };
    +
    +  // attendre la fin de la transaction, quand l'ajout a été effectué
    +  transaction.oncomplete = function() {
    +    console.log('Transaction completed: database modification finished.');
    +
    +    // mettre à jour l'affichage pour montrer le nouvel item en exécutant displayData()
    +    displayData();
    +  };
    +
    +  transaction.onerror = function() {
    +    console.log('Transaction not opened due to error');
    +  };
    +}
    + +

    C'est assez complexe, voyons ça pas à pas :

    + +
      +
    1. +

      On exécute {{domxref("Event.preventDefault()")}} sur l'objet événement pour empêcher le formulaire d'être véritablement soumis (cela provoquerait une actualisation de la page et gâcherait l'expérience utilisateur).

      +
    2. +
    3. +

      On crée un objet représentant une entrée à ajouter dans la base de données, en le remplissant avec les valeurs des champs du formulaire. Notez qu'on n'a pas besoin d'inclure explicitement une valeur id — comme nous l'avons précédemment expliqué, il est auto-rempli.

      +
    4. +
    5. +

      On ouvre une transaction en lecture/écritre (readwrite) sur l'object store notes en utilisant la méthode {{domxref("IDBDatabase.transaction()")}}. Cet object transaction va nous permettre d'accéder à l'object store, pour ajouter une nouvelle entrée par exemple.

      +
    6. +
    7. +

      On récupère l'object store de la transaction avec la méthode {{domxref("IDBTransaction.objectStore()")}} et on le stocke dans la variable objectStore.

      +
    8. +
    9. +

      On ajoute un nouvel enregistrement à la base de données en utilisant {{domxref("IDBObjectStore.add()")}}. Cela crée une requête, sur le même principe qu'on a déjà vu.

      +
    10. +
    11. On ajoute des gestionnaires d'événement à request et transaction pour exécuter du code aux points importants de leur cycle de vie : +
        +
      • Quand la requête a réussit, on efface les champs du formulaire — pour pouvoir ajouter une nouvelle note
      • +
      • Quand la transaction est terminé, on réexécute la fonction displayData() — pour mettre à jour l'affichage de notes sur la page.
      • +
      +
    12. +
    +
  4. +
+ +

Afficher les données

+ +

Nous avons déjà appelé displayData() deux fois dans notre code, nous allons maintenant définir cette fonction. Ajoutez ce qui suit à votre code, en dessous de la définition de la fonction précédente :

+ +
// Définit la fonction displayData()
+function displayData() {
+  // Vide le contenu de la liste à chaque fois qu'on la met à jour
+  // Si on ne le faisait pas, des duplicats seraient affichés à chaque ajout
+  while (list.firstChild) {
+    list.removeChild(list.firstChild);
+  }
+
+  // Ouvre l'object store puis récupère un curseur - qui va nous permettre d'itérer
+  // sur les entrées de l'object store
+  let objectStore = db.transaction('notes').objectStore('notes');
+  objectStore.openCursor().onsuccess = function(e) {
+    // Récupère une référence au curseur
+    let cursor = e.target.result;
+
+    // S'il reste des entrées sur lesquelles itérer, on exécute ce code
+    if(cursor) {
+      // Crée un li, h3, et p pour mettre les données de l'entrée puis les ajouter à la liste
+      let listItem = document.createElement('li');
+      let h3 = document.createElement('h3');
+      let para = document.createElement('p');
+
+      listItem.appendChild(h3);
+      listItem.appendChild(para);
+      list.appendChild(listItem);
+
+      // Récupère les données à partir du curseur et les met dans le h3 et p
+      h3.textContent = cursor.value.title;
+      para.textContent = cursor.value.body;
+
+      // Met l'ID de l'entrée dans un attribut du li, pour savoir à quelle entrée il correspond
+      // Ce sera utile plus tard pour pouvoir supprimer des entrées
+      listItem.setAttribute('data-note-id', cursor.value.id);
+
+      // Crée un bouton et le place dans le li
+      let deleteBtn = document.createElement('button');
+      listItem.appendChild(deleteBtn);
+      deleteBtn.textContent = 'Delete';
+
+      // Définit un gestionnaire d'événement pour appeler deleteItem() quand le bouton supprimer est cliqué
+      deleteBtn.onclick = deleteItem;
+
+      // Continue l'itération vers la prochaine entrée du curseur
+      cursor.continue();
+    } else {
+      // Si la liste est vide, affiche un message "Aucune note n'existe"
+      if(!list.firstChild) {
+        let listItem = document.createElement('li');
+        listItem.textContent = 'No notes stored.';
+        list.appendChild(listItem);
+      }
+      // Il n'y a plus d'entrées dans le curseur
+      console.log('Notes all displayed');
+    }
+  };
+}
+ +

Encore une fois, pas à pas :

+ +
    +
  1. +

    D'abord on vide le contenu de l'élément {{htmlelement("ul")}}, pour pouvoir le remplir avec le contenu mis à jour. Si on ne le faisait pas, on obtiendrait une énorme liste de contenus dupliqués à chaque mise à jour.

    +
  2. +
  3. +

    Ensuite, on récupère une référence à l'object store notes en utilisant {{domxref("IDBDatabase.transaction()")}} et {{domxref("IDBTransaction.objectStore()")}} comme nous l'avons fait dans addData(), mais en chaînant ces deux instructions en une seule ligne.

    +
  4. +
  5. +

    L'étape suivante consiste à utiliser la méthode {{domxref("IDBObjectStore.openCursor()")}} pour ouvrir un curseur — une construction qui peut être utilisée pour itérer sur les entrées d'un object store. On chaîne un gestionnaire d'événement onsuccess à la fin de cette opération pour rendre le code plus concis — dès que le curseur est récupéré, le gestionnaire est exécuté.

    +
  6. +
  7. +

    On récupère une référence au curseur lui-même (un objet {{domxref("IDBCursor")}}) avec cursor = e.target.result.

    +
  8. +
  9. +

    Ensuite, on vérifie si le curseur contient une entrée de l'object store (if(cursor){ ... }) — si c'est le cas, on crée des éléments du DOM, les remplit avec les données de l'entrée, et les insère dans la page (à l'intérieur de l'élément <ul>). On inclut un bouton de suppression, qui, quand il est cliqué, supprime l'entrée en cours en appelant la fonction deleteItem() — que nous allons voir dans la section suivante.

    +
  10. +
  11. +

    À la fin du bloc if, on utilise la méthode {{domxref("IDBCursor.continue()")}} pour avancer le curseur à la prochaine entrée dans l'object store et réexécuter le bloc. S'il reste une autre entrée sur laquelle itérer, elle sera à son tour insérée dans la page, continue() sera exécuté à nouveau, et ainsi de suite.

    +
  12. +
  13. +

    Quand il n'y a plus d'enregistrements à parcourir, le curseur retourne undefined, et le bloc else sera donc exécuté à la place. Ce bloc vérifie si des notes ont été insérées dans le <ul> — si ce n'est pas le cas, on insère un message indiquant qu'il n'existe aucune note.

    +
  14. +
+ +

Supprimer une note

+ +

Come nous avons vu ci-dessus, lorsque le bouton supprimer est cliqué, la note correspondante est supprimée. Cette action est réalisée par la fonction deleteItem(), que l'on définit ainsi :

+ +
// Définit la fonction deleteItem()
+function deleteItem(e) {
+  // Récupère l'id de l'entrée que l'on veut supprimer
+  // On doit le convertir en nombre avant d'essayer de récupérer l'entrée correspondante dans IDB
+  // les clés sont sensibles à la casse
+  let noteId = Number(e.target.parentNode.getAttribute('data-note-id'));
+
+  // Ouvre une transaction et supprime la note ayant l'id récupéré ci-dessus
+  let transaction = db.transaction(['notes'], 'readwrite');
+  let objectStore = transaction.objectStore('notes');
+  let request = objectStore.delete(noteId);
+
+  // Indique à l'utilisateur que l'entrée a été supprimée
+  transaction.oncomplete = function() {
+    // supprime l'élément parent du bouton, le li
+    // pour qu'il ne soit plus affiché
+    e.target.parentNode.parentNode.removeChild(e.target.parentNode);
+    console.log('Note ' + noteId + ' deleted.');
+
+    // Si la liste est vide, affiche un message qui l'indique
+    if(!list.firstChild) {
+      let listItem = document.createElement('li');
+      listItem.textContent = 'No notes stored.';
+      list.appendChild(listItem);
+    }
+  };
+}
+ + + +

Et voilà ! L'exemple devrait maintenant fonctionner.

+ +
+

Note : Si vous rencontrez des difficultés, n'hésitez pas à consulter notre exemple en direct (ou voir le code source).

+
+ +

Stocker des données complexes avec IndexedDB

+ +

Comme nous l'avons mentionné auparavant, IndexedDB peut être utilisé pour stocker plus que de simples chaînes de caractères. On peut stocker à peu près tout ce qu'on veux, y compris des objets complexes tels que des vidéos ou des images. Et ce n'est pas plus difficilte à réaliser qu'avec n'importe quel autre type de données.

+ +

Pour vous montrer comment le faire, nous avons écrit un autre exemple appelé IndexedDB video store (le voir en direct). Lorsque vous exécutez l'exemple pour la première fois, il télécharge des vidéos à partir du réseau, les stocke dans une base de données IndexedDB, puis affiche les vidéos dans des éléments {{htmlelement("video")}} de l'interface utilisateur. Les prochaines fois que vous l'exécutez, il récupère les vidéos de la base de données — cela rend les chargements suivants beaucoup plus rapides et moins gourmands en bande passante.

+ +

Passons en revue les parties les plus intéressantes de l'exemple. Nous ne regarderons pas tout — une grande partie est similaire à l'exemple précédent, et le code est bien commenté.

+ +
    +
  1. +

    Pour cet exemple, nous avons stocké le nom des vidéos à récupérer dans un tableau d'objets :

    + +
    const videos = [
    +  { 'name' : 'crystal' },
    +  { 'name' : 'elf' },
    +  { 'name' : 'frog' },
    +  { 'name' : 'monster' },
    +  { 'name' : 'pig' },
    +  { 'name' : 'rabbit' }
    +];
    +
  2. +
  3. +

    Pour commencer, une fois que la base de données a été ouverte, on exécute la fonction init(). Elle boucle sur les noms des vidéos et essaie de charger l'entrée correspondante dans la base de données videos.

    + +

    On peut facilement vérifier si une entrée a été trouvée en vérifiant si request.result est évalué à true — si l'entrée n'est pas présente, la valeur retournée est undefined.

    + +

    Les vidéos présentes en base de données (stockées sous formes de blobs), sont directement passées à la fonction displayVideo() pour les afficher dans l'interface utilisateur. Pour les vidéos non présentes, on appelle la fonction fetchVideoFromNetwork(), qui récupère la vidéo à partir du réseau.

    + +
    function init() {
    +  // Boucle sur les vidéos une par une
    +  for(let i = 0; i < videos.length; i++) {
    +    // Ouvre une transaction, récupère l'object store, et récupère chaque video par son nom
    +    let objectStore = db.transaction('videos').objectStore('videos');
    +    let request = objectStore.get(videos[i].name);
    +    request.onsuccess = function() {
    +      // Si l'entrée existe dans la BDD (le résultat n'est pas undefined)
    +      if(request.result) {
    +        // Affiche la vidéo en utilisant displayVideo()
    +        console.log('taking videos from IDB');
    +        displayVideo(request.result.mp4, request.result.webm, request.result.name);
    +      } else {
    +        // Récupère la vidéo à partir du réseau
    +        fetchVideoFromNetwork(videos[i]);
    +      }
    +    };
    +  }
    +}
    +
  4. +
  5. +

    Le bout de code qui suit est extrait de la fonction fetchVideoFromNetwork() — ici, on récupère les versions MP4 et WebM de la vidéos en utilisant deux requêtes {{domxref("fetch()", "WindowOrWorkerGlobalScope.fetch()")}} distinctes. On utilise ensuite la méthode {{domxref("blob()", "Body.blob()")}} pour extraire la réponse sous forme de blob, ce qui nous donne une représentation objet de la vidéo que l'on peut stocker et afficher plus tard.

    + +

    Il reste cependant un problème — ces deux requêtes sont asynchrones et ont veut afficher/stocker la vidéo uniquement lorsque les deux promesses sont résolues. Heureusement, il existe une méthode native qui gère ce problème — {{jsxref("Promise.all()")}}. Elle prend un argument — la liste de toutes les promesses qui doivent être attendues — et retourne elle-même une promesse. Quand toutes les promesses sont résolues, alors la promesse de la méthode all() est résolue, avec pour valeur un tableau contenant toutes les valeurs individuelles retournées par les promesses.

    + +

    À l'intérieur du bloc all(), vous pouvez voir qu'on appelle la fonction displayVideo(), comme on l'a fait précédemment, pour afficher les vidéos dans l'interface utilisateur, puis la fonction storeVideo() pour stocker ces vidéos dans la base de données.

    + +
    let mp4Blob = fetch('videos/' + video.name + '.mp4').then(response =>
    +  response.blob()
    +);
    +let webmBlob = fetch('videos/' + video.name + '.webm').then(response =>
    +  response.blob()
    +);
    +
    +// Exécuter le bloc de code suivant lorsque les deux promesses sont résolues
    +Promise.all([mp4Blob, webmBlob]).then(function(values) {
    +  // Afficher la vidéo récupérée à partir du réseau avec displayVideo()
    +  displayVideo(values[0], values[1], video.name);
    +  // La stocker dans IDB avec storeVideo()
    +  storeVideo(values[0], values[1], video.name);
    +});
    +
  6. +
  7. +

    Regardons storeVideo() en premier. Cela ressemble beaucoup à ce qu'on a fait dans l'exemple précédent pour ajouter des données à la base de données — on ouvre une transaction en lecture/écriture et on récupère l'object store de videos, on crée un objet à ajouter à la base de données et on l'ajoute avec {{domxref("IDBObjectStore.add()")}}.

    + +
    function storeVideo(mp4Blob, webmBlob, name) {
    +  // Ouvre une transaction, récupère object store
    +  let objectStore = db.transaction(['videos'], 'readwrite').objectStore('videos');
    +  // Crée une entrée à ajouter à IDB
    +  let record = {
    +    mp4 : mp4Blob,
    +    webm : webmBlob,
    +    name : name
    +  }
    +
    +  // Ajoute l'entrée à IDB avec add()
    +  let request = objectStore.add(record);
    +
    +  ...
    +
    +};
    +
  8. +
  9. +

    Enfin, displayVideo() crée les éléments DOM nécessaires pour insérer la vidéo dans l'interface utilisateur, puis les ajoute à la page. Les parties les plus intéressantes sont copiées ci-dessous — pour afficher notre blob vidéo dans un élément <video>, on doit créer un objet URL (URL interne qui pointe vers un blob en mémoire) en utilisant la méthode {{domxref("URL.createObjectURL()")}}. Une fois que c'est fait, on peut assigner l'URL comme valeur d'attribut src de l'élément {{htmlelement("source")}}, et ça marche.

    + +
    function displayVideo(mp4Blob, webmBlob, title) {
    +  // Crée l'objet URL à partir du blob
    +  let mp4URL = URL.createObjectURL(mp4Blob);
    +  let webmURL = URL.createObjectURL(webmBlob);
    +
    +  ...
    +
    +  let video = document.createElement('video');
    +  video.controls = true;
    +  let source1 = document.createElement('source');
    +  source1.src = mp4URL;
    +  source1.type = 'video/mp4';
    +  let source2 = document.createElement('source');
    +  source2.src = webmURL;
    +  source2.type = 'video/webm';
    +
    +  ...
    +}
    +
  10. +
+ +

Stockage hors-ligne de ressources

+ +

L'exemple ci-dessus montre comment créer une application qui stocke des ressources volumineuses dans une base de données IndexedDB, évitant ainsi de devoir les télécharger plus d'une fois. C'est déjà une grande amélioration pour l'expérience utilisateur, mais il manque encore une chose: les fichiers HTML, CSS, et JavaScript doivent encore être téléchargés à chaque fois que le site est accédé, ce qui veut dire qu'il ne fonctionnera pas lorsqu'il n'y a pas de connexion réseau

+ +

+ +

C'est là qu'interviennet les Service workers et l'API étroitement liée, Cache.

+ +

Service Worker / Cache

+ +

Un service worker est un fichier JavaScript qui, pour faire simple, est associé à une origine (un site web à un domaine donné) lorsque le navigateur y accède. Une fois associé, il peut contrôler les pages disponibles pour cette origine. Il le fait en s'installant entre la page chargée et le réseau, interceptant les requêtes réseau visant cette origine.

+ +

Quand le service worker intercepte une requête, il peut faire tout ce que vous voulez (voir quelques idées de cas d'utilisation), mais l'exemple le plus classique est de sauvegarder les réponses réseau hors-ligne pour fournir ces réponses aux requêtes qui suivent au lieu d'utiliser le réseau. Ainsi, cela vous permet de faire fonctionner un site web complètement hors-ligne.

+ +

L'API Cache est un autre mécanisme de stockage côté client, il a été conçu pour enregistrer les réponses HTTP et fonctionne donc très bien en synergie avec les service workers.

+ +
+

Note : Les Service workers et Cache sont pris en charge par la plupart des navigateurs modernes aujourd'hui. Au moment de la rédaction de cet article, Safari était encore occupé à l'implémenter, mais il devrait bientôt être disponible.

+
+ +

Un exemple service worker

+ +

Voyons un exemple, pour vous donner une idée de ce à quoi cela pourrait ressembler. Nous avons crée une autre version de l'exemple video store vu précédemment. Cela fonctionne de manière identique, mais enregistre également le HTML, CSS, et JavaScript dans l'API Cache via un service worker, permettant à l'exemple de marcher hors ligne!

+ +

Voir IndexedDB video store avec service worker en direct, ou voir le code source.

+ +

Enregistrer le service worker

+ +

La première chose à noter est qu'il  a un peu plus de code placé dans le fichier JavaScript principal (voir index.js):

+ +
// Enregistre un service worker pour contrôler le site hors-ligne
+if('serviceWorker' in navigator) {
+  navigator.serviceWorker
+           .register('/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js')
+           .then(function() { console.log('Service Worker Registered'); });
+}
+ + + +
+

Note : Le chemin du fichier sw.js est relatif à l'origine du site, et non au fichier JavaScript qui l'appelle.
+ Le service worker est sur https://mdn.github.io/learning-area/.../sw.js. L'origine est https://mdn.github.io. Le chemin donné doit donc être /learning-area/.../sw.js.
+ Si vous vouliez héberger cet exemple sur votre propre serveur, vous devriez changer le chemin en conséquence. C'est plutôt inhabituel, mais cela doit fonctionner de cette façon pour des raisons de sécurité.

+
+ +

Installer le service worker

+ +

Quand une page sous le contrôle du service worker est appelée (par exemple lorsque l'exemple est rechargé), alors le service worker est installé par rapport à cette page et il peut commencer à la contrôler. Quand cela arrive, un événement install est déclenché sur le service worker; vous pouvez écrire du code dans le service worker pour qu'il réponde à cette installation.

+ +

Prenons pour exemple le fichier sw.js (le service worker) :

+ +
self.addEventListener('install', function(e) {
+ e.waitUntil(
+   caches.open('video-store').then(function(cache) {
+     return cache.addAll([
+       '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/',
+       '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.html',
+       '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.js',
+       '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/style.css'
+     ]);
+   })
+ );
+});
+ +
    +
  1. +

    Le gestionnaire d'événément install est enregistré sur self. Le mot-clé self est un moyen de faire référence au service worker de la portée globale à partir de son fichier.

    +
  2. +
  3. +

    À l'intérieur du gestionnaire d'installation, on utilise la méthode {{domxref("ExtendableEvent.waitUntil()")}}, disponible sur l'objet événement, pour signaler que le navigateur ne doit pas terminer l'installation du service worker avant que la promesse qu'il contient ne soit résolue avec succès.

    +
  4. +
  5. +

    Ici, on voit l'API Cache en action: on utilise la méthode {{domxref("CacheStorage.open()")}} pour ouvrir un nouvel objet cache dans lequel les réponses seront stockées (similaire à un object store IndexedDB). Cette promesse se résout avec un objet {{domxref("Cache")}} représentant le cache du video-store.

    +
  6. +
  7. +

    On utilise la méthode {{domxref("Cache.addAll()")}} pour récupérer une série de ressources et ajouter leur réponse au cache.

    +
  8. +
+ +

C'est tout pour l'instant, l'installation est terminée.

+ +

Répondre aux futures requêtes

+ +

Avec le service worker enregistré et installé pour notre page HTML, et les ressources pertinentes ajoutées au cache, on est presque prêts. Il n'y a plus qu'une chose à faire: écrire du code pour répondre aux prochaines requêtes réseau.

+ +

C'est ce que fait le second bloc de code dans sw.js :

+ +
self.addEventListener('fetch', function(e) {
+  console.log(e.request.url);
+  e.respondWith(
+    caches.match(e.request).then(function(response) {
+      return response || fetch(e.request);
+    })
+  );
+});
+ +
    +
  1. +

    On ajoute un deuxième gestionnaire d'événement au service worker, qui exécute une fonction quand l'événement fetch est déclenché. Cela arrive quand le navigateur requête une ressource dans le même répertoire que le service worker (ou sous-répertoire).

    +
  2. +
  3. +

    À l'intérieur de cette fonction, on affiche l'URL de la ressource demandée dans la console, et on utilise la méthode {{domxref("FetchEvent.respondWith()")}} pour retourner une réponse personnalisée à la requête.

    +
  4. +
  5. +

    Pour construire la réponse, on utilise d'abord {{domxref("CacheStorage.match()")}} afin de vérifier si la requête est en cache (qu'une requête correspond à l'URL demandée est en cache).

    +
  6. +
  7. +

    Si elle est trouvée, la promesse se résout avec la réponse correspondante; sinon, avec undefined. Dans ce cas, on récupère la réponse à partir du réseau, en utilisant fetch(), et on retourne le résultat.

    +
  8. +
+ +

C'est tout pour notre service worker. Il y a tout un tas de choses que vous pouvez faire avec — pour plus de détails, consultez le service worker cookbook. Et merci à Paul Kinlan pour son article Adding a Service Worker and Offline into your Web App, qui a inspiré cet exemple.

+ +

Tester l'exemple hors-ligne

+ +

Pour tester notre exemple de service worker, rechargez d'abord la page pour vous assurer qu'il est bien installé. Une fois que c'est fait, vous pouvez soit:

+ + + +

Si vous actualisez votre page d'exemple, vous devriez toujours la voir se charger normalemment. Tout est stocké hors connexion — les ressources de la page dans Cache et les vidéos dans une base de données IndexedDB.

+ +

Sommaire

+ +

C'est tout pour l'instant. Nous espérons que vous avez trouvé notre récapitulatif des technologies de stockage côté client utile.

+ +

Voir aussi

+ + + +

{{PreviousMenu("Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs", "Learn/JavaScript/Client-side_web_APIs")}}

+ +

Dans ce module

+ + diff --git a/files/fr/learn/javascript/client-side_web_apis/drawing_graphics/index.html b/files/fr/learn/javascript/client-side_web_apis/drawing_graphics/index.html new file mode 100644 index 0000000000..ce68c6620b --- /dev/null +++ b/files/fr/learn/javascript/client-side_web_apis/drawing_graphics/index.html @@ -0,0 +1,922 @@ +--- +title: Dessiner des éléments graphiques +slug: Apprendre/JavaScript/Client-side_web_APIs/Drawing_graphics +tags: + - API + - Apprendre + - Articles + - Canvas + - Codage + - Débutant + - Graphismes + - JavaScript + - WebGL +translation_of: Learn/JavaScript/Client-side_web_APIs/Drawing_graphics +--- +
{{LearnSidebar}}{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Third_party_APIs", "Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs", "Learn/JavaScript/Client-side_web_APIs")}}
+ +

Le navigateur contient des outils de programmation graphique très puissants, du langage SVG (Scalable Vector Graphics), aux APIs pour dessiner sur les éléments HTML {{htmlelement("canvas")}}, (voir API Canvas et WebGL). Cet article fournit une introduction à canvas et introduit d'autres ressources pour vous permettre d'en apprendre plus.

+ + + + + + + + + + + + +
Prérequis:Bases de JavaScript (voir premiers pas, les briques JavaScript, introduction aux objets), les notions de bases des APIs côté client
Objectif:Apprendre les bases pour dessiner sur des éléments <canvas> en utilisant JavaScript.
+ +

Éléments graphiques sur le Web

+ +

Comme nous en avons parlé dans notre module HTML Multimédia et Intégration, le web était à l'origine uniquement du texte, ce qui était très ennuyeux. Les images ont donc été introduites — d'abord via l'élément {{htmlelement("img")}} et plus tard via les propriétés CSS comme {{cssxref("background-image")}}, et SVG.

+ +

Ce n'était cependant toujours pas assez. Tandis qu'il était possible d'utiliser CSS et JavaScript pour animer (ou manipuler) les images vectorielles SVG — puisqu'elles sont définies par le balisage — il n'y avait aucun moyen de faire de même pour les images bitmap, et les outils disponibles étaient plutôt limités. Le Web n'avait toujours pas de moyen efficace de créer des animations de jeux, des scènes 3D, et autres dispositions couramment traitées par les langages de bas niveau tels que C++ ou Java.

+ +

La situation a commencé à s'améliorer quand les navigateurs ont commencé à prendre en charge l'élément {{htmlelement("canvas")}} et l' API Canvas associée — Apple l'a inventée vers 2004, et les autres navigateurs l'ont l'implémentée dans les années qui ont suivi. Comme vous le verrez dans cet article, canvas fournit de nombreux outils utiles à la création d'animation 2D, jeux, visualisations de données, et autres types d'application, particulièrement quand il est combiné à d'autres APIs que la plateforme web fournit.

+ +

L'exemple ci-dessous montre une simple animation de balles qui rebondissent en canvas 2D, que nous avons déjà vue dans notre module La construction d'objet en pratique:

+ +

{{EmbedGHLiveSample("learning-area/javascript/oojs/bouncing-balls/index-finished.html", '100%', 500)}}

+ +

Autour de 2006-2007, Mozilla a commencé à travailler sur une implémentation expérimentale de canvas 3D. C'est devenu WebGL, lequel a gagné en popularité parmi les fournisseurs de navigateur, et a été standardisé autour de 2009-2010. WebGL permet de créer de véritables graphiques 3D dans le navigateur web; l'exemple ci-dessous montre un simple cube WebGL qui tourne:

+ +

{{EmbedGHLiveSample("learning-area/javascript/apis/drawing-graphics/threejs-cube/index.html", '100%', 500)}}

+ +

Cet article se concentrera principalement sur les canvas 2D, car le code WebGL brut est très complexe. Nous montrerons cependant comment utiliser une bibliothèque WebGL pour créer une scène 3D plus facilement, et vous pourrez  par la suite suivre le tutoriel WebGL, qui couvre le code WebGL brut.

+ +
+

Note: Canvas est très bien pris en charge parmi les différents navigateurs, à l'exception de IE 8 (et inférieur) pour les canvas 2D, et IE 11 (et inférieur) pour WebGL.

+
+ +

Apprentissage actif: Débuter avec un <canvas>

+ +

Si vous voulez créer une scène 2D ou 3D sur une page web, vous devez commencer avec un élément HTML {{htmlelement("canvas")}}. Cet élément est utilisé pour définir la zone de la page où l'image sera dessinée. C'est aussi simple que d'inclure l'élément dans la page:

+ +
<canvas width="320" height="240"></canvas>
+ +

Cela va créer un canvas sur la page d'une taille de 320 pixels par 240.

+ +

À l'intérieur des balises du canvas, vous pouvez mettre du contenu alternatif, qui est affiché si le navigateur de l'utilisateur ne prend pas en charge les canvas.

+ +
<canvas width="320" height="240">
+  <p>Votre navigateur ne prend pas en charge canvas. Boo hoo!</p>
+</canvas>
+ +

Bien sûr, le message ci-dessus est vraiment inutile! Dans un exemple réel, vous voudriez plutôt associer le contenu alternatif au contenu du canvas. Par exemple, si vous voulez afficher un graphique en temps réel des cours boursiers, le contenu alternatif pourrait être une image statique du dernier graphique, avec un texte indiquant quels sont les prix.

+ +

Crée et dimensionner notre canvas

+ +

Commençons par créer notre propre canvas, que nous utiliserons pour dessiner nos futures expériences.

+ +
    +
  1. +

    Premièrement, copiez localement notre fichier 0_canvas_start.html, et ouvez-le dans votre éditeur de texte.

    +
  2. +
  3. +

    Ajoutez le code suivant à l'intérieur, juste après la balise {{htmlelement("body")}} ouvrante:

    + +
    <canvas class="myCanvas">
    +  <p>Ajouter un contenu alternatif approprié ici.</p>
    +</canvas>
    + +

    Nous avons ajouté un attribut class à l'élément <canvas> pour que ce soit plus facile à sélectionner dans le cas où nous aurions plusieurs canvas sur la page. Et nous avons supprimé les attributs width et height pour le moment (vous pouvez les remettre si vous le voulez mais nous les définirons en utilisant JavaScript dans une section plus bas). Les canvas sans hauteur et largeur explicites sont définits par défaut à 300 pixels par 150.

    +
  4. +
  5. +

    Maintenant, ajoutez les lignes suivantes à l'intérieur de l'élément {{htmlelement("script")}}:

    + +
    var canvas = document.querySelector('.myCanvas');
    +var width = canvas.width = window.innerWidth;
    +var height = canvas.height = window.innerHeight;
    + +

    Ici, nous avons stocké une référence vers le canvas dans la variable canvas. Sur la deuxième ligne, nous affectons à la fois une nouvelle variable width et la propriété width du canvas à {{domxref("Window.innerWidth")}} (ce qui nous donne la largeur de la fenêtre). Sur la troisième ligne, nos affectons à la fois une nouvelle variable height et la propriété height du canvas à {{domxref("Window.innerHeight")}} (ce qui nous donne la hauteur de la fenêtre). Nous avons donc un canvas qui remplit toute la largeur et hauteur de la fenêtre!

    + +

    Vous avez également vu que nous avons chaîné les assignations ensemble avec plusieurs signes égal — ce qui est autorié en JavaScript, et c'est une bonne technique si vous voulez que plusieurs variables aient la même valeur. Nous avons gardé la hauteur et largeur du canvas facilement accessibles dans les variables width/height, ces valeurs seront utiles plus tard (par exemple, si vous voulez dessiner quelque chose exactement à mi-chemin de la largeur du canvas).

    +
  6. +
  7. +

    Si vous sauvegardez et chargez votre exemple dans le navigateur maintenant, vous ne verrez rien, ce qui est normal, mais vous verrez également des barres de défilement, ce qui est un problème pour nous. Cela se produit parce que l'élément {{htmlelement("body")}} a des {{cssxref("margin")}} qui, ajoutées à la taille du canvas, résulte en un document qui est plus large que la fenêtre. Pour se débarasser des barres de défilement, nous devons supprimer les {{cssxref("margin")}} et aussi définir {{cssxref("overflow")}} à hidden. Ajoutez ce qui suit à l'intérieur du {{htmlelement("head")}} du document:

    + +
    <style>
    +  body {
    +    margin: 0;
    +    overflow: hidden;
    +  }
    +</style>
    + +

    Les barres de défilement ne devraient plus être là.

    +
  8. +
+ +
+

Note: Vous devrez généralement définir la taille de l'image en utilisant les attributs HTML ou les propriétéss DOM, comme expliqué ci-dessus. Vous pourriez théoriquement utiliser CSS, le problème étant que le dimensionnement le canvas est alors effectué après que le contenu canvas n'ait été calculé, et comme toute autre image (puisque le canvas une fois affiché n'est plus qu'une simple image), elle peut devenir pixelisée/déformée.

+
+ +

Obtenir le contexte du canvas et configuration finale

+ +

Nous devons faire une dernière chose avant de considérer notre template finit. Pour dessiner sur le canvas, nous devons récupérer une référence à la zone de dessin, appelé un contexte. Pour ce faire, on utilise la méthode {{domxref("HTMLCanvasElement.getContext()")}}, qui, pour un usage basique ne prend qu'un seul paramètre, spécifiant quel type de contexte nous voulons récupérer.

+ +

En l'occurence, nous voulons un canvas 2D, alors ajoutez le JavaScript suivant à la suite des autres instructions à l'intérieur de l'élément <script>:

+ +
var ctx = canvas.getContext('2d');
+ +
+

Note: Vous pouvez choisir d'autres types de contexte comme webgl pour WebGL, webgl2 pour WebGL 2, etc., mais nous n'en aurons pas besoin dans cet article.

+
+ +

Voilà — notre canvas est maintenant préparé et prêt à être dessiné! La variable ctx contient désormais un objet {{domxref("CanvasRenderingContext2D")}}, et toutes les opérations de dessin sur le canvas impliqueront de manipuler cet objet.

+ +

Faisons une dernière chose avant de passer à autre chose. Nous allons colorier l'arrière-plan du canvas en noir, cela vous donnera un avant-goût de l'API canvas. Ajoutez les lignes suivantes au bas de votre JavaScript:

+ +
ctx.fillStyle = 'rgb(0, 0, 0)';
+ctx.fillRect(0, 0, width, height);
+ +

Ici nous définissons une couleur de remplissage en utilisant la propriété du canvas {{domxref("CanvasRenderingContext2D.fillStyle", "fillStyle")}} (qui prend une valeur de couleur tout comme les propriétés CSS), puis nous dessinons un rectangle qui recouvre intégralement la surface du canvas avec la méthode {{domxref("CanvasRenderingContext2D.fillRect", "fillRect")}} (les deux premiers paramètres sont les coordonnées du coin supérieur gauche du rectangle; les deux derniers sont la largeur et la hauteur du rectangle que vous voulez dessiner — on vous avait dit que ces variables width et height allaient être utiles)!

+ +

OK, notre template est prêt et il est temps de passer à autre chose.

+ +

Les bases du canvas 2D

+ +

Pour rappel, toutes les opération de dessin sont effectuées en manipulant un objet {{domxref("CanvasRenderingContext2D")}} (dans notre cas, ctx).

+ +

De nombreuses opérations doivent recevoir des coordonnées en entrée pour savoir où dessiner quelque chose — le coin supérieur gauche du canvas est le point (0, 0), l'axe horizontal (x) va de gauche à droite, et l'axe vertical (y) va de haut en bas.

+ +

+ +

Dessiner des formes est souvent fait en utilisant la forme rectangle, ou alors en traçant une ligne le long d'un certain chemin puis en remplissant la forme. Nous allons vous montrer ci-dessous comment faire ces deux choses.

+ +

Rectangles simples

+ +

Commençons avec quelques rectangles simples.

+ +
    +
  1. +

    Tout d'abord, faites une copie de votre template (ou copiez localement le fichier 1_canvas_template.html si vous n'avez pas suivit les étapes précédentes).

    +
  2. +
  3. +

    Ensuite, ajoutez les lignes suivantes au bas de votre JavaScript:

    + +
    ctx.fillStyle = 'rgb(255, 0, 0)';
    +ctx.fillRect(50, 50, 100, 150);
    + +

    Si vous sauvegardez votre code et rafraichissez la page, vous devriez voir qu'un rectangle rouge est apparu sur le canvas. Son coin supérieur gauche est à (50,50) pixels du coin supérieur gauche du canvas (comme définit par les deux premiers paramètres), il a une largeur de 100 pixels et une hauteur de 150 pixels (comme définit par les paramètres 3 et 4).

    +
  4. +
  5. +

    Ajoutons un autre rectangle dans le mix — un vert cette fois. Ajoutez ce qui suit au bas de votre JavaScript:

    + +
    ctx.fillStyle = 'rgb(0, 255, 0)';
    +ctx.fillRect(75, 75, 100, 100);
    + +

    Sauvegardez et rafraichissez, et vous verrez un nouveau rectangle. Cela soulève un point important: les opérations graphiques comme dessiner des rectangles, lignes, et autres, sont executées dans l'ordre dans lequel elle apparaissent dans le code. Pensez-y comme peindre un mur, chaque couche de peinture s'ajoute par dessus les anciennes et peuvent même mettre cacher ce qu'il y a en dessous. Vous ne pouvez rien y faire, il faut donc réfléchir soigneusement à l'ordre dans lequel vous allez dessiner les éléments graphiques.

    +
  6. +
  7. +

    Notez que vous pouvez dessiner des éléments graphiques semi-transparents en spécifiant une couleur semi-transparente, par exemple en utilisant rgba(). La valeur a définit ce qu'on appelle le "canal alpha", ou la quantité de transparence de la couleur. Plus la valeur de a est élevée, plus la couleur est opaque. Ajoutez ce qui suit à votre code:

    + +
    ctx.fillStyle = 'rgba(255, 0, 255, 0.75)';
    +ctx.fillRect(25, 100, 175, 50);
    +
  8. +
  9. +

    Maintenant essayez de dessiner plus de rectangles par vous-même; amusez-vous!

    +
  10. +
+ +

Traits et épaisseurs de ligne

+ +

Jusqu'à présent nous avons vu comment dessiner des rectangles pleins, mais on peut aussi ne dessiner que les contours (dit strokes - traits - en graphic design). Pour définir la couleur que vous voulez pour le contour, utilisez la propriété {{domxref("CanvasRenderingContext2D.strokeStyle", "strokeStyle")}}. Pour dessiner le contour du rectangle, on appelle {{domxref("CanvasRenderingContext2D.strokeRect", "strokeRect")}}.

+ +
    +
  1. +

    Ajoutez ce qui suit au bas de votre JavaScript:

    + +
    ctx.strokeStyle = 'rgb(255, 255, 255)';
    +ctx.strokeRect(25, 25, 175, 200);
    +
  2. +
  3. +

    L'épaisseur de trait par défaut est de 1 pixel; vous pouvez ajuster la valeur de la propriété {{domxref("CanvasRenderingContext2D.lineWidth", "lineWidth")}} pour changer ça (prend un nombre spécifiant le nombre de pixels d'épaisseur de trait). Ajoutez la ligne suivante entre les deux lignes précédentes:

    + +
    ctx.lineWidth = 5;
    + +

    Vous devriez maintenant voir que votre contour blanc est devenu beaucoup plus épais!

    +
  4. +
+ +

C'est tout pour le moment. À ce stade votre exemple devrait ressembler à ça:

+ +

{{EmbedGHLiveSample("learning-area/javascript/apis/drawing-graphics/getting-started/2_canvas_rectangles.html", '100%', 250)}}

+ +
+

Note: Le code terminé est disponible sur GitHub, 2_canvas_rectangles.html.

+
+ +

Dessiner des chemins

+ +

Si vous voulez dessiner quelque chose de plus complexe qu'un rectangle, vous allez certainement devoir utiliser un path (chemin). En gros, cela implique de spécifier exactement où déplacer un stylo sur le canvas pour tracer la forme que vous voulez. L'API Canvas inclut des fonctions pour dessiner des lignes droites, des cercles, des courbes Bézier, et plus encore.

+ +

Commençons la section en faisant une nouvelle copie de notre template (1_canvas_template.html), dans lequel nous allons dessiner le nouvel exemple.

+ +

Nous allons utiliser quelques méthodes et propriétés communes dans les sections suivantes:

+ + + +

Typiquement, une manière de dessiner un trait simple ressemblerait à ça:

+ +
ctx.fillStyle = 'rgb(255, 0, 0)';
+ctx.beginPath();
+ctx.moveTo(50, 50);
+// tracer le trait
+ctx.fill();
+ +

Dessiner des lignes

+ +

Dessinons un triangle équilatéral sur le canvas.

+ +
    +
  1. +

    Tout d'abord, ajoutez la fonction d'aide suivante au bas de votre code. Elle convertit des valeurs en degrés en radians, ce qui est utile car chaque fois que vous devez fournir une valeur d'angle en JavaScript, ce sera presque toujours en radians, tandis que les humains pensent généralement en degrés.

    + +
    function degToRad(degrees) {
    +  return degrees * Math.PI / 180;
    +};
    +
  2. +
  3. +

    Ensuite, commencez votre path en ajoutant ce qui suit au bas de votre JavaScript. Ici, nous définissons une couleur pour notre triangle et déplaçons le stylo au point (50, 50) sans rien tracer. C'est à partir de là que nous allons dessiner notre triangle.

    + +
    ctx.fillStyle = 'rgb(255, 0, 0)';
    +ctx.beginPath();
    +ctx.moveTo(50, 50);
    +
  4. +
  5. +

    Maintenant ajoutez le bloc de code suivant:

    + +
    ctx.lineTo(150, 50);
    +var triHeight = 50 * Math.tan(degToRad(60));
    +ctx.lineTo(100, 50+triHeight);
    +ctx.lineTo(50, 50);
    +ctx.fill();
    + +

    Parcourons ceci dans l'ordre:

    + +
      +
    1. +

      D'abord nous ajoutons une ligne vers (150, 50) — notre path va maintenant 100 pixels vers la droite le long de l'axe horizontal (x).

      +
    2. +
    3. +

      Puis, nous calculons la hauteur de notre triangle équilatéral, en utilisant un peu de trigonométrie simple. Nous dessinons un triangle pointant vers le bas.

      + +

      Les angles d'un triangle équilatéral sont tous de 60 degrés. Pour calculer la hauteur, nous pouvons séparer le triangle en deux triangles rectangles par le milieu, qui auront alors des angles de 90, 60 et 30 degrés.

      + +

      Pour ce qui est des côtés:

      + +
        +
      • Le côté le plus long est appelé l'hypoténuse
      • +
      • Le côté relié à l'angle de 60 degrés (et qui n'est pas l'hypothénuse) est dit adjacent à cet angle — sa longueur est de 50 pixels puisque c'est la moitié de la ligne que nous avons dessiné.
      • +
      • Le côté opposé à l'angle de 60 degrés est dit opposé à cet angle — c'est la hauteur que nous voulons calculer.
      • +
      + +

       

      + +

      + +

      Une des formule trigonométrique de base stipule que la longueur du côté adjacent mutiplié par la tangente de l'angle est égale à l'opposé, soit 50 * Math.tan(degToRad(60)). Nous utilisons notre fonction degToRad() pour convertir 60 degrés en radians, puisque {{jsxref("Math.tan()")}} attend une valeur en radians.

      +
    4. +
    5. +

      Avec la hauteur calculée, nous ajoutons une nouvelle ligne vers (100, 50+triHeight). La coordonnée X est simple, elle est à mi-chemin de la ligne que nous avons tracé. La valeur de Y d'autre part doit être de 50 plus la hauteur du triangle, puisque le haut du triangle est à 50 pixels du haut du canvas.

      +
    6. +
    7. +

      L'instruction qui suit ajoute une ligne vers le point de départ du triangle.

      +
    8. +
    9. +

      Pour finir, nous appelons ctx.fill() pour finir le path et remplir la forme.

      +
    10. +
    +
  6. +
+ +

Dessiner des cercles

+ +

Maintenant, voyons comment dessiner un cercle sur le canvas. Pour ce faire, on utilise la méthode {{domxref("CanvasRenderingContext2D.arc", "arc()")}}, qui dessine tout ou une portion de cercle à un point spécifié.

+ +
    +
  1. +

    Ajoutons un arc à notre canvas en ajoutant le code qui suit:

    + +
    ctx.fillStyle = 'rgb(0, 0, 255)';
    +ctx.beginPath();
    +ctx.arc(150, 106, 50, degToRad(0), degToRad(360), false);
    +ctx.fill();
    + +

    arc() prend six paramètres.

    + +
      +
    • Les deux premiers spécifient la position du centre du cercle (X et Y respectivement).
    • +
    • Le troisième est le rayon du cercle
    • +
    • Le quatrième et le cinquième sont les angles de début et de fin pour dessiner l'arc (donc spécifier 0 et 360 nous donne un cercle fermé)
    • +
    • Et le sixième paramètre définit si le cercle doit être dessiné dans le sens des aiguilles d'une montre ou dans le sens inverse (false pour le sens horaire).
    • +
    + +
    +

    Note: 0 degrés est horizontalement vers la droite.

    +
    +
  2. +
  3. +

    Ajoutons un autre arc:

    + +
    ctx.fillStyle = 'yellow';
    +ctx.beginPath();
    +ctx.arc(200, 106, 50, degToRad(-45), degToRad(45), true);
    +ctx.lineTo(200, 106);
    +ctx.fill();
    + +

    Le motif ici est très similaire, a deux différences près:

    + +
      +
    • Nous avons mis le dernier paramètre de arc() à true, ce qui signifie que l'arc est tracé dans le sens inverse des aiguilles d'une montre.  Donc si notre arc commence à -45 degrés et fini à 45 degrés, nous dessinons un arc de 270 degrés. Si vous changez true à false et ré-exécutez le code, seule une portion de 90 degrés sera dessinée.
    • +
    • Avant d'appeler fill(), nous ajoutons une ligne vers le centre du cercle. Nous obtenons une découpe de style Pac-Man plutôt sympa. Si vous supprimiez cette ligne (essayez!) et ré-exécutiez le code, vous auriez juste un cercle dont le bout a été coupé — entre le début et la fin de l'arc. Cela illuste un autre point important du canvas: si vous essayez de remplir une forme incomplète (qui n'est pas fermée), le navigateur ajoute une ligne droite entre le début et la fin du path et le remplit.
    • +
    +
  4. +
+ +

C'est tout pour le moment; votre exemple final devrait ressembler à ceci:

+ +

{{EmbedGHLiveSample("learning-area/javascript/apis/drawing-graphics/getting-started/3_canvas_paths.html", '100%', 200)}}

+ +
+

Note: Le code finit est disponible sur GitHub, 3_canvas_paths.html.

+
+ +
+

Note: Pour en savoir plus sur les fonctions de dessin avancées, telles que les courbes Bézier, consultez notre tutoriel Dessiner des formes avec le canevas.

+
+ +

Texte

+ +

Canvas dispose également de fonctionnalités pour écrire du texte. Nous allons les explorer brièvement. Commencez par créer une nouvelle copie du template (1_canvas_template.html), dans lequel nous allons dessiner le nouvel exemple.

+ +

Le texte peut être avec deux méthodes:

+ + + +

Ces deux méthodes prennent trois paramètres: la chaîne de caractères à écrire et les coordonnées X et Y du coin supérieur gauche de la zone de texte (text box) — littéralement, la zone entourant le texte que vous écrivez.

+ +

Il existe également un certain nombre de proprétés pour contrôler le rendu du texte, comme {{domxref("CanvasRenderingContext2D.font", "font")}}, qui permer de spécifier la police d'écriture, la taille, etc — elle accepte la même syntaxe que la propriété CSS {{cssxref("font")}}.

+ +

Essayez d'ajouter le bloc suivant au bas de votre javaScript:

+ +
ctx.strokeStyle = 'white';
+ctx.lineWidth = 1;
+ctx.font = '36px arial';
+ctx.strokeText('Canvas text', 50, 50);
+
+ctx.fillStyle = 'red';
+ctx.font = '48px georgia';
+ctx.fillText('Canvas text', 50, 150);
+ +

Ici nous dessinons deux lignes de texte, une avec le contour et l'autre remplie. L'exemple final devrait ressembler à ça:

+ +

{{EmbedGHLiveSample("learning-area/javascript/apis/drawing-graphics/getting-started/4_canvas_text.html", '100%', 180)}}

+ +
+

Note: Le code final est disponible sur GitHub, 4_canvas_text.html.

+
+ +

Jouez avec et voyez ce que vous pouvez faire! Vous pouvez trouver plus d'information sur les options disponibles pour ajouter du texte sur un canvas dans Dessin de texte avec canvas.

+ +

Dessiner des images sur le canvas

+ +

Il est possible d'afficher des images externes sur le canvas. Ce peut être des images simples, des images à l'intérieur d'une vidéo, ou le contenu d'autres canvas. Pour le moment, nous allons juste nous occuper d'ajouter des images simples sur le canvas.

+ +
    +
  1. +

    Comme précédemment, créez une nouvelle copie du template (1_canvas_template.html), où nous dessinerons l'exemple. Vous allez également devoir sauvegarder une copie de notre image d'exemple — firefox.png — dans le même répertoire.

    + +

    Les images sont dessinés sur le canvas en utilisant la méthode {{domxref("CanvasRenderingContext2D.drawImage", "drawImage()")}}. Dans sa version la plus simple, elle prend trois paramètres — une référence de l'image que vous voulez afficher et les coordonnées X et Y du coin supérieur gauche de l'image sur le canvas.

    +
  2. +
  3. +

    Commençons par obtenir une ressource de l'image à inclure dans notre canvas. Ajoutez les lignes suivantes au bas de votre JavaScript:

    + +
    var image = new Image();
    +image.src = 'firefox.png';
    + +

    Ici, nous créons un nouvel objet {{domxref("HTMLImageElement")}} en utilisant le constructeur {{domxref("HTMLImageElement.Image()", "Image()")}}. (L'objet retourné est le même type que celui retourné lorsque vous récupérez une référence vers un élément {{htmlelement("img")}} existant). Nous définissons son attribut  {{htmlattrxref("src", "img")}} à notre image du logo Firefox. À ce stade, le navigateur commence à charger l'image.

    +
  4. +
  5. +

    Nous pourrions essayer maintenant d'inclure l'image en utilisant drawImage(), mais nous devons nous assurer que le fichier image ait été chargé en premier, faute de quoi le code échouera. Nous pouvons y parvenir en utilisant le gestionnaire d'événement onload, qui ne sera appelé que lorsque l'image aura fini de charger. Ajoutez le bloc suivant à la suite du précédent:

    + +
    image.onload = function() {
    +  ctx.drawImage(image, 50, 50);
    +}
    + +

    Si vous chargez votre exemple dans le navigateur maintenant, vous devriez voir l'image inclue dans le canvas.

    +
  6. +
  7. +

    Mais il y en a plus! Et si nous ne voulions afficher qu'une partie de l'image, ou la redimensionner? Nous pouvons faire ces deux choses avec une version plus complexe de drawImage(). Mettez à jour votre ligne ctx.drawImage() comme suit:

    + +
    ctx.drawImage(image, 20, 20, 185, 175, 50, 50, 185, 175);
    + +
      +
    • Le premier paramètre est la référence de l'image, comme précédemment.
    • +
    • Les paramètres 2 et 3 définissent les coordonnées à partir d'où découper l'image, relativement au coin supérieur gauche de l'image d'origine. Tout ce qui est à gauche de X (paramètre 2) ou au-dessus de Y (paramètre 3) ne sera pas dessiné.
    • +
    • Les paramètres 4 et 5 définissent la largeur et hauteur de la zone que nous voulons découper, à partir du coin supérieur gauche de l'image découpée.
    • +
    • Les paramètres 6 et 7 définissent les coordonnées où vous souhaitez placer l'image sur le canvas, relativement au coin supérieur gauche du canvas.
    • +
    • Les paramètres 8 et 9 définissent la largeur et la hauteur affichée de l'image découpée. En l'occurence, nous avons spécifié les mêmes dimensions que la découpe, mais vous pouvez la redimensionner (et la déformer) en spécifiant des valeurs différentes.
    • +
    +
  8. +
+ +

L'exemple final devrait ressembler à ça:

+ +

{{EmbedGHLiveSample("learning-area/javascript/apis/drawing-graphics/getting-started/5_canvas_images.html", '100%', 260)}}

+ +
+

Note: Le code final est disponible sur GitHub, 5_canvas_images.html.

+
+ +

Boucles et animations

+ +

Jusqu'ici, nous avons couvert quelques utilisations très basiques du canvas 2D, mais vous ne ressentirez la pleine puissance du canvas que si vous le mettez à jour ou l'animez d'une manière ou d'une autre. Après tout, le canvas fournit des images scriptables! Si vous n'avez pas l'intention de changer quelque chose, alors autant utiiliser des images statiques et vous épargner du travail.

+ +

Créer une boucle

+ +

Jouer avec des boucles est plutôt amusant — vous pouvez exécuter des commandes de canvas à l'intérieur d'une boucle for (ou tout autre type de boucle) comme n'importe quel autre code JavaScript.

+ +

Construisons un exemple simple.

+ +
    +
  1. +

    Créez une nouvelle copie du template (1_canvas_template.html) et ouvrez-le dans votre éditeur de texte.

    +
  2. +
  3. +

    Ajoutez la ligne qui suit au bas de votre JavaScript. Elle contient une nouvelle méthode, {{domxref("CanvasRenderingContext2D.translate", "translate()")}}, qui déplace le point d'origine du canvas:

    + +
    ctx.translate(width/2, height/2);
    + +

    Cela a pour effet de déplacer l'origine des coordonnées (0, 0) au centre du canvas, plutôt que d'être dans le coin supérieur gauche. C'est très utile dans de nombreuses situations, comme celle-ci, où nous voulons que notre dessin soit dessiné par rapport au centre du canvas.

    +
  4. +
  5. +

    Maintenant ajoutez le code suivant au bas du Javacript:

    + +
    function degToRad(degrees) {
    +  return degrees * Math.PI / 180;
    +};
    +
    +function rand(min, max) {
    +  return Math.floor(Math.random() * (max-min+1)) + (min);
    +}
    +
    +var length = 250;
    +var moveOffset = 20;
    +
    +for(var i = 0; i < length; i++) {
    +
    +}
    + +

    Ici, nous implémentons

    + +
      +
    • la même fonction degToRad() que nous avons vu dans l'exemple du triangle auparavant,
    • +
    • une fonction rand(), qui retoune un nombre aléatoire entre une limite inférieure et une limite supérieure,
    • +
    • les variables length et moveOffset (que nous verrons plus loin),
    • +
    • et une boucle for vide.
    • +
    +
  6. +
  7. +

    L'idée est que nous allons dessiner quelque chose sur le canvas à l'intérieur de la boucle for, et itérer dessus pour créer quelque chose d'intéressant. Ajoutez le code suivant à l'intérieur de la boucle for:

    + +
    ctx.fillStyle = 'rgba(' + (255-length) + ', 0, ' + (255-length) + ', 0.9)';
    +ctx.beginPath();
    +ctx.moveTo(moveOffset, moveOffset);
    +ctx.lineTo(moveOffset+length, moveOffset);
    +var triHeight = length/2 * Math.tan(degToRad(60));
    +ctx.lineTo(moveOffset+(length/2), moveOffset+triHeight);
    +ctx.lineTo(moveOffset, moveOffset);
    +ctx.fill();
    +
    +length--;
    +moveOffset += 0.7;
    +ctx.rotate(degToRad(5));
    + +

    Ainsi à chaque itération, on:

    + +
      +
    1. Définit fillStyle comme étant une nuance de violet légèrement transparente, et qui change à chaque fois en fonction de la valeur de length. Comme vous le verrez plus tard, sa valeur diminue à chaque itération, ce qui a pour effet de rendre la couleur toujours plus claire.
    2. +
    3. Ouvre un path.
    4. +
    5. Déplace le stylo aux coordonnées de (moveOffset, moveOffset); Cette variable définit jusqu'où nous voulons nous déplacer à chaque fois que nous dessinons.
    6. +
    7. Dessine une ligne aux coordonées de (moveOffset+length, moveOffset). Cela dessine une ligne de longueur length parallèle à l'axe X.
    8. +
    9. Calcule la hauteur du triangle, comme vu auparavant.
    10. +
    11. Dessine une ligne vers le coin du bas du triangle.
    12. +
    13. Dessine une ligne vers le début du triangle.
    14. +
    15. Appelle fill() pour remplir le triangle.
    16. +
    17. Met à jour les variables qui indiquent comment dessiner le triangle, afin qu'elles soient prêtes pour la prochaine itération: +
        +
      • Diminue la valeur de length de 1, de sorte que les triangles deviennent de plus en plus petits;
      • +
      • Augmente un peu moveOffset pour que chaque triangle successif soit légèrement plus éloigné;
      • +
      • et utilise une nouvelle fonction, {{domxref("CanvasRenderingContext2D.rotate", "rotate()")}}, qui permet de faire pivoter entièrement le canvas! Nous le faisons pivoter de 5 degrés avant de dessiner le triangle suivant.
      • +
      +
    18. +
    +
  8. +
+ +

C'est tout! L'exemple final devrait ressemble à ça:

+ +

{{EmbedGHLiveSample("learning-area/javascript/apis/drawing-graphics/loops_animation/6_canvas_for_loop.html", '100%', 550)}}

+ +

À ce stade, nous vous encourageons à jouer avec l'exemple et de vous l'approprier! Par exemple:

+ + + +
+

Note: Le code terminé est disponible sur GitHub, 6_canvas_for_loop.html.

+
+ +

Animations

+ +

L'exemple de boucle que nous avons construit ci-dessus était amusant, mais en vrai vous avez besoin d'une boucle qui continue constamment d'itérer pour toute application sérieuse de canvas (telles que les jeux et les visualisations en temps réel). Si vous pensez à votre canvas comme étant en quelque sorte un film, vous allez vouloir que l'affichage se mette à jour à chaque image pour afficher la mise à jour avec un taux de rafraichissement idéal de 60 images par seconde, afin que le mouvement soit lisse et agréable pour l'oeil humain.

+ +

Il y a quelques fonctions JavaScript qui vous permettrons d'exécuter des fonctions de manière répétée, plusieurs fois par seconde, la meilleure étant ici {{domxref("window.requestAnimationFrame()")}}. Elle prend un paramètre — la fonction que vous voulez exécuter pour chaque image. Dès que le navigateur est prêt à mettre à jour l'écran, votre fonction sera appelée. Si cette fonction dessine la nouvelle mise à jour, puis appelle de nouveau requestAnimationFrame() juste avant la fin de la fonction, la boucle d'animation continuera de s'exécuter de manière fluide. La boucle s'arrête lorsque vous vous arrêtez d'appeler requestAnimationFrame() ou si vous appelez {{domxref("window.cancelAnimationFrame()")}} après avoir appelé requestAnimationFrame() mais avant que votre fonction n'ait été exécutée.

+ +
+

Note: C'est une bonne pratique d'appeler cancelAnimationFrame() à partir de votre code principal lorsque vous avez terminé d'utiliser l'animation, pour vous assurer qu'aucune mise à jour n'attend d'être exécutée.

+
+ +

Le navigateur s'occupe des détails complexes tels qu'exécuter l'animation à une vitesse constante, et ne pas gaspiller de ressources en animant des choses qui ne sont pas visibles.

+ +

Pour voir comment cela fonctionne, regardons rapidement notre exemple des balles qui rebondissent (le voir en direct, et voir le code source). Le code de la boucle qui garde le tout en mouvement ressemble à ceci:

+ +
function loop() {
+  ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
+  ctx.fillRect(0, 0, width, height);
+
+  while(balls.length < 25) {
+    var ball = new Ball();
+    balls.push(ball);
+  }
+
+  for(i = 0; i < balls.length; i++) {
+    balls[i].draw();
+    balls[i].update();
+    balls[i].collisionDetect();
+  }
+
+  requestAnimationFrame(loop);
+}
+
+loop();
+ +

Nous lançons la fonction loop() une fois pour commencer le cycle et dessiner la première image de l'animation. La fonction loop() s'occupe ensuite d'appeler requestAnimationFrame(loop) pour afficher la prochaine image de l'animation, et ce continuellement.

+ +

Notez que sur chaque image, nous effaçons complètement le canvas et redessinons tout. Nous créons de nouvelles balles pour chaque image — au maximum 25 — puis, pour chaque balle, la dessinons, mettons à jour sa position, et vérifions si elle est en collision avec une autre balle. Une fois que vous avez dessiné quelque chose sur un canvas, il n'y a aucun moyen pour manipuler cet élément graphique individuellement comme vous pouvez le faire avec les élément DOM. Vous ne pouvez pas déplacer les balles sur le canvas parce qu'une fois dessinée, une balle n'est plus une balle mais juste des pixels sur un canvas. Au lieu de ça, vous devez effacer et redessiner, soit en effaçant et redessinant absolutement tout le canvas, soit en ayant du code qui sait exactement quelles parties doivent être effacées, et qui efface et redessine uniquement la zone minimale nécessaire.

+ +

Optimiser l'animation graphique est une spécialité entière de programmation, avec beaucoup de techniques ingénieuses disponibles. Mais celles-ci sont au-delà de ce dont nous avons besoin pour notre exemple!

+ +

En général, le processus pour animer un canvas implique les étapes suivantes:

+ +
    +
  1. Effacer le contenu du cavas (par exemple avec {{domxref("CanvasRenderingContext2D.fillRect", "fillRect()")}} ou {{domxref("CanvasRenderingContext2D.clearRect", "clearRect()")}}).
  2. +
  3. Sauvegarder l'état (si nécessaire) en utilisant {{domxref("CanvasRenderingContext2D.save", "save()")}} — c'est nécessaire lorsque vous voulez enregistrer les paramètres que vous mis à jour sur le canvas avant de continuer, ce qui est utile pour des applications plus avancées.
  4. +
  5. Dessiner les éléments graphiques que vous animez.
  6. +
  7. Restaurer les paramètres sauvegardés à l'étape 2 en utilisant {{domxref("CanvasRenderingContext2D.restore", "restore()")}}
  8. +
  9. Appeler requestAnimationFrame() pour planifier le dessin de l'image suivante de l'animation.
  10. +
+ +
+

Note: Nous ne couvrirons pas save() et restore() ici, mais elles sont bien expliquées dans notre tutoriel Transformations (et ceux qui le suivent).

+
+ +

Une animation simple de personnage

+ +

Créons maintenant notre propre animation simple — nous allons faire parcourir l'écran à un personnage d'un certain jeu vidéo rétro plutôt génial.

+ +
    +
  1. +

    Faites une nouvelle copie du template (1_canvas_template.html) et ouvrez-le dans votre éditeur de texte. Sauvegardez une copie de walk-right.png dans le même répertoire.

    +
  2. +
  3. +

    Au bas du JavaScript, ajoutez la ligne suivante pour placer une fois de plus l'origine des coordonnées au milieu du canvas:

    + +
    ctx.translate(width/2, height/2);
    +
  4. +
  5. +

    Nous allons maintenant créer un objet {{domxref("HTMLImageElement")}}, définir son attribut {{htmlattrxref("src", "img")}} à l'image que nous voulons charger, et ajouter le gestionnaire d'événement onload pour appeler la fonction draw() quand l'image sera chargée:

    + +
    var image = new Image();
    +image.src = 'walk-right.png';
    +image.onload = draw;
    +
  6. +
  7. +

    Ajoutons quelques variables pour garder une trace de la position du sprite à dessiner à l'écran, et le numéro du sprite que nous voulons afficher.

    + +
    var sprite = 0;
    +var posX = 0;
    + +

    L'image de sprites (que nous avons respectueusement emprunté à Mike Thomas dans son article Create a sprite sheet walk cycle using using CSS animation — créer un cycle de marche avec une feuille de sprites en utilisant les animations CSS) ressemble à ça:

    + +

    + +

    Elle contient six sprites qui constituent une séquence de marche — chacun a 102 pixels de large et 148 pixels de hauteur. Pour afficher chaque sprite proprement, nous allons devoir utiliser drawImage() pour découper un seul sprite de l'image et n'afficher que cette partie, comme nous l'avons fait précédemment avec le logo Firefox. La coordonnée X de la découpe devra être un multiple de 102 et la coordonnée Y sera toujours 0. La taille de la découpe sera toujours de 102 pixels par 148.

    +
  8. +
  9. +

    Insérons maintenant une fonction draw() vide au bas du code, prête à être remplie de code:

    + +
    function draw() {
    +
    +};
    +
  10. +
  11. +

    Le reste du code dans cette section va dans draw(). Tout d'abord, ajoutez la ligne suivante, qui efface le canvas pour préparer le dessin de chaque image. Notez que nous devons spécifier le coin supérieur gauche du rectangle comme étant -(width/2), -(height/2) puisque nous avons définit l'origine du canvas à width/2, height/2 plus tôt.

    + +
    ctx.fillRect(-(width/2), -(height/2), width, height);
    +
  12. +
  13. +

    Ensuite, nous allons dessinons notre image en utilisant drawImage() — la version à 9 paramètres. Ajoutez ce qui suit:

    + +
    ctx.drawImage(image, (sprite*102), 0, 102, 148, 0+posX, -74, 102, 148);
    + +

    Comme vous pouvez le voir:

    + +
      +
    • Nous spécifions image comme étant l'image à inclure.
    • +
    • Les paramètres 2 et 3 spécifient le coin supérieur gauche de la portion de l'image à découper: la valeur X vaut sprite multiplié par 102 (où sprite est le numéro du sprite, entre 0 et 5) et la valeur Y vaut toujours 0.
    • +
    • Les paramètres 4 et 5 spécifient la taille de la découpe — 102 pixels par 148.
    • +
    • Les paramètres 6 et 7 spécifient le coin supérieur gauche de la découpe sur le canvas — la position de X est 0+posX, ce qui signifie que nous pouvons modifier la position du dessin en modifiant la valeur de posX.
    • +
    • Les paramètres 8 et 9 spécifient la taille de l'image sur le canvas. Nous voulons garder sa taille d'origine, on définit donc 102 pour largeur et 148 pour hauteur.
    • +
    +
  14. +
  15. +

    Maintenant, nous allons changer la valeur de sprite après chaque dessin — après certains d'entre eux du moins. Ajoutez le bloc de code suivant au bas de la fonction draw():

    + +
      if (posX % 13 === 0) {
    +    if (sprite === 5) {
    +      sprite = 0;
    +    } else {
    +      sprite++;
    +    }
    +  }
    + +

    Nous enveloppons le bloc entier de if (posX % 13 === 0) { ... }. On utilise l'opérateur modulo (%) (aussi connu sous le nom d'opérateur reste) pour vérifier si la valeur de posX peut être exactement divisée par 13, sans reste. Si c'est le cas, on passe au sprite suivant en incrémentant sprite (en retournant à 0 après le sprite #5). Cela implique que nous ne mettons à jour le sprite que toutes les 13èmes images, ou à peu près 5 images par seconde (requestAnimationFrame() appelle jusqu'à 60 images par secondes si possible). Nous ralentissons délibéremment le cadence des images parce que nous n'avons que six sprites avec lesquels travailler, et si on en affiche un à chaque 60ième de seconde, notre personnage va bouger beaucoup trop vite!

    + +

    À l'intérieur du bloc, on utilise une instruction if ... else pour vérifier si la valeur de sprite vaut 5 (le dernier sprite, puisque les numéro de sprite vont de 0 à 5). Si nous sommes en train d'afficher le dernier sprite, alors on réinitialilse sprite à 0; sinon on l'incrémente de 1.

    +
  16. +
  17. +

    Ensuite, nous devons déterminer comment modifier la valeur de posX sur chaque image — ajoutez le bloc de code à la suite:

    + +
      if(posX > width/2) {
    +    newStartPos = -((width/2) + 102);
    +    posX = Math.ceil(newStartPos / 13) * 13;
    +    console.log(posX);
    +  } else {
    +    posX += 2;
    +  }
    + +

    Nous utilisons une autre instruction if ... else pour voir si la valeur de posX est plus grande que width/2, ce qui signifie que notre personnage est sortit du bord droit de l'écran. Si c'est le cas, on calcule la position qui met le personnage à gauche du bord gauche de l'écran, et on définit posX au multiple de 13 le plus proche de ce nombre. Il faut obligatoirement un multiple de 13 pour que le bloc de code précédent puisse toujours fonctionner!

    + +

    Si notre personnage n'a pas atteint le bord de l'écran, on incrémente posX de 2. Cela le fera bouger un peu vers la droite la prochaine fois qu'on le dessinera.

    +
  18. +
  19. +

    Finalement, nous devons boucler sur l'animation en appelannt {{domxref("window.requestAnimationFrame", "requestAnimationFrame()")}} en bas de la fonction draw():

    + +
    window.requestAnimationFrame(draw);
    +
  20. +
+ +

Et voilà! L'exemple final devrait ressembler à ça:

+ +

{{EmbedGHLiveSample("learning-area/javascript/apis/drawing-graphics/loops_animation/7_canvas_walking_animation.html", '100%', 260)}}

+ +
+

Note: Le code final est disponible sur GitHub, 7_canvas_walking_animation.html.

+
+ +

Une application simple de dessin

+ +

Comme exemple final d'animation, nous aimerions vous montrer une application très simple de dessin, pour illustrer comment la boucle d'animation peut être combinée avec les entrées de l'utilisateur (comme le mouvement de la souris en l'occurence). Nous n'allons pas expliquer la procédure pas à pas pour construire cette application, nous allons juste explorer les parties les plus intéressantes du code.

+ +

L'exemple peut être trouvé sur GitHub, 8_canvas_drawing_app.html, et vous pouvez jouer avec en direct ci-dessous:

+ +

{{EmbedGHLiveSample("learning-area/javascript/apis/drawing-graphics/loops_animation/8_canvas_drawing_app.html", '100%', 600)}}

+ +

Regardons les parties les plus intéressantes. Tout d'abord, nous gardons une trace des coordonnées X et Y de la souris et si elle est pressée ou non grâce à trois variables: curX, curY, et pressed. Quand la souris bouge, nous déclenchons une fonction via le gestionnaire d'événement onmousemove, lequel capture les valeurs X et Y actuelles. Nous utilisons également les gestionnaires d'événement onmousedown et onmouseup pour changer la valeur de pressed à true quand le bouton de la souris est pressé, et de nouveau à false quand il est relaché.

+ +
var curX;
+var curY;
+var pressed = false;
+
+document.onmousemove = function(e) {
+  curX = (window.Event) ? e.pageX : e.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
+  curY = (window.Event) ? e.pageY : e.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
+}
+
+canvas.onmousedown = function() {
+  pressed = true;
+};
+
+canvas.onmouseup = function() {
+  pressed = false;
+}
+ +

Quand le bouton "Clear canvas" (effacer le canvas) est cliqué, nous exécutons une simple fonction qui efface entièrement le canvas grâce à un rectangle noir, de la même manière que nous avons vu précédemment:

+ +
clearBtn.onclick = function() {
+  ctx.fillStyle = 'rgb(0, 0, 0)';
+  ctx.fillRect(0, 0, width, height);
+}
+ +

La boucle du dessin est relativement simple cette fois-ci — si pressed est à true, nous dessinons un cercle rempli avec la couleur du color picker (sélecteur de couleur), et d'un rayon égal à la valeur définit dans le champs de sélection dans un intervalle.

+ +
function draw() {
+  if(pressed) {
+    ctx.fillStyle = colorPicker.value;
+    ctx.beginPath();
+    ctx.arc(curX, curY-85, sizePicker.value, degToRad(0), degToRad(360), false);
+    ctx.fill();
+  }
+
+  requestAnimationFrame(draw);
+}
+
+draw();
+ +
+

Note: Les types d'{{htmlelement("input")}} range et color sont relativement bien pris en charge parmi les différents navigateurs, à l'exception des versions d'Internet Explorer inférieures à 10; et Safari ne prend pas en charge le type color. Si votre navigateur ne prend pas en charge ces types, il affichera simplement un champ texte et vous n'aurez qu'à entrer des valeurs de couleur et numéro valides vous-mêmes.

+
+ +

WebGL

+ +

Il est maintenant temps de laisser la 2D derrière, et de jeter un coup d'oeil au canvas 3D. Le contenu 3D d'un canvas est spécifié en utilisant l'API WebGL, qui est une API complètement séparée de l'API des canvas 2D, même si ls deux sont affichés sur des éléments {{htmlelement("canvas")}}.

+ +

WebGL est basé sur le langage de programmation graphique OpenGL, et permet de communiquer directement avec le GPU de l'ordinateur. En soi, l'écriture WebGL est plus proche des langages de bas niveau tel que C++ que du JavaScript usuel; c'est assez complexe mais incroyablement puissant.

+ +

Utiliser une bibliothèque

+ +

De par sa complexité, la plupart des gens écrivent du code de graphique 3D en utilisant une bibliothèque JavaScript tierce telle que Three.js, PlayCanvas ou Babylon.js. La plupart d'entre elles fonctionnent d'une manière similaire, offrant des fonctionnalités pour créer des formes primitives et personnalisées, positionner des caméras et des éclairages, recouvrir des surfaces avec des textures et plus encore. Elles se chargent de WebGL pour vous, vous permettant de travailler à un niveau plus haut.

+ +

Oui, en utiliser une signifie apprendre une autre nouvelle API (une API tierce en l'occurence), mais elles sont beaucoup plus simples que de coder du WebGL brut.

+ +

Recréer notre cube

+ +

Regardons un exemple simple pour créer quelque chose avec une bibliothèque WebGL. Nous allons choisir Three.js, puisque c'est l'une des plus populaires. Dans ce tutoriel, nous allons créer le cube 3D qui tourne que nous avons plus tôt.

+ +
    +
  1. +

    Pour commencer, créez une copie locale de index.html dans un nouveau répertoire, et sauvegardez metal003.png dans ce même répertoire. C'est l'image que nous allons utiliser comme texture de surface du cube plus tard.

    +
  2. +
  3. +

    Ensuite, créez un nouveau fichier main.js, toujours dans le même répertoire.

    +
  4. +
  5. +

    Si vous ouvrez index.html dans votre éditeur de texte, vous verrez qu'il y a deux éléments {{htmlelement("script")}} — le premier ajoute three.min.js à la page, et le second ajoute notre fichier main.js à la page. Vous devez télécharger la bibliothèque three.min.js et la sauvegarder dans le même répertoire que précédemment.

    +
  6. +
  7. +

    Maintenant que nous avons inclus three.js dans notre page, nous pouvons commencer à écrire du code JavaScript qui l'utilise dans main.js. Commençons par créer une nouvelle scène — ajoutez ce qui suit dans le fichier main.js:

    + +
    var scene = new THREE.Scene();
    + +

    Le constructeur Scene() crée une nouvelle scène, qui représente l'ensemble du monde 3D que nous essayons d'afficher.

    +
  8. +
  9. +

    Ensuite, nous avons besoin d'une caméra pour voir la scène. En terme d'imagerie 3D, la caméra représente la position du spectateur dans le monde. Pour ajouter une caméra, ajoutez les lignes suivantes à la suite:

    + +
    var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    +camera.position.z = 5;
    +
    + +

    Le constructeur PerspectiveCamera() prend quatre arguments:

    + +
      +
    • Le champ de vision: Quelle est la largeur de la zone devant la caméra qui doit être visible à l'écran, en degrés.
    • +
    • Le rapport d'aspect (aspect ratio): Habituellement, c'est le rapport entre la largeur de la scène divisé par la hauteur de la scène. Utiliser une autre valeur va déformer la scène (ce qui pourrait être ce que vous voulez, mais ce n'est généralement pas le cas).
    • +
    • Le plan proche (near plane): Jusqu'où les objets peuvent être proches de la caméra avant que nous arrêtions de les afficher à l'écran. Pensez-y comme quand vous approchez votre doigt de plus en plus près de l'espace entre vos yeux, vous finissez par ne plus le voir.
    • +
    • Le plan éloigné (far plane): Jusqu'à quelle distance de la caméra doit-on afficher les objets.
    • +
    + +

    Nous définissons également la position de la caméra à 5 unités de distance de l'axe Z, qui, comme en CSS, est hors de l'écran vers vous, le spectateur.

    +
  10. +
  11. +

    Le troisième ingrédient essentiel est un moteur de rendu. C'est un objet qui restitue une scène donnée, vu à travers une caméra donnée. Nous allons en créer dès à présent en utilisant le constructeur WebGLRenderer() — mais nous ne l'utiliserons que plus tard. Ajoutez les lignes suivantes à la suite de votre JavaScript:

    + +
    var renderer = new THREE.WebGLRenderer();
    +renderer.setSize(window.innerWidth, window.innerHeight);
    +document.body.appendChild(renderer.domElement);
    + +

    La première ligne crée un nouveau moteur de rendu, la deuxième ligne définit la taille à laquelle le moteur de rendu va dessiner la vue de la caméra, et la troisième ligne ajoute l'élément {{htmlelement("canvas")}} crée par le moteur de rendu au {{htmlelement("body")}} du document. Désormais, tout ce que dessine le moteur de rendu sera affiché dans notre fenêtre.

    +
  12. +
  13. +

    Ensuite, nous voulons créer le cube que nous afficherons sur le canvas. Ajoutez le morceau de code suivant au bas de votre JavaScript:

    + +
    var cube;
    +
    +var loader = new THREE.TextureLoader();
    +
    +loader.load( 'metal003.png', function (texture) {
    +  texture.wrapS = THREE.RepeatWrapping;
    +  texture.wrapT = THREE.RepeatWrapping;
    +  texture.repeat.set(2, 2);
    +
    +  var geometry = new THREE.BoxGeometry(2.4, 2.4, 2.4);
    +  var material = new THREE.MeshLambertMaterial( { map: texture, shading: THREE.FlatShading } );
    +  cube = new THREE.Mesh(geometry, material);
    +  scene.add(cube);
    +
    +  draw();
    +});
    + +

    Il y a un peu plus à encaisser ici, alors allons-ici par étapes:

    + +
      +
    • Nous créons d'abord une variable globale cube pour pouvoir accéder à notre cube de n'importe où dans notre code.
    • +
    • Ensuite, nous créons un nouvel objet TextureLoader, et appellons load() dessus. La fonction load() prend deux paramètres dans notre exemple (bien qu'elle puisse en prendre plus): la texture que nous voulons charger (notre PNG), et la fonction qui sera exécutée lorsque la texture sera chargée.
    • +
    • À l'intérieur de cette fonction, nous utilisons les propriétés de l'objet texture pour spécifier que nous voulons une répétition 2 x 2 de l'image sur tous les côtés du cube.
    • +
    • Ensuite, nous créons un nouvel objet BoxGeometry et MeshLambertMaterial, que nous passons à un Mesh pour créer notre cube. Typiquement, un objet requiert une géométrie (quelle est sa forme) et un matériau (à quoi ressemble sa surface).
    • +
    • Pour finir, nous ajoutons notre cube à la scène, puis appellons la fonction draw() pour commencer l'animation.
    • +
    +
  14. +
  15. +

    Avant de définir la fonction draw(), nous allons ajouter quelques lumières à la scène, pour égayer un peu les choses; ajoutez le bloc suivant à la suite de votre code:

    + +
    var light = new THREE.AmbientLight('rgb(255, 255, 255)'); // soft white light
    +scene.add(light);
    +
    +var spotLight = new THREE.SpotLight('rgb(255, 255, 255)');
    +spotLight.position.set( 100, 1000, 1000 );
    +spotLight.castShadow = true;
    +scene.add(spotLight);
    + +

    Un objet AmbientLight est une lumière douce qui illumine la scène entière, un peu comme le soleil comme vous êtes dehors. Un objet SpotLight, d'autre part, est un faisceau de lumière, plutôt comme une lampe de poche/torche (ou un spotlight - projecteur - en fait).

    +
  16. +
  17. +

    Pour finir, ajoutons notre fonction draw() au bas du code:

    + +
    function draw() {
    +  cube.rotation.x += 0.01;
    +  cube.rotation.y += 0.01;
    +  renderer.render(scene, camera);
    +
    +  requestAnimationFrame(draw);
    +}
    + +

    C'est assez intuittif: sur chaque image, on fait légèrement tourner notre cube sur ses axes X et Y, affichons la scène telle qu'elle vue par notre caméra, puis appellons requestAnimationFrame() pour planifier le dessin de notre prochaine image.

    +
  18. +
+ +

Jetons un coup d'oeil rapide au produit fini:

+ +

{{EmbedGHLiveSample("learning-area/javascript/apis/drawing-graphics/threejs-cube/index.html", '100%', 500)}}

+ +

Vous pouvez trouver le code terminé sur GitHub.

+ +
+

Note: Dans notre repo GitHub vous pouvez également trouver d'autres exemples 3D intéressants — Three.js Video Cube (le voir en direct). On utilise {{domxref("MediaDevices.getUserMedia", "getUserMedia()")}} pour prendre un flux vidéo à partir d'une webcam de l'ordinateur et le projetons sur le côté du cube comme texture!

+
+ +

Sommaire

+ +

À ce stade, vous devriez avoir une idée utile des bases de la programmation graphique en utilisant Canvas et WebGL et de ce que vous pouvez faire avec ces APIs. Vous pouvez trouver des endroits où aller pour trouver plus d'informations dans la section suivante. Amusez-vous!

+ +

Voir aussi

+ +

Nous n'avons couverts dans cet article que les vraies bases du canvas — il y a tellement plus à apprendre! Les articles suivants vous mèneront plus loin.

+ + + +

Exemples

+ + + +

{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Third_party_APIs", "Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs", "Learn/JavaScript/Client-side_web_APIs")}}

+ +

 

+ +

Dans ce module

+ + diff --git a/files/fr/learn/javascript/client-side_web_apis/fetching_data/index.html b/files/fr/learn/javascript/client-side_web_apis/fetching_data/index.html new file mode 100644 index 0000000000..2acc2ed9b3 --- /dev/null +++ b/files/fr/learn/javascript/client-side_web_apis/fetching_data/index.html @@ -0,0 +1,397 @@ +--- +title: Récupérer des données du serveur +slug: Apprendre/JavaScript/Client-side_web_APIs/Fetching_data +tags: + - API + - Apprendre + - Article + - Codage + - Débutant + - Fetch + - JavaScript + - XHR + - data +translation_of: Learn/JavaScript/Client-side_web_APIs/Fetching_data +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Manipulating_documents", "Learn/JavaScript/Client-side_web_APIs/Third_party_APIs", "Learn/JavaScript/Client-side_web_APIs")}}
+ +

Une autre tâche courante dans les sites et applications web modernes est de récupérer des données à partir du serveur pour mettre à jour des sections de la page web sans la recharger entièrement. Ce qui pourrait paraître comme un petit détail a, en vérité, eu un impact énorme sur les performances et le comportement des sites. Dans cet article, nous allons expliquer le concept et les technologies qui rendent cela possible, tels que XMLHttpRequest et l'API Fetch.

+ + + + + + + + + + + + +
Prérequis :Notions de base de JavaScript (voir premiers pas, les briques JavaScript, les objets JavaScript), les notions de bases des APIs côté client
Objectif :Apprendre à récupérer des données du serveur web et les utiliser pour mettre à jour le contenu de la page.
+ +

Quel est le problème?

+ +

À la base, le chargement d'une page web est simple — vous envoyez une requête à un serveur et, tant qu'il n'y a pas eu de problème, les ressources de la page web sont téléchargées et affichées sur votre ordinateur.

+ +

A basic representation of a web site architecture

+ +

Le problème avec ce modèle c'est qu'à chaque fois que vous voulez mettre à jour une partie de la page, par exemple pour afficher la page suivante d'une liste de produits, vous devez recharger toute la page. Ce surcoût est tout à fait inutile et résulte en une mauvaise expérience utilisateur, particulièrement pour les pages qui sont lourdes, complexes et du coup longues à charger.

+ +

L'arrivée d'Ajax

+ +

Pour traiter ce problème, des technologies ont été élaborées qui permettent de récupérer à la demande de petites portions de données (comme du HTML, {{glossary("XML")}}, JSON, ou texte brut) et de les afficher dans la page web.

+ +

Nous avons pour cela l'API {{domxref("XMLHttpRequest")}} à notre disposition ou — plus récemment — l'API Fetch. Elles permettent de réaliser des requêtes HTTP pour récupérer des ressources spécifiques disponibles sur un serveur et de formater les données retournées selon les besoins avant l'affichage dans la page.

+ +
+

Note : Dans les premiers temps, cette technique était appelée "Asynchronous JavaScript and XML" (JavaScript asychrone et XML), dit AJAX, parce qu'elle utilisait {{domxref("XMLHttpRequest")}} pour requêter des données XML. De nos jours, c'est rarement le cas; la plupart du temps, on utilise XMLHttpRequest ou Fetch pour requêter des données JSON. Quoi qu'il en soit, le procédé reste le même et le terme "Ajax" est resté pour décrire cette technique.

+
+ +

A simple modern architecture for web sites

+ +

Le modèle Ajax implique une API web comme proxy pour requêter les données plus intelligemment que simplement rafraîchir la page à chaque fois. Voyons plutôt l'impact que cela a :

+ +
    +
  1. Allez sur un site riche en information de votre choix, comme Amazon, YouTube, CNN...
  2. +
  3. Cherchez quelque chose dans la barre de recherche, comme un nouveau produit. Le contenu principal va changer, mais la plupart de ce qui l'entoure reste statique, comme l'entête, le pied de page, le menu de navigation, etc.
  4. +
+ +

C'est une bonne chose puisque :

+ + + +

Notez que pour accélerer les choses encore davantage, certains sites stockent les ressources et données chez le client lors de sa première visite, si bien que les visites suivantes, les fichiers locaux sont utilisés et non re-téléchargés du serveur. Le contenu n'est rechargé que lorsqu'il a été mis à jour sur le serveur.

+ +

A basic web app data flow architecture

+ +

Une requête Ajax basique

+ +

Voyons maintenant comment ces requêtes sont gérées, en utilisant soit {{domxref("XMLHttpRequest")}} soit Fetch. Pour ces exemples, nous allons requêter les données de différents fichiers texte et les utiliserons pour remplir une zone de contenu.

+ +

Ces fichiers agiront comme une fausse base de données ; dans une vraie application, il est plus probable que vous utiliseriez un langage côté serveur comme PHP, Python, ou Node pour récupérer les données à partir d'une véritable base de données. En revanche, nous voulons ici garder les choses simples ; nous allons donc nous concentrer sur le côté client.

+ +

XMLHttpRequest

+ +

XMLHttpRequest (qui est fréquemment abrégé XHR) est une technologie assez vieille maintenant — elle a été inventée par Microsoft dans les années 90 et a été standardisée dans les autres navigateurs il y a longtemps.

+ +
    +
  1. +

    Pour commencer cet exemple, faites une copie locale de ajax-start.html et des quatre fichiers texte — verse1.txt, verse2.txt, verse3.txt, et verse4.txt — dans un nouveau répertoire sur votre ordinateur. Dans cet exemple, nous allons charger le verset d'un poème (que vous pourriez bien reconnaître), quand il est sélectionné dans le menu déroulant, en utilisant XHR.

    +
  2. +
  3. +

    À l'intérieur de l'élément {{htmlelement("script")}}, ajoutez le code qui suit. Il stocke une référence aux éléments {{htmlelement("select")}} et {{htmlelement("pre")}} dans des variables et définit un gestionnaire d'événement {{domxref("GlobalEventHandlers.onchange","onchange")}}, pour que, quand la valeur du menu déroulant est changée, la valeur sélectionnée soit passée comme paramètre à la fonction  updateDisplay().

    + +
    var verseChoose = document.querySelector('select');
    +var poemDisplay = document.querySelector('pre');
    +
    +verseChoose.onchange = function() {
    +  var verse = verseChoose.value;
    +  updateDisplay(verse);
    +};
    +
  4. +
  5. +

    Définissons maintenant la fonction updateDisplay(). Tout d'abord, mettez ce qui suit au bas de votre JavaScript — c'est la structure vide de la fonction :

    + +
    function updateDisplay(verse) {
    +
    +};
    +
  6. +
  7. +

    Nous allons commencer notre fonction en construisant une URL relative qui pointe vers le fichier texte que nous voulons charger, nous en aurons besoin plus tard. La valeur de l'élément {{htmlelement("select")}} à tout instant est la même que l'élément {{htmlelement("option")}} sélectionné (c'est à dire le texte de l'élément sélectionné, ou son attribut value s'il est spécifié) — par exemple "Verse 1". Le fichier correspondant est "verse1.txt" et il est situé dans le même répertoire que le fichier HTML, le nom du fichier seul suffira donc.

    + +

    Les serveurs web sont généralement sensibles à la casse, le nom de fichier n'a pas d'espace et a une extension de fichier. Pour convertir "Verse 1" en "verse1.txt" nous allons convertir le "V" en minuscles avec {{jsxref("String.toLowerCase", "toLowerCase()")}}, supprimer l'espace avec {{jsxref("String.replace", "replace()")}} et ajouter ".txt" à la fin avec une simple concaténation de chaînes. Ajoutez les lignes suivantes à l'intérieur de la fonction updateDisplay() :

    + +
    verse = verse.replace(" ", "");
    +verse = verse.toLowerCase();
    +var url = verse + '.txt';
    +
  8. +
  9. +

    Pour commencer à créer une requête XHR, vous allez devoir créer un nouvel objet avec le constructeur {{domxref("XMLHttpRequest.XMLHttpRequest", "XMLHttpRequest()")}}. Vous pouvez appeler cet objet comme vous le voulez, mais nous l'appellerons request pour plus de clarté. Ajoutez ce qui suit à vos lignes précédentes :

    + +
    var request = new XMLHttpRequest();
    +
  10. +
  11. +

    Ensuite, vous allez devoir utiliser la méthode {{domxref("XMLHttpRequest.open","open()")}} pour spécifier la méthode HTTP et l'URL à utiliser pour récupérer la ressource. Nous allons ici utiliser la méthode GET et passer notre variable url pour URL. Ajoutez ceci à la suite de la ligne précédente :

    + +
    request.open('GET', url);
    +
  12. +
  13. +

    Nous allons définir le type de réponse que nous attendons — définit par la propriété {{domxref("XMLHttpRequest.responseType", "responseType")}} de la requête — comme text. Ce n'est pas strictement nécessaire ici — XHR retourne du texte par défaut — mais c'est une bonne idée d'en prendre l'habitude pour les cas où vous aurez besoin de définir un type différent. Ajoutez ceci à la suite :

    + +
    request.responseType = 'text';
    +
  14. +
  15. +

    Récupérer une ressource sur le réseau est une opération {{glossary("asynchronous","asynchrone")}}, ce qui signifie que vous devez attendre que cette opération se termine (par exemple, que la ressource soit renvoyée) avant de pouvoir récupérer la réponse — sans quoi une erreur est levée. XHR permet d'exécuter du code lorsque la réponse est reçue grâce au gestionnaire d'événement {{domxref("XMLHttpRequest.onload", "onload")}} — quand l'événement {{event("load")}} est déclenché. Une fois que la réponse a été reçue, alors la réponse est accessible via la propriété response de l'objet XHR utilisé.

    + +

    Ajoutez le bloc de code qui suit toujours au bas de la fonction updateDisplay(). Vous verrez qu'à l'intérieur du gestionnaire d'événément onload, nous assignons la propriété textContent de poemDisplay (l'élément {{htmlelement("pre")}}) à la valeur de la propriété {{domxref("XMLHttpRequest.response", "request.response")}}.

    + +
    request.onload = function() {
    +  poemDisplay.textContent = request.response;
    +};
    +
  16. +
  17. +

    Les étapes précédentes nous ont permis de configurer la requête XHR, mais celle-ci n'est exécutée que lorsqu'on le demande explicitement. Pour ce faire, il faut appeler la méthode {{domxref("XMLHttpRequest.send","send()")}}. Ajoutez la ligne suivante à la suite du code déjà écrit :

    + +
    request.send();
    + +

    Voyez la section {{anch("Serving your example from a server", "Servir votre exemple depuis un serveur")}} pour pouvoir tester.

    +
  18. +
  19. +

    Un dernier problème avec cet exemple est qu'il ne montre rien au chargement de la page (mais uniquement à la sélection d'un verset). Pour corriger cela, ajoutez ce qui suit au bas de votre code (juste au-dessus de la balise fermante </script>), pour charger le verset 1 par défaut, et s'assurer que l'élément {{htmlelement("select")}} montre toujours la bonne valeur :

    + +
    updateDisplay('Verse 1');
    +verseChoose.value = 'Verse 1';
    +
  20. +
+ +

Servir votre exemple depuis un serveur

+ +

Certains navigateurs (dont Chrome) n'exécuteront pas de requêtes XHR si vous exécutez votre script simplement à partir d'un fichier local. Cela est dû à des restrictions de sécurité (pour plus d'infos sur la sécurité web, consultez l'article La sécurité d'un site web).

+ +

Pour règler ce problème, vous devez tester l'exemple à travers un serveur web local. Pour savoir comment procéder, lisez Comment configurer un serveur de test local?

+ +

Fetch

+ +

L'API Fetch est une solution moderne qui vient remplacer XHR — elle a été introduite récemment dans les navigateurs pour rendre les requêtes HTTP asynchrones plus simples en JavaScript, à la fois pour les développeurs et pour les autres APIs qui utilisent cette technologie.

+ +

Voyons comment convertir le dernier exemple, en remplaçant XHR par Fetch.

+ +
    +
  1. +

    Faites une copie du répertoire de votre dernier exemple. (Ou si vous ne l'avez pas fait, créez un nouveau répertoire et copiez le fichier xhr-basic.html et les quatre fichiers texte — verse1.txt, verse2.txt, verse3.txt, and verse4.txt — à l'intérieur).

    +
  2. +
  3. +

    À l'intérieur de la fonction updateDisplay(), vous avez le code XHR suivant :

    + +
    var request = new XMLHttpRequest();
    +request.open('GET', url);
    +request.responseType = 'text';
    +
    +request.onload = function() {
    +  poemDisplay.textContent = request.response;
    +};
    +
    +request.send();
    +
  4. +
  5. +

    Remplacez-le avec ce qui suit :

    + +
    fetch(url).then(function(response) {
    +  response.text().then(function(text) {
    +    poemDisplay.textContent = text;
    +  });
    +});
    +
  6. +
  7. +

    Chargez l'exemple dans votre navigateur (en l'exécutant à travers un serveur web) et il devrait produire le même résultat que la version XHR  — pourvu que vous utilisiez un navigateur moderne.

    +
  8. +
+ +

Que se passe-t-il dans le code Fetch?

+ +

Tout d'abord, nous invoquons la méthode {{domxref("WindowOrWorkerGlobalScope.fetch()","fetch()")}}, en lui passant l'URL de la ressource que nous voulons récupérer. C'est la version moderne équivalente à {{domxref("XMLHttpRequest.open","request.open()")}} de XHR, et n'avez pas à appeler .send() — la requête est exécutée directemment.

+ +

Ensuite, la méthode {{jsxref("Promise.then",".then()")}} est chaînée à la suite de fetch() — cette méthode fait partie des {{jsxref("Promise","Promesses")}}, une fonctionnalité JavaScript moderne qui permet d'effectuer des opérations asynchrones. fetch() retourne une promesse, qui est résolue lorsque la réponse est reçue du serveur — et nous utilisons .then() pour exécuter du code à ce moment là. C'est l'équivalent du gestionnaire d'événément onload dans la version XHR.

+ +

La fonction définie dans le .then() reçoit la réponse du serveur comme paramètre, une fois que la promesse retournée par fetch() est résolue. À l'intérieur de cette fonction, nous utilisons la méthode {{domxref("Body.text","text()")}} pour récupérer le contenu de la réponse en texte brut. C'est l'équivalent de request.responseType = 'text' dans la version XHR.

+ +

Vous verrez que text() retourne également une promesse, nous y chaînons donc un nouveau .then(), à l'intérieur de quoi nous définissons une fonction. Cette dernière récupère quant à elle le texte brut que la promesse précédente résout.

+ +

Enfin, dans le corps de la fonction, nous faisons la même chose que nous faisions dans la version XHR — définir le contenu texte de l'élément {{htmlelement("pre")}} au texte récupéré.

+ +

À propos des promesses

+ +

Les promesses peuvent être un peu déroutantes au premier abord, ne vous en souciez pas trop pour l'instant. Vous vous y ferez après un certain temps, d'autant plus après en avoir appris davantage sur les APIs JavaScript modernes — la plupart des APIs récentes utilisent beaucoup les promesses.

+ +

Regardons à nouveau la structure d'une promesse pour voir si nous pouvons en donner plus de sens.

+ +

Promesse 1

+ +
fetch(url).then(function(response) {
+  //...
+});
+ +

Si l'on traduit en bon français les instructions JavaScript, on pourrait dire

+ + + +

On dit qu'une promesse est "résolue" (resolved) lorsque l'opération spécifiée à un moment donné est terminée. En l'occurence, l'opération spécifiée est de récupérer une ressource à une URL donnée (en utilisant une requête HTTP) et de retourner la réponse reçue du serveur.

+ +

La fonction passée à then() n'est pas exécutée immédiatement — elle est exécutée à un moment dans le futur, dès que la promesse est résolue (c'est à dire qu'elle a retourné la réponse du serveur).

+ +

Notez que vous pouvez également choisir de stocker votre promesse dans une variable, et de chaîner le {{jsxref("Promise.then",".then()")}} sur cette variable. L'exemple suivant fait la même chose que le précédent :

+ +
var myFetch = fetch(url);
+
+myFetch.then(function(response) {
+  //...
+});
+ +

Parce que la méthode fetch() retourne une promesse qui résout une réponse HTTP, la fonction définie à l'intérieur du .then() reçoit la réponse en tant que paramètre. Vous pouvez appeler le paramètre comme vous souhaitez — l'exemple ci-dessous fait toujours la même chose :

+ +
fetch(url).then(function(dogBiscuits) {
+  //...
+});
+ +

Mais il est plus logique de donner un nom de paramètre qui décrit son contenu !

+ +

Promesse 2

+ +

Voyons maintenant la fonction appelé dans .then():

+ +
function(response) {
+  response.text().then(function(text) {
+    poemDisplay.textContent = text;
+  });
+}
+ +

L'objet response a une méthode {{domxref("Body.text","text()")}}, qui convertit les données brutes contenues dans la réponse en texte brut — c'est le format que nous voulons. Cette méthode retourne également une promesse, qui se résout lorsque la réponse est convertie en texte, nous utilisons donc un deuxième {{jsxref("Promise.then",".then()")}} pour cette deuxième promesse.

+ +

À l'intérieur de ce dernier .then(), nous définissons une nouvelle fonction, qui décide de ce que nous faisons avec le texte récupéré. Nous nous contentons de définir la propriété textContent de l'élément {{htmlelement("pre")}} à la valeur du texte.

+ +

Chaîner les then()

+ +

Notez que le résultat de la fonction appelée par le .then() est également retourné par ce dernier, nous pouvons donc mettre les .then() bout à bout, en passant le résultat du bloc précédent au prochain.

+ +

Ainsi, le bloc de code suivant fait la même chose que notre exemple original, mais écrit dans un style différent :

+ +
fetch(url).then(function(response) {
+  return response.text()
+}).then(function(text) {
+  poemDisplay.textContent = text;
+});
+ +

Beaucoup de développeurs préfèrent ce style, plus "plat" : il évite de définir des fonctions à l'intérieur de fonctions et est plus facile à lire lorsqu'il y a beaucoup de promesses qui s'enchaînent. La seule différence ici est que nous avons une instruction return pour retourner response.text(), et ce résultat est passé au prochain .then().

+ +

Quel mécanisme devriez-vous utiliser?

+ +

Cela dépend du projet sur lequel vous travaillez. XHR existe depuis longtemps maintenant et bénéficie d'un très bon support sur les différents navigateurs. Fetch et les promesses, en revanche, sont un ajout plus récent à la plateforme web, bien qu'ils soient pris en charge par la plupart des navigateurs, Internet Explorer et Safari font exception.

+ +

Si vous voulez un support des anciens navigateurs, alors XHR est probablement la solution préférable. En revanche, si vous travaillez sur un projet plus progressif, et que vous n'êtes pas tant préoccupé par les anciens navigateurs, alors Fetch peut être un bon choix.

+ +

Vous devriez apprendre les deux alternatives — Fetch deviendra plus populaire au fur et à mesure que l'utilisation d'Internet Explorer diminue (IE n'est plus développé, en faveur du nouveau navigateur de Microsoft, Edge), mais vous allez avoir besoin de XHR pendant un moment encore.

+ +

Un exemple plus complexe

+ +

Pour clore l'article, nous allons regarder un exemple un peu plus complexe, qui montre des utilisations plus intéressantes de Fetch. Nous avons créé un site d'exemple appelé The Can Store (le magasin de conserves) — c'est un supermarché fictif qui ne vend que des boites de conserves. Vous pouvez trouver cet exemple en direct sur GitHub, et voir le code source.

+ +

A fake ecommerce site showing search options in the left hand column, and product search results in the right hand column.

+ +

Par défaut, le site affiche tous les produits ; mais vous pouvez utiliser le formulaire dans la colonne de gauche pour les filtrer par catégorie, ou chercher un terme, ou les deux.

+ +

Il y a du code plutôt complexe pour traiter le filtrage des produits par catégorie et par terme de recherche, manipulant les chaînes de caractères pour afficher les données correctement dans l'interface utilisateur, etc. Nous n'allons pas en discuter dans cet article, mais vous pouvez trouver des commentaires très complets dans le code (voir can-script.js). Nous allons expliquer le code Fetch.

+ +

Premier Fetch

+ +

Le premier bloc qui utilise Fetch se trouve au début du JavaScript :

+ +
fetch('products.json').then(function(response) {
+  if(response.ok) {
+    response.json().then(function(json) {
+      products = json;
+      initialize();
+    });
+  } else {
+    console.log('Network request for products.json failed with response ' + response.status + ': ' + response.statusText);
+  }
+});
+ +

Cela ressemble à ce que vous avons vu précédemment, sauf que la deuxième promesse est à l'intérieur d'une condition. Cette condition vérifie si la réponse retournée est un succès ou non — la propriété {{domxref("response.ok")}} contient un booléen qui vaut true si le statut de la réponse était OK (statut HTTP 200, "OK"), ou false sinon.

+ +

Si la réponse était un succès, nous déclenchons la deuxième promesse — cette fois-ci en utilisant {{domxref("Body.json","json()")}} et non {{domxref("Body.text","text()")}}, puisque nous voulons récupérer la réponse sous forme de données structurées JSON et non de texte brut.

+ +

Si la réponse n'est pas un succès, nous affichons une erreur dans la console indiquant que la requête réseau a échoué, avec le statut et le message obtenus (contenus dans les propriétés {{domxref("response.status")}} et {{domxref("response.statusText")}} respectivement). Bien sûr, un véritable site web traiterait cette erreur plus gracieusement, en affichant un message à l'écran en offrant peut-être des options pour remédier à la situation.

+ +

Vous pouvez tester le cas d'échec vous-même :

+ +
    +
  1. Faites une copie locale des fichiers d'exemple (téléchargez et dézippez le fichier ZIP can-store)
  2. +
  3. Éxecutez le code via un serveur web (comme vu précédemment dans {{anch("Serving your example from a server", "Servir votre exemple depuis un serveur")}})
  4. +
  5. Modifiez le chemin du fichier à récupérer, mettez un nom de fichier qui n'existe pas, comme 'produc.json'.
  6. +
  7. Maintenant, chargez le fichier index dans votre navigateur (via localhost:8000) et regardez dans la console de développement. Vous verrez un message parmi les lignes "Network request for products.json failed with response 404: File not found" (la requête réseau pour products.json a échoué avec la réponse 404: Fichier non trouvé).
  8. +
+ +

Deuxième Fetch

+ +

Le deuxième bloc Fetch se trouve dans la fonction fetchBlob():

+ +
fetch(url).then(function(response) {
+  if(response.ok) {
+    response.blob().then(function(blob) {
+      objectURL = URL.createObjectURL(blob);
+      showProduct(objectURL, product);
+    });
+  } else {
+    console.log('Network request for "' + product.name + '" image failed with response ' + response.status + ': ' + response.statusText);
+  }
+});
+ +

Cela fonctionne à peu près de la même manière que le précédent, sauf qu'au lieu d'utiliser {{domxref("Body.json","json()")}}, on utilise {{domxref("Body.blob","blob()")}} — en l'occurence, nous voulons récupérer la réponse sous la forme d'un fichier image, et le format de données que nous utilisons est Blob — ce terme est une abbréviation de "Binary Large Object" (large objet binaire) et peut être utilisé pour représenter de gros objets fichier — tels que des fichiers images ou vidéo.

+ +

Une fois que nous avons reçu notre blob avec succès, nous créons un objet URL, en utilisant {{domxref("URL.createObjectURL()", "createObjectURL()")}}. Cela renvoie une URL interne temporaire qui pointe vers un blob en mémoire dans le navigateur. Cet objet n'est pas très lisible, mais vous pouvez voir à quoi il ressemble en ouvrant l'application Can Store, Ctrl + Clic droit sur l'image, et sélectionner l'option "Afficher l'image" (peut légèrement varier selon le navigateur que vous utilisez). L'URL créée sera visible à l'intérieur de la barre d'adresse et devrait ressembler à quelque chose comme ça :

+ +
blob:http://localhost:7800/9b75250e-5279-e249-884f-d03eb1fd84f4
+ +

Challenge : une version XHR de Can Store

+ +

Comme exercice pratique, nous aimerions que vous essayiez de convertir la version Fetch de l'application en une version XHR. Faites une copie du fichier ZIP et essayiez de modifier le JavaScript en conséquence.

+ +

Quelques conseils qui pourraient s'avérer utiles :

+ + + +
+

Note : Si vous avez des difficultés à le faire, vous pouvez comparer votre code à la version finale sur GitHub (voir le code source, ou voir en direct).

+
+ +

Sommaire

+ +

Voilà qui clôt notre article sur la récupération de données à partir du serveur. À ce stade, vous devriez savoir comment travailler avec XHR et Fetch.

+ +

Voir aussi

+ +

Il y a beaucoup de sujets abordés dans cet article, dont nous n'avons qu'égratigné la surface. Pour plus de détails sur ces sujets, essayez les articles suivants:

+ + + +
{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Manipulating_documents", "Learn/JavaScript/Client-side_web_APIs/Third_party_APIs", "Learn/JavaScript/Client-side_web_APIs")}}
+ +
+

Dans ce module

+ + +
diff --git a/files/fr/learn/javascript/client-side_web_apis/index.html b/files/fr/learn/javascript/client-side_web_apis/index.html new file mode 100644 index 0000000000..d5d6f410e3 --- /dev/null +++ b/files/fr/learn/javascript/client-side_web_apis/index.html @@ -0,0 +1,51 @@ +--- +title: API web utilisées côté client +slug: Apprendre/JavaScript/Client-side_web_APIs +tags: + - API + - API Web + - Apprendre + - Articles + - Codage + - DOM + - Débutant + - Graphismes + - JavaScript + - Localisation + - Media + - Module + - données +translation_of: Learn/JavaScript/Client-side_web_APIs +--- +
{{LearnSidebar}}
+ +

Lorsque vous écrivez du JavaScript côté client pour des sites Web ou des applications, vous n'irez pas très loin avant d'utiliser des API - des interfaces pour manipuler différents aspects du navigateur et du système d'exploitation sur lesquels le site opère, ou même des données provenant d'autres sites web ou services. Dans ce module, nous allons explorer ce que sont les API, et comment utiliser certaines API les plus courantes que vous rencontrerez souvent dans votre travail de développement.

+ +

Prérequis

+ +

Pour tirer le meilleur parti de ce module, vous devriez avoir parcouru les précédents modules JavaScript de la série (Premiers pas, Building blocks et objets JavaScript). Ces modules impliquent tout de même un bon nombre d'utilisations simples de l'API, car il est difficile d'écrire des exemples JavaScript côté client faisant quelque chose d'utile sans eux! Ici, nous passons à un niveau supérieur, en supposant que vous connaissiez le langage JavaScript de base et explorant les APIs Web courantes de manière un peu plus détaillée.

+ +

Une connaissance basique de HTML et CSS serait aussi utile.

+ +
+

Remarque: Si vous travaillez sur un ordinateur/tablette/autre périphérique où vous n'avez pas la possibilité de créer vos propres fichiers, vous pouvez essayer (la plupart) des exemples de code dans un programme de code en ligne tel que JSBin ou Thimble.

+
+ +

Guides

+ +
+
Introduction aux API du Web
+
Tout d'abord, nous survolerons du concept d'API — qu'est-ce que c'est, comment ça fonctionne, comment les utiliser dans votre code, et comment sont-elles structurées. Nous verrons également quelles sont les principales API et leur utilisation.
+
Manipuler des documents
+
Quand on écrit des pages web et des applications, une des choses les plus courantes que l'on veut faire est de manipuler la structure du document d'une manière ou d'une autre. On le fait généralement en utilisant le Document Object Model (DOM), un ensemble d'APIs qui permettent de contrôler le HTML et le style — et qui utilisent massivement l'objet {{domxref("Document")}}. Dans cet article, nous allons voir comment utiliser le DOM en détail, ainsi que quelques APIs intéressantes qui peuvent modifier votre environnement.
+
Récupérer des données du serveur
+
Une autre tâche courante dans les sites et applications web modernes est de récupérer des données à partir du serveur pour mettre à jour des sections de la page web sans la recharger entièrement. Ce qui pourrait paraître comme un petit détail, a en vérité eu un impact énorme sur les performances et le comportement des sites. Dans cet article, nous allons expliquer le concept et les technologies qui rendent cela possible, tels que {{domxref("XMLHttpRequest")}} et l'API Fetch.
+
APIs tierces
+
Les APIs que nous avons vu jusqu'à présent sont intégrées dans le navigateur, mais ce n'est pas le cas de toutes. De nombreux gros sites web tels que Google Maps, Twitter, Facebook, PayPal, etc, fournissent des APIs permettant aux développeurs d'utiliser leurs données (par exemple pour afficher un flux twitter sur un blog) ou service (par exemple afficher une carte Google Maps sur un site, ou utiliser Facebook pour permettre aux utilisateurs de se connecter). Cet article compare les APIs du navigateur aux APIs tierces et montre quelques utilisations typiques de ces dernières.
+
Dessiner des éléments graphiques
+
Le navigateur contient des outils de programmation graphique très puissants, du langage SVG (Scalable Vector Graphics), aux APIs pour dessiner sur les éléments HTML {{htmlelement("canvas")}}, (voir API Canvas et WebGL). Cet article fournit une introduction à canvas et introduit d'autres ressources pour vous permettre d'en apprendre plus.
+
APIs vidéo et audio
+
HTML5 fournit des éléments pour intégrer du multimédia dans les documents — {{htmlelement("video")}} et {{htmlelement("audio")}} — et qui viennent avec leurs propres APIs pour contrôler la lecture, se déplacer dans le flux, etcCet article montre comment réaliser les tâches les plus communes, comme créer des contrôles de lectures personnalisés.
+
Stockage côté client
+
Les navigateurs web modernes permettent aux sites web de stocker des données sur l'ordinateur de l'utilisateur — avec sa permission — puis de les récupérer au besoin. Cela permet d'enregistrer des données pour du stockage long-terme, de sauvegarder des documents ou sites hors-ligne, de conserver des préférences spécifiques à l'utilisateur, et plus encore. Cet article explique les fondamentaux pour y parvenir.
+
diff --git a/files/fr/learn/javascript/client-side_web_apis/introduction/index.html b/files/fr/learn/javascript/client-side_web_apis/introduction/index.html new file mode 100644 index 0000000000..b7e2ed71b4 --- /dev/null +++ b/files/fr/learn/javascript/client-side_web_apis/introduction/index.html @@ -0,0 +1,307 @@ +--- +title: Introduction aux API du Web +slug: Apprendre/JavaScript/Client-side_web_APIs/Introduction +tags: + - API + - API Web + - Apprentissage + - Article + - Codage + - Débutant + - Navigateur + - Objet + - Tierce partie + - côté‑client +translation_of: Learn/JavaScript/Client-side_web_APIs/Introduction +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/JavaScript/Client-side_web_APIs/Manipulating_documents", "Learn/JavaScript/Client-side_web_APIs")}}
+ +

Tout d'abord, nous survolerons le concept d'API — qu'est-ce que c'est, comment ça fonctionne, comment les utiliser dans votre code, et comment sont-elles structurées ? Nous verrons également quelles sont les principales APIs et leur utilisation.

+ + + + + + + + + + + + +
Prérequis :Des connaissances de base en informatique, une compréhension de base du HTML et CSS, des notions de JavaScript (voir premiers pas, briques JavaScript, objets JavaScript).
Objectif :Vous familiariser avec les APIs, ce qu'elles permettent de faire, et comment les utiliser dans votre code.
+ +

C'est quoi une API ?

+ +

Les APIs (Application Programming Interfaces) sont des constructions disponibles dans les langages de programmation pour permettre aux développeurs de créer plus facilement des fonctionnalités complexes. Elles s'occupent des parties de code plus complexes, fournissant au développeur une syntaxe plus facile à utiliser à la place.

+ +

En guise d'exemple concret, pensez à des branchements électriques dans une maison, appartement ou autre logement. Si vous souhaitez utiliser un appareil dans votre maison, il vous suffit de le brancher dans une prise et cela fonctionne. Vous n'essayez pas de le brancher directement à l'alimentation électrique — le faire serait réellement inefficace, et, si vous n'êtes pas électricien, difficile et dangereux à réaliser.

+ +

+ +

Image source: Overloaded plug socket by The Clear Communication People, on Flickr.

+ +

De la même façon, par exemple, pour programmer des graphismes en 3D, il est beaucoup plus facile de le faire en utilisant une API écrite dans un langage de haut niveau comme JavaScript ou Python, plutôt que d'essayer d'écrire du code bas niveau (comme C ou C ++) qui contrôle directement le GPU de l'ordinateur ou d'autres fonctions graphiques.

+ +
+

Note : Voir aussi l'entrée API du glossaire pour plus de descriptions.

+
+ +

APIs JavaScript côté client

+ +

Le JavaScript côté client en particulier a de nombreuses APIs à sa disposition — elles ne font pas partie du langage JavaScript lui-même, elles sont construites par dessus JavaScript, offrant des super-pouvoirs supplémentaires à utiliser dans votre code. Elles appartiennent généralement à une des deux catégories:

+ + + +

+ +

Relations entre JavaScript, APIs et autres outils JavaScript

+ +

Ci-dessus, nous avons indiqué ce qu'est une API JavaScript côté client et quelle est sa relation avec le langage JavaScript. Pour récapituler, clarifier, et apporter plus de précisions sur  d'autres outils JavaScript qui existent:

+ + + +

Que peuvent faire les API ?

+ +

Il y a un beaucoup d'APIs disponibles dans les navigateurs modernes. Elles permettent de faire un large éventail de choses. Vous pouvez vous en faire une petite idée en jetant un coup d'œil à la page de l'index des API MDN

+ +

API de navigateur courantes

+ +

En particulier, voici les catégories d'API de navigateur les plus courantes que vous utiliserez (et que nous allons voir dans ce module plus en détail) :

+ + + +

APIs tierces courantes

+ +

Il y a une grande variété d'APIs tierces; en voici quelques unes des plus populaires que vous allez probablement utiliser tôt ou tard : 

+ + + +
+

Note : Vous pouvez trouver des informations sur beaucoup plus d'API tierces dans le répertoire Programmable Web API.

+
+ +

Comment les API fonctionnent-elles?

+ +

Chaque API Javascript fonctionne de manière légèrement différente d'une autre, mais de manière générale, elles ont des fonctionnalités communes et des thèmes similaires.

+ +

Elles sont fondées sur des objets

+ +

Les APIs interagissent avec le code en utilisant un ou plusieurs objets Javascript, qui servent de conteneurs pour les données utilisées par l'API (contenues dans les propriétés d'objet), et la fonctionnalité rendue disponible par l'API (contenue dans des méthodes d'objet).

+ +
+

Note : Si vous n'êtes pas déjà familier avec le fonctionnement des objets, vous devriez revenir en arrière et parcourir le module objets Javascript avant de continuer.

+
+ +

Prenons pour exemple l'API Géolocalisation — c'est une API très simple composée de quelques simples objets :

+ + + +

Alors comment ces objets interagissent-ils ? Si vous regardez notre exemple maps-example.html (regardez‑le aussi en direct), vous verrez le code suivant : 

+ +
navigator.geolocation.getCurrentPosition(function(position) {
+  var latlng = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
+  var myOptions = {
+    zoom: 8,
+    center: latlng,
+    mapTypeId: google.maps.MapTypeId.TERRAIN,
+    disableDefaultUI: true
+  }
+  var map = new google.maps.Map(document.querySelector("#map_canvas"), myOptions);
+});
+ +
+

Note : Quand vous chargez l'exemple ci-dessus pour la première fois, vous devriez voir une boîte de dialogue demandant si vous acceptez de partager votre position avec cette application (voir la section {{anch ("Elles ont des mécanismes de sécurité supplémentaires si nécessaire")}} plus loin dans cet article).
+ Vous devez accepter pour pouvoir inscrire votre position sur la carte. Si vous ne pouvez toujours pas voir la carte, vous devrez activer l'autorisation à la main. Vous pouvez le faire de différentes manières selon le navigateur utilisé ; par exemple, dans Firefox, allez dans > Outils > Informations sur la page > Permissions, puis modifiez le paramètre Accèder à votre position ; dans Chrome, allez à Paramètres > Confidentialité > Afficher les paramètres avancés > Paramètres de contenu, puis modifiez les paramètres d'emplacement.
+  

+
+ +

Pour récupérer l'objet {{domxref("Geolocation")}} du navigateur, on fait appel à {{domxref("Navigator.geolocation")}}. On se sert ensuite de la méthode {{domxref("Geolocation.getCurrentPosition()")}} pour obtenir la position actuelle de notre appareil. On commence donc avec

+ +
navigator.geolocation.getCurrentPosition(function(position) { ... });
+ +

C'est pareil que:

+ +
var myGeo = navigator.geolocation;
+myGeo.getCurrentPosition(function(position) { ... });
+ +

On peut utiliser la syntaxe point pour chaîner l'accès propriété/méthode et réduire ainsi le nombre de lignes à écrire.

+ +

La méthode {{domxref("Geolocation.getCurrentPosition()")}} n'a qu'un seul paramètre obligatoire : une fonction anonyme qui s'exécute une fois que la position actuelle du périphérique a été récupérée avec succès. Cette fonction prend elle-même un paramètre, l'objet {{domxref("Position")}}, contenant les données de position actuelle.

+ +
+

Note : Une fonction prise en argument par une autre fonction s'appelle une fonction de rappel.

+
+ +

Elles utilisent des fonctions de rappel

+ +

Cette manière d'appeler des fonctions seulement quand une opération est terminée, pour s'assurer de la bonne fin d'une opération avant d'utiliser les données renvoyées dans une autre opération, est très courante dans les API JavaScript. C'est ce qu'on appelle des opérations {{glossary("asynchronous", "asynchrones")}}.

+ +

Récupérer la position actuelle de l'appareil repose sur un composant externe (le GPS de l'appareil ou un autre matériel de géolocalisation), on ne peut pas garantir que cela sera fait à temps pour utiliser immédiatement les données qu'il renvoie. Par conséquent, quelque chose comme cela ne fonctionne pas :

+ +
var position = navigator.geolocation.getCurrentPosition();
+var myLatitude = position.coords.latitude;
+ +

Si la première ligne n'a pas encore renvoyé son résultat, la deuxième ligne renvoie une erreur, car les données de position ne sont pas encore disponibles.

+ +

Pour cette raison, les APIs impliquant des opérations asynchrones sont conçues pour utiliser des {{glossary ("callback function","fonctions de rappel")}} ou bien le système plus moderne des Promesses — maintenant disponible dans ECMAScript 6 et largement utilisé dans les nouvelles APIs.

+ +

Pour les APIs tierces, elles doivent être inclues

+ +

On combine l'API Geolocation avec une API tierce — l'API Google Maps — pour tracer l'emplacement renvoyé par getCurrentPosition() sur une carte Google Map. Pour mettre cette API à disposition sur notre page on doit l'inclure — vous trouverez cette ligne dans le code HTML:

+ +
<script type="text/javascript" src="https://maps.google.com/maps/api/js?key=AIzaSyDDuGt0E5IEGkcE6ZfrKfUtE9Ko_de66pA"></script>
+ +

Elles utilisent des constructeurs et des options pour être personnalisées

+ +

Pour afficher la position de l'utilisateur sur la carte, on crée d'abord une instance d'objet LatLng avec le constructeur google.maps.LatLng(). Il prend les valeurs de géolocalisation {{domxref ("coords.latitude")}} et {{domxref ("coords.longitude")}} comme paramètres:

+ +
var latlng = new google.maps.LatLng(
+    position.coords.latitude,
+    position.coords.longitude
+);
+ +

L'objet que nous avons construit est définit comme la valeur de la propriété center d'un objet d'options, myOptions. Ces options vont être utilisées pour construire la carte.

+ +

On crée une instance d'objet pour représenter notre carte en appelant le constructeur google.maps.Map() avec deux paramètres — une référence à l'élément {{htmlelement ("div")}} sur lequel on veut afficher la carte (celui avec l'ID map_canvas), et l'objet d'options que nous avons défini juste au-dessus.

+ +
var myOptions = {
+  zoom: 8,
+  center: latlng,
+  mapTypeId: google.maps.MapTypeId.TERRAIN,
+  disableDefaultUI: true
+}
+
+var map = new google.maps.Map(document.querySelector("#map_canvas"), myOptions);
+ +

Ceci fait, notre carte s'affiche.

+ +

Ce dernier bloc de code met en évidence deux modèles courants que vous verrez dans de nombreuses APIs. Tout d'abord, les objets des APIs contiennent généralement des constructeurs, qui sont appelés pour créer des instances d'objets. Ensuite, les objets APIs ont souvent plusieurs options disponibles qui peuvent être modifiées pour obtenir l'environnement exact que vous voulez pour votre programme. Les constructeurs d'API acceptent généralement des objets d'options en tant que paramètres, ce qui vous permet de définir leur comportement.

+ +
+

Note : Ne vous inquiétez pas si vous ne comprenez pas immédiatement le détail de cet exemple . Nous aborderons plus amplement les APIs tierces parties dans un futur article.

+
+ +

Elles ont des points d'entrée identifiables

+ +

Lorsque vous utilisez une API, vous devez d'abord savoir quel est le point d'entrée de l'API. Dans l'API Geolocation, c'est assez simple — c'est la propriété {{domxref ("Navigator.geolocation")}} qui renvoie l'objet {{domxref ("Geolocation")}} du navigateur. Cet objet contient toutes les méthodes disponibles de géolocalisation à l'intérieur.

+ +

L'API DOM (Document Object Model) a un point d'entrée encore plus simple — ses caractéristiques sont généralement trouvées attachées à l'objet {{domxref ("Document")}}, ou à toute instance d'un élément HTML que vous souhaitez affecter d'une manière ou d'une autre. Par exemple:

+ +
var em = document.createElement('em'); // créer un nouvel élément
+var para = document.querySelector('p'); // référence à un élément p existant
+em.textContent = 'Hello there!'; // fournir à em un contenu textuel
+para.appendChild(em); // incorporer un paragraphe dans em
+ +

D'autres API ont des points d'entrée légèrement plus complexes, impliquant souvent un contexte spécifique dans lequel le code de l'API doit être écrit. Par exemple, l'objet contextuel de l'API Canvas est créé en obtenant une référence à l'élément {{htmlelement ("canvas")}} sur lequel vous voulez dessiner, puis en appelant sa méthode {{domxref ("HTMLCanvasElement.getContext ()")}} :

+ +
var canvas = document.querySelector('canvas');
+var ctx = canvas.getContext('2d');
+ +

Tout ce que nous voulons faire sur canvas est alors obtenu en appelant les propriétés et méthodes de l'objet conteneur (qui est une instance de {{domxref ("CanvasRenderingContext2D")}}). Par exemple :

+ +
Ball.prototype.draw = function() {
+  ctx.beginPath();
+  ctx.fillStyle = this.color;
+  ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
+  ctx.fill();
+};
+ +
+

Note : Vous pouvez voir le code source de notre démo « balles rebondissantes » (ou voir directement).

+
+ +

Elles utilisent des événements pour réagir aux changements d'état

+ +

Nous avons déjà parlé des événements plus haut dans ce cours, dans notre article Introduction aux événements — cet article explique en détail ce que sont les événements Web et leur utilisation dans votre code. Si vous ne vous êtes pas encore familiarisé avec le fonctionnement des événements de l'API Web côté client, vous devriez lire cet article avant de continuer.

+ +

Certaines API Web ne détectent pas les événements, d'autres peuvent réagir à certains. Vous pouvez généralement trouver les propriétés des APIs qui permettent de lancer des fonctions lorsque les événements surviennent dans les sections "Gestionnaires d'événements" des documents de réference des APIs.

+ +

À titre de simple exemple, les instances de l'objet XMLHttpRequest (qui représentent une requête HTTP vers le serveur pour récupérer une ressource) ont un certain nombre d'événements disponibles. Par exemple, l'événement load est déclenché lorsqu'une réponse a été retournée avec succès avec la ressource demandée, et qu'elle devient alors disponible:

+ +
var requestURL = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';
+var request = new XMLHttpRequest();
+request.open('GET', requestURL);
+request.responseType = 'json';
+request.send();
+
+request.onload = function() {
+  var superHeroes = request.response;
+  populateHeader(superHeroes);
+  showHeroes(superHeroes);
+}
+ +
+

Note : Vous pouvez voir le code source de notre exemple ajax.html (ou le voir directement).

+
+ +

Les cinq premières lignes définissent l'emplacement de la ressource que nous voulons récupérer, créent une nouvelle instance d'un objet de requête en utilisant le constructeur XMLHttpRequest(), ouvrent une requête HTTP GET pour récupérer la ressource spécifiée, spécifient que la réponse doit être envoyée au format JSON, puis envoient la demande.

+ +

La fonction gestionnaire onload indique ensuite ce qu'on fait avec la réponse. On sait que la réponse sera disponible dès que l'événement load est appelé (sauf si une erreur se produit), on sauvegarde donc la réponse — contenant le JSON renvoyé — dans la variable superHeroes, puis on la passe à deux fonctions différentes pour un traitement ultérieur.

+ +

Elles ont des mécanismes de sécurité supplémentaires si nécessaire

+ +

Les caractéristiques des APIs Web sont soumises aux mêmes considérations de sécurité que JavaScript et des autres technologies Web (par exemple, la same-origin policy), mais elles disposent parfois de mécanismes de sécurité supplémentaires.

+ +

Par exemple, certaines des APIs Web les plus modernes ne fonctionneront que sur les pages HTTPS car elles transmettent des données potentiellement sensibles (exemple: Service Workers et Push).

+ +

En outre, certaines APIs Web demandent l'autorisation d'être activés par l'utilisateur une fois que les appels sont faits dans votre code. Par exemple, vous avez peut-être remarqué une boîte de dialogue comme celle-ci lors du chargement de notre exemple de Geolocation précédent :

+ +

+ +

De même, l'API Notifications demande une autorisation:

+ +

+ +

Ces invites d'autorisation sont affichées aux utilisateurs pour des raisons de sécurité — si elles n'étaient pas en place, alors les sites pourraient commencer à suivre secrètement votre emplacement sans que vous le sachiez, ou à vous envoyer des messages indésirables avec beaucoup de notifications ennuyantes.

+ +

Résumé

+ +

À ce stade, vous devriez avoir une bonne idée de ce que sont les APIs, comment elles fonctionnent et ce que vous pouvez faire avec dans votre code JavaScript. Vous êtes probablement impatients de commencer à faire des choses amusantes avec des APIs spécifiques, alors allons-y ! Par la suite, nous verrons comment manipuler des documents avec le Document Object Model (DOM).

+ +

{{NextMenu("Learn/JavaScript/Client-side_web_APIs/Manipulating_documents", "Learn/JavaScript/Client-side_web_APIs")}}

+ +

Dans ce module

+ + + +

 

diff --git a/files/fr/learn/javascript/client-side_web_apis/manipulating_documents/index.html b/files/fr/learn/javascript/client-side_web_apis/manipulating_documents/index.html new file mode 100644 index 0000000000..79911663f8 --- /dev/null +++ b/files/fr/learn/javascript/client-side_web_apis/manipulating_documents/index.html @@ -0,0 +1,332 @@ +--- +title: Manipuler des documents +slug: Apprendre/JavaScript/Client-side_web_APIs/Manipulating_documents +tags: + - API + - Apprendre + - Article + - Codage + - DOM + - Document Object Model + - Débutant + - JavaScript + - Navigator + - WebAPI + - Window +translation_of: Learn/JavaScript/Client-side_web_APIs/Manipulating_documents +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Introduction", "Learn/JavaScript/Client-side_web_APIs/Fetching_data", "Learn/JavaScript/Client-side_web_APIs")}}
+ +

Quand on écrit des pages web et des applications, une des choses les plus courantes que l'on veut faire est de manipuler la structure du document d'une manière ou d'une autre. On le fait généralement en utilisant le Document Object Model (DOM), un ensemble d'APIs qui permettent de contrôler le HTML et le style — et qui utilisent massivement l'objet {{domxref("Document")}}. Dans cet article, nous allons voir comment utiliser le DOM en détail, ainsi que quelques APIs intéressantes qui peuvent modifier votre environnement.

+ + + + + + + + + + + + +
Prérequis:Connaissances de base en informatique, notions de base d'HTML, CSS, et JavaScript — dont les objets JavaScript.
Objectif:Sa familiariser avec les APIs DOM, et autres APIs souvent associées au DOM et à la manipulation de document
+ +

Les principaux composants du navigateur

+ +

Les navigateurs web sont des logiciels très compliqués avec beaucoup de pièces mobiles, dont beaucoup qui ne peuvent pas être contrôlées ou manipulées par un développeur web en utilisant JavaScript. Vous pourriez penser que de telles limitations sont une mauvaise chose, mais les navigateurs sont verrouillés pour de bonnes raisons, la plupart du temps pour des raisons de sécurité. Imaginez qu'un site web puisse accéder à vos mots de passe stockés ou autre information sensible, et se connecter à des sites Web comme si c'était vous?

+ +

Malgré les limitations, les APIs Web nous donnent accès à beaucoup de fonctionnalités, lesquelles nous permettent de faire pleins de choses géniales avec les pages web. Il existe quelques éléments évidents que vous utilisez régulièrement dans votre code — jetez un coup d'oeil au diagramme suivant, il représente les principaux composants du navigateur directemment impliqués dans l'affichage des pages web:

+ +

+ + + +

Dans cet article, nous allons principalement nous concentrer sur la manipulation du document, mais nous verrons également quelques autres éléments utiles.

+ +

Le modèle objet du document (Document Object Model)

+ +

Le document chargé dans l'onglet de votre navigateur, et donc son contenu, est accessible via un modèle objet du document — Document Objet Model en anglais, ou DOM. Il s'agit d'une structure arborescente créée par le navigateur et qui permet aux langages de programmation d'accéder facilement à la structure HTML — par exemple, le navigateur lui-même l'utilise pour appliquer les informations de style ou pour corriger les éléments lorsque le HTML est invalide, tandis qu'un développeur peut l'utiliser pour manipuler la page une fois qu'elle a été chargée.

+ +

Nous avons créé une simple page d'example, dom-example.html (voir en direct). Essayez de l'ouvrir dans votre navigateur — c'est une page très simple qui contient un élément {{htmlelement("section")}}, à l'intérieur duquel se situe une image et un paragraphe avec un lien. Le code source HTML ressemble à ça:

+ +
<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Simple DOM example</title>
+  </head>
+  <body>
+      <section>
+        <img src="dinosaur.png" alt="A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth.">
+        <p>Here we will add a link to the <a href="https://www.mozilla.org/">Mozilla homepage</a></p>
+      </section>
+  </body>
+</html>
+ +

Le DOM, d'autre part, ressemble à ça:

+ +

+ +
+

Note: Ce diagramme du DOM a été créé en utilisant le Live DOM viewer de Ian Hickson.

+
+ +

Vous pouvez voir ici que chaque élément et donnée texte dans le document a sa propre entrée dans l'arbre — appelé un noeud (node). Vous rencontrerez également différents termes pour décrire différents type de noeuds et leur position dans l'arbre par rapport à d'autres:

+ + + +

Il est utile de vous familiariser avec ces termes avant de travailler avec le DOM, puisqu'un certain nombre de documentations les utilisent. Vous les avez peut-être déjà rencontrés si vous avez étudié CSS (ex. sélecteur descendant, sélecteur enfant).

+ +

Apprentissage actif: Manipulations basiques du DOM

+ +

Pour commencer l'apprentissage de la manipulation du DOM, commençons par la pratique.

+ +
    +
  1. Faites une copie locale de la page dom-example.html et de l'image qui l'accompagne.
  2. +
  3. Ajoutez un élément <script></script> juste avant la balise fermante </body>.
  4. +
  5. Pour manipuler un élément dans le DOM, vous allez d'abord sélectionner cet élément et stocker une référence vers cet élément dans une variable. À l'intérieur de votre élément <script>, ajoutez la ligne suivante: +
    var link = document.querySelector('a');
    +
  6. +
  7. Maintenant que nous avons une référence vers l'élément, nous pouvous commencer à le manipuler en utilisant les propriétés et les méthodes disponibles dessus (celles-ci sont définies sur les interfaces telles que {{domxref("HTMLAnchorElement")}} dans le cas d'un élément {{htmlelement("a")}}, et sur les interfaces plus génériques {{domxref("HTMLElement")}}, et {{domxref("Node")}} — qui représente tout noeud dans le DOM). Tout d'abord, nous allons changer le texte du lien en mettant à jour la valeur de la propriété {{domxref("Node.textContent")}}. Ajoutez la ligne suivante à la suite de la précédente: +
    link.textContent = 'Mozilla Developer Network';
    +
  8. +
  9. Nous allons également changer l'URL où dirige le lien, pour qu'il ne dirige pas au mauvais endroit quand on clique dessus. Ajoutez la ligne suivante au bas de votre JavaScript: +
    link.href = 'https://developer.mozilla.org';
    +
  10. +
+ +
+

Notez que, comme beaucoup de choses en JavaScript, il y a plusieurs façons de sélectionner et récupérer une référence vers un élément dans une variable. {{domxref("Document.querySelector()")}} est l'approche moderne recommandée — elle est pratique puisqu'elle permet de sélectionner des éléments en utilisant les sélecteurs CSS. L'appel à querySelector() que nous avons utilisé plus tôt récupère le premier élément {{htmlelement("a")}} qui apparaît dans le document. Si vous vouliez récupérer plusieurs éléments, vous auriez pu utiliser {{domxref("Document.querySelectorAll()")}}, qui récupère tous les éléments du document qui correspondent au sélecteur, et retourne des références vers ces éléments dans un objet similaire à un tableau appelé un NodeList.

+ +

Il existe des méthodes plus anciennes pour récupérer des références aux éléments, telles que:

+ + + +

Ces deux dernières méthodes fonctionnent même dans les anciens navigateurs, contrairement à querySelector(), mais sont beaucoup moins pratiques. Jetez un coup d'oeil aux docs et essayez d'en trouver d'autres!

+
+ +

Créer et placer de nouveaux noeuds

+ +

Ce qui précède vous a donné un petit avant-goût de ce que vous pouvez faire, mais allons plus loin et regardons comment créer de nouveaux éléments.

+ +
    +
  1. De retour à notre exemple, commençons par récupérer une référence vers notre élément {{htmlelement("section")}} — ajoutez le code suivant au bas de votre script existant (faites de même avec les lignes qui suivront): +
    var sect = document.querySelector('section');
    +
  2. +
  3. Nous allons créer un nouveau paragraphe avec {{domxref("Document.createElement()")}} et lui donner un texte de la même manière que précédemment: +
    var para = document.createElement('p');
    +para.textContent = 'We hope you enjoyed the ride.';
    +
  4. +
  5. Nous pouvons maintenant ajouter ce paragraphe en bas de la section en utilisant {{domxref("Node.appendChild()")}}: +
    sect.appendChild(para);
    +
  6. +
  7. Finallement, ajoutons un noeud texte au premier paragraphe, pour finir la phrase joliment. D'abord, créons un noeud texte avec {{domxref("Document.createTextNode()")}}: +
    var text = document.createTextNode(' — the premier source for web development knowledge.');
    +
  8. +
  9. Puis, après avoir récupéré un référence vers le premier paragraphe, ajoutons-y le noeud texte: +
    var linkPara = document.querySelector('p');
    +linkPara.appendChild(text);
    +
  10. +
+ +

C'est le plus gros de ce dont vous aurez besoin pour ajouter des noeuds au DOM — vous utiliserez beaucoup ces méthodes lorsque vous construirez des interfaces dynamiques (nous verrons quelques exemples plus tard).

+ +

Déplacer des éléments

+ +

Il peut y avoir des moments où vous allez vouloir déplacer des noeuds. Si on voulait déplacer le premier paragraphe au bas de la section, on pourrait faire ça:

+ +
sect.appendChild(linkPara);
+ +

Cela déplace le paragraphe tout au bas de la section. On pourrait penser que cela ajouterait une copie, mais ce n'est pas le cas — linkPara est une référence vers un et un seul élément. Si on voulait ajouter une copie, on devrait utiliser {{domxref("Node.cloneNode()")}} à la place.

+ +

Supprimer des éléments

+ +

Supprimer des éléments est également plutôt simple, du moins quand on a une référence de l'élément et de son parent. Dans notre cas, on peut utiliser {{domxref("Node.removeChild()")}}, comme ceci:

+ +
sect.removeChild(linkPara);
+ +

Vous pourriez aussi vouloir supprimer un élément en n'ayant qu'une référence vers cet élément, et c'est souvent le cas. Il n'existe pas de méthode pour dire à un noeud de se supprimer, vous auriez donc à faire comme suit:

+ +
linkPara.parentNode.removeChild(linkPara);
+ +

Testez les lignes ci-dessus dans votre code.

+ +

Manipuler le style

+ +

Il est possible de manipuler le style CSS JavaScript de plusieurs manières.

+ +

Stylesheets

+ +

Vous pouvez obtenir une liste de toutes les feuilles de style du document en utilisant {{domxref("Document.stylesheets")}}, qui retourne un tableau d'objets {{domxref("CSSStyleSheet")}}. Vous pouvez ainsi ajouter/supprimer des styles comme vous le souhaitez. Cependant, nous n'allons pas nous étendre sur ces fonctionnalités car elles sont archaïques et il est difficule de manipuler le style avec. Il y a des moyens plus simples.

+ +

Propriété style

+ +

La première façon consiste à ajouter des styles en ligne (inline style), directement sur les éléments que vous voulez styler. Pour ce faire, on utilise la propriété {{domxref("HTMLElement.style")}}, qui nous permet d'accéder au style en ligne des éléments du document. Vous pouvez définir les propriétés de cet objet pour mettre à jour directement le style en ligne d'un élément.

+ +
    +
  1. À titre d'exemple, essayez d'ajouter les lignes suivantes au bas de votre JavaScript: +
    para.style.color = 'white';
    +para.style.backgroundColor = 'black';
    +para.style.padding = '10px';
    +para.style.width = '250px';
    +para.style.textAlign = 'center';
    +
  2. +
  3. Rafraichissez la page et vous verrez que les styles ont été appliqués au paragraphe. Si vous regardez le paragraphe dans l'Inspecteur du navigateur, vous verrez que que ces lignes sont en effet ajoutées comme style en ligne au document: +
    <p style="color: white; background-color: black; padding: 10px; width: 250px; text-align: center;">We hope you enjoyed the ride.</p>
    +
  4. +
+ +
+

Note: Notez que les propriétés JavaScript qui représentent les propriétés CSS sont écrites en lower camel case tandis que la version CSS est liée par des tirets (par exemple backgroundColor au lieu de background-color). Assurez-vous de ne pas les mélanger, sans quoi ça ne marchera pas.

+
+ +

Attribut classe

+ +

Il y a un autre moyen de manipuler dynamiquement des styles sur votre document, que nous allons voir maintenant.

+ +
    +
  1. Supprimez l'exemple précédent de votre JavaScript (5 lignes).
  2. +
  3. Ajoutez ce qui suit de le {{htmlelement("head")}} de votre HTML: +
    <style>
    +.highlight {
    +  color: white;
    +  background-color: black;
    +  padding: 10px;
    +  width: 250px;
    +  text-align: center;
    +}
    +</style>
    +
  4. +
  5. Nous allons maintenant utiliser une méthode très utile pour la manipulation HTML de manière générale — {{domxref("Element.setAttribute()")}}. Cette fonction prend deux paramètres, le nom de l'attribut que vous voulez définir sur l'élémént et la valeur que vous voulez lui attribuer. En l'occurence, nous allons définir la classe de l'élément à highlight: +
    para.setAttribute('class', 'highlight');
    +
  6. +
  7. Rafraichissez votre page, et vous pourrez constater qu'il n'y a aucun changement par rapport au dernier exemple. La seule différence est qu'on a utilisé une classe et non des styles en ligne.
  8. +
+ +

La méthode que vous utilisez ne dépend que de vous; chacune a ses avantages et ses inconvénients. Les styles en ligne demandent moins de préparation et sont utiles pour un usage simple, tandis que l'usage des classes est une méthode plus puriste — on ne mélange pas le CSS et le JavaScript. Alors que vous construirez des applications de plus en plus volumineuses et complexes, vous allez probablement utiliser la dernière méthode plus fréquemment, mais c'est à vous de décider.

+ +

À ce stade, nous n'avons pas vraiment fait quoi que soit d'utile! Il n'y a pas d'intérêt à générer du contenu statique avec JavaScript — autant l'écrire directement en HTML et ne pas utiliser JavaScript c'est plus complexe qu'HTML et vient avec quelques inconvénients, comme le fait que ce ne soit pas lisible par les moteurs de recherche.

+ +

Dans les prochaines sections, nous verrons un exemple plus pratique de l'utilisation des APIs du DOM.

+ +
+

Note: Vous pouvez trouver la version finale de dom-example.html sur GitHub (le voir en direct aussi).

+
+ +

Apprentissage actif: Récupérer des informations à partir de l'objet Window

+ +

Jusqu'à présent nous avons utilisé les fonctionnalités de {{domxref("Node")}} et {{domxref("Document")}} (le DOM) pour manipuler les documents, mais vous pouvez obtenir des données d'autres sources. Repensez à notre démo maps-example.html du dernier article — on y récupérait des données de géolocalisation pour afficher une carte de votre région. Vous devez juste vous assurer que vos données sont dans le bon format, et JavaScript rend cette tâche facile par rapport à de nombreux autres langages, puisqu'il est faiblement typé — par exemple, les nombres sont automatiquement convertis en chaîne de caractères quand on veut les afficher à l'écran.

+ +

Dans cet exemple, nous allons résoudre un problème très commun — s'assurer que votre application est de la taille de la fenêtre, quelle que soit la taille de la fenêtre. C'est souvent utilisé pour les jeux, où vous voulez utiliser autant de place à l'écran que vous en avez pour jouer.

+ +
    +
  1. Pour commencer, faites une copie locale des fichiers de démo window-resize-example.html et bgtile.png. Ouvrez le fichier html — vous verrez que nous avons un élément {{htmlelement("div")}} qui recouvre une petite partie de l'écran avec un motif de mosaïques. Nous allons l'utiliser pour représenter la surface de notre interface.
  2. +
  3. Premièrement, nous allons récupérer une référence au <div>, ainsi que la largeur et la hauteur de la fenêtre, et les stocker dans des variables — ces deux dernières valeurs sont faciles à obtenir via les propriétés {{domxref("Window.innerWidth")}} et {{domxref("Window.innerHeight")}}. Ajoutez les lignes qui suivent à l'intérieur de l'élément {{htmlelement("script")}}: +
    var div = document.querySelector('div');
    +var WIDTH = window.innerWidth;
    +var HEIGHT = window.innerHeight;
    +
  4. +
  5. Ensuite, nous allons modifier dynamiquement la largeur et hauteur du <div> pour qu'elles soient égales à celles de la fenêtre. Ajoutez les lignes suivantes à la suite des précédentes: +
    div.style.width = WIDTH + 'px';
    +div.style.height = HEIGHT + 'px';
    +
  6. +
  7. Sauvegardez et rafraichissez votre page — vous devriez désormais voir que le <div> est aussi grand que la fenêtre, quelle qu'en soit la taille. Si maintenant vous essayez d'agrandir votre fenêtre, vous pouvez constater qu'il ne change pas de taille — nous ne définissons la taille qu'une seule fois.
  8. +
  9. Nous pouvons utiliser un gestionnaire d'événément pour que le <div> soit redimensionné à chaque fois que la fenêtre est redimensionnée. L'objet {{domxref("Window")}} a pour ça un événement disponible appelé resize, qui est déclenché lorsque la fenêtre est redimensionnée — nous pouvons utiliser le gestionnaire d'événement {{domxref("Window.onresize")}} pour ré-exécuter notre code de dimensionnement à chaque fois. Ajoutez ce qui suit au bas de votre code: +
    window.onresize = function() {
    +  WIDTH = window.innerWidth;
    +  HEIGHT = window.innerHeight;
    +  div.style.width = WIDTH + 'px';
    +  div.style.height = HEIGHT + 'px';
    +}
    +
  10. +
+ +
+

Note: Vous pouvez trouver notre exemple de redimensionnement de la fenêtre terminé sur Github (voir en direct aussi).

+
+ +

Apprentissage actif: Une liste de courses dynamique

+ +

Pour clore l'article, nous aimerions vous proposer un petit challenge — nous voulons créer une simple liste de courses qui nous permette d'ajouter des items à la liste dynamiquement en utilisant un champ de formulaire et un bouton. Quand vous ajoutez une valeur au champ et appuyez sur le bouton:

+ + + +

La démo terminée doit ressembler à ça:

+ +

+ +

Pour compléter l'exercice, suivez les étapes ci-dessous, et assurez-vous que votre exemple se comporte comme décrit ci-dessus.

+ +
    +
  1. Tout d'abord, téléchargez une copie du fichier shopping-list.html. Vous verrez qu'il contient un peu de CSS, un label, champ et bouton, une liste vide et un élément {{htmlelement("script")}}. Vous devrez apporter toutes vos modifications à l'intérieur du script.
  2. +
  3. Créez trois variables, contenant des références à la liste {{htmlelement("ul")}}, champ {{htmlelement("input")}}, et bouton {{htmlelement("button")}}.
  4. +
  5. Créez une fonction qui est déclenchée lorsqu'on clique sur le bouton.
  6. +
  7. À l'intérieur du corps de la fonction, commencez par stoquer la valeur (propriété value) du champ dans une variable.
  8. +
  9. Ensuite, videz le champ en définissant sa valeur à une chaîne vide — ''.
  10. +
  11. Créez trois nouveaux éléments — un élément de liste {{htmlelement('li')}}, un {{htmlelement('span')}} et {{htmlelement('button')}}, et stockez-les dans des variables.
  12. +
  13. Ajoutez le <span> et <button> comme enfant du <li>.
  14. +
  15. Définissez le contenu du <span> à la valeur du champ que vous avez récupéré précedemment, et définissez le contenu du boutton à "Supprimer".
  16. +
  17. Ajoutez le <li> comme enfant de la liste.
  18. +
  19. Ajoutez un gestionnaire d'événément pour le bouton "Supprimer", pour que quand il est cliqué, le <li> dans lequel il se situe est supprimé.
  20. +
  21. Finalement, utilisez la méthode {{domxref("HTMLElement.focus")}} pour donner le focus au champ, qu'il soit prêt à recevoir la valeur du prochain élément.
  22. +
+ +
+

Note: Si vous êtes vraiment bloqué, vous pouvez regarder notre liste de courses terminée (voir en direct.)

+
+ +

Sommaire

+ +

Nous avons finit de voir la manipulation du document par le DOM. À ce stade, vous devriez comprendre quels sont les composants importants du navigateur web en ce qui concerne le contrôle des documents et l'expérience utilisateur sur le web. Plus important encore, vous devriez comprendre ce qu'est le Document Object Model, et comment l'utiliser pour créer des fonctionnalités utiles.

+ +

Voir aussi

+ +

Il y a beaucoup plus à voir que ce qui est couvert dans cet article. Jetez un coup d'oeil à nos références pour en découvrir davantage:

+ + + +

(Voir notre Référence Web API pour une liste complètes des APIs web documentées sur MDN!)

+ +
{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Introduction", "Learn/JavaScript/Client-side_web_APIs/Fetching_data", "Learn/JavaScript/Client-side_web_APIs")}}
+ +
+

Dans ce module

+ + +
diff --git a/files/fr/learn/javascript/client-side_web_apis/third_party_apis/index.html b/files/fr/learn/javascript/client-side_web_apis/third_party_apis/index.html new file mode 100644 index 0000000000..f8e36b2078 --- /dev/null +++ b/files/fr/learn/javascript/client-side_web_apis/third_party_apis/index.html @@ -0,0 +1,440 @@ +--- +title: API tierces +slug: Apprendre/JavaScript/Client-side_web_APIs/Third_party_APIs +tags: + - API + - Apprendre + - Débutant +translation_of: Learn/JavaScript/Client-side_web_APIs/Third_party_APIs +--- +
{{LearnSidebar}}{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Fetching_data", "Learn/JavaScript/Client-side_web_APIs/Drawing_graphics", "Learn/JavaScript/Client-side_web_APIs")}}
+ +

Jusqu'à présent, nous avons uniquement abordé des API qui sont fournies par le navigateur. Il en existe d'autres : de nombreux sites et services, tels que Google Maps, Twitter, Facebook, PayPal, etc. fournissent des API permettant aux développeurs d'exploiter leurs données (ex. afficher un flux Twitter sur un blog) ou leurs services (utiliser l'outil de connexion Facebook pour que vos utilisateurs se connectent sur votre application). Dans cet article, nous verrons les différences entre les API du navigateur et celles fournies par des services tiers (en anglais, on parle de « third-party API ») et nous illustrerons certains cas d'usage pour ces API tierces.

+ + + + + + + + + + + + +
Prérequis :Les bases de JavaScript (voir premiers pas, blocs de construction, les objets JavaScript), les bases des API côté client.
Objectifs :Comprendre le fonctionnement des API tierces et comment les utiliser pour ajouter des fonctionnalités à ses sites / applications.
+ +

Qu'est-ce qu'une API tierce ?

+ +

Les API tierces sont des API qui sont fournis par des tiers, généralement des entreprises comme Facebook, Twitter ou Google, qui permettent d'accéder à leurs données et/ou leurs fonctionnalités grâce à JavaScript afin de les utiliser sur son site. Utiliser une API de cartographie afin d'afficher une carte sur une page est un exemple.

+ +

Regardons cet exemple qui utilise l'API MapQuest et voyons avec lui les différences entre les API tierces et celles du navigateur.

+ +
+

Note : Vous pouvez récupérer l'ensemble des exemples de code en une seule fois. Dans ce cas, il vous suffit de rechercher dans votre dépôt les fichiers utilisés pour chaque section.

+
+ +

Elles sont situées sur des serveurs tiers

+ +

Les API fournies par le navigateur sont construites dans le navigateur et on peut y accéder immédiatement avec du code JavaScript. Ainsi, l'API Web Audio que nous avons vu dans cet article introductif s'utilise via l'objet {{domxref("AudioContext")}} fourni nativement :

+ +
const audioCtx = new AudioContext();
+  ...
+const audioElement = document.querySelector('audio');
+  ...
+const audioSource = audioCtx.createMediaElementSource(audioElement);
+// etc.
+ +

En revanche, les API tierces sont situées sur des serveurs tiers. Pour y accéder avec JavaScript, il faut d'abord se connecter aux fonctionnalités de l'API afin de les rendre disponibles sur la page. Pour cela, on pourra utiliser une bibliothèque JavaScript disponible sur le serveur via un élément {{htmlelement("script")}}. Pour notre exemple avec MapQuest, voici ce que ça donne :

+ +
<script src="https://api.mqcdn.com/sdk/mapquest-js/v1.3.2/mapquest.js"></script>
+<link type="text/css" rel="stylesheet" href="https://api.mqcdn.com/sdk/mapquest-js/v1.3.2/mapquest.css"/>
+ +

On peut alors utiliser les objets fournis par cette bibliothèque. Voici un fragment de code qui illustre cette utilisation :

+ +
var L;
+
+var map = L.mapquest.map('map', {
+  center: [53.480759, -2.242631],
+  layers: L.mapquest.tileLayer('map'),
+  zoom: 12
+});
+ +

Ici on crée une variable dans laquelle enregistrer les informations de la carte puis on crée une nouvelle carte à l'aide de la méthode mapquest.map() qui prend comme argument :

+ + + +

C'est tout ce dont l'API MapQuest a besoin pour dessiner une carte. C'est le serveur auquel on se connecte qui gère les aspects plus compliqués (comme afficher les bonnes tuiles pour la zone géographique, etc.).

+ +
+

Note : Certaines API fonctionnent différemment pour l'accès aux fonctionnalités et passent par une requête HTTP sur une URL spécifique pour récupérer les données. Ces API sont appelées API REST (ou RESTful APIs en anglais) et nous les abordons plus bas dans l'article.

+
+ +

Des clés d'API sont nécessaires pour les utiliser

+ +

Dans les navigateurs, comme nous l'avons vu dans le premier article, les sécurités relatives aux API sont gérées via des permissions afin d'avertir l'utilisateur et d'éviter les utilisations malveillantes de la part des sites.

+ +

Pour les API tierces, le système est légèrement différent. Généralement, ce sont des clés qui sont utilisées afin de fournir aux développeurs l'accès aux fonctionnalités de l'API. Dans ce système, la clé sert plutôt à protéger des abus de la part des développeurs envers le site tiers.

+ +

Dans l'exemple MapQuest, vous pourrez trouver une ligne semblable à celle-ci :

+ +
L.mapquest.key = 'VOTRE-CLE-D-API-ICI';
+ +

Cette ligne indique une clé d'API utilisée par notre application. Le développeur de l'application doit obtenir une clé et l'inclure dans le code de l'application afin de pouvoir accéder aux fonctionnalités de l'API. Pour cet exemple, il s'agit d'une valeur imaginaire.

+ +
+

Note : Lorsque vous construisez votre propre application, utilisez une « vraie » valeur de clé plutôt que la valeur de substitution fournie en exemple.

+
+ +

Certaines API peuvent nécessiter de fournir la clé d'une façon différente mais le fonctionnement général reste similaire.

+ +

L'existence d'une telle clé d'API permet au fournisseur tiers de contrôler les accès et actions des différents développeurs/utilisateurs. Ainsi, lorsqu'un développeur demande une clé, il devient alors connu du fournisseur de l'API et ce dernier peut agir de son côté si l'API est détournée ou utilisée de façon incorrecte (par exemple pour pister des personnes ou parce que le site du développeur sollicite l'API avec de trop nombreuses requêtes). Dès qu'un usage incorrect est détecté du côté du fournisseur, il suffit alors de révoquer l'accès et de couper ou de limiter les accès pour cette clé.

+ +

Étendre l'exemple « MapQuest »

+ +

Ajoutons quelques fonctionnalités à cet exemple MapQuest afin d'illustrer le fonctionnement d'autres aspects de l'API.

+ +
    +
  1. +

    Pour commencer cette section, copiez le fichier initial dans un nouveau répertoire. Si vous avez déjà cloné le dépôt des exemples, vous disposez déjà d'une copie située sous le répertoire javascript/apis/third-party-apis/mapquest.

    +
  2. +
  3. +

    Ensuite, rendez-vous sur le site MapQuest pour les développeurs, créez un compte puis créez une clé de développement (au moment où nous écrivons ces lignes, sur le site, le nom utilisé est "consumer key" et la procédure de création demande aussi la saisie d'une URL "callback URL" qui est optionnelle (vous pouvez la laisser vide).

    +
  4. +
  5. Ouvrez un éditeur pour éditer le fichier initial et remplacez la valeur pour la clé d'API avec la vôtre.
  6. +
+ +

Modifier le type de la carte

+ +

L'API MapQuest permet d'afficher différents types de carte. Localisez la ligne suivante dans votre fichier :

+ +
layers: L.mapquest.tileLayer('map')
+ +

Ici, vous pouvez changer 'map' en 'hybrid' afin d'afficher une carte avec un style hybride. Vous pouvez essayer d'autres valeurs comme celles indiquées sur la page de référence de la méthode tileLayer().

+ +

Ajouter différents contrôles

+ +

Sur la carte, on peut utiliser différents contrôles. Par défaut, seul un contrôle pour le zoom est affiché. Il est possible d'étendre les contrôles disponibles en utilisant la méthodemap.addControl(). Ajoutez la ligne suivante à l'intérieur du gestionnaire window.onload :

+ +
map.addControl(L.mapquest.control());
+ +

La méthode mapquest.control() crée un ensemble complet de contrôle et est placée, par défaut, dans le coin supérieur droit de la carte. Cette position peut être ajustée grâce à un paramètre d'options contenant une propriété position dont la valeur est un mot-clé décrivant la position souhaitée. Vous pouvez modifier la ligne de la façon suivante par exemple :

+ +
  map.addControl(L.mapquest.control({ position: 'bottomright' }));
+ +

D'autres types de contrôle sont disponibles comme mapquest.searchControl() et mapquest.satelliteControl(). Certains sont avancés et permettent de nombreuses choses. N'hésitez pas à en essayer différents pour voir ce qui vous semble le mieux pour votre projet.

+ +

Ajouter un marqueur personnalisé

+ +

Pour ajouter une icône sur un point de la carte, on pourra utiliser la méthode L.marker()  (documentée dans la documentation de Leaflet.js). Dans window.onload, vous pouvez ajouter le fragment de code suivante window.onload :

+ +
L.marker([53.480759, -2.242631], {
+  icon: L.mapquest.icons.marker({
+    primaryColor: '#22407F',
+    secondaryColor: '#3B5998',
+    shadow: true,
+    size: 'md',
+    symbol: 'A'
+  })
+})
+.bindPopup('Ici se trouve Manchester !')
+.addTo(map);
+ +

Comme on peut le voir ici, la méthode peut prendre deux paramètres :

+ + + +

L'icône est définie via un appel à la méthode mapquest.icons.marker() à laquelle on fournit des informations telles que la couleur et la taille du marqueur.

+ +

Après l'appel à la première méthode, on enchaîne avec un appel avec .bindPopup('Ici se trouve Manchester !'), qui fournit le contenu à afficher lorsqu'on cliquera sur le marqueur.

+ +

Enfin, on chaîne un appel .addTo(map) pour ajouter le marqueur sur la carte.

+ +

Essayez les différentes options que vous trouverez dans la documentation et voyez quel résultat vous pouvez obtenir ! MapQuest fournit certaines fonctionnalités relativement avancées (itinéraire, recherche, etc.).

+ +
+

Note : Si vous ne parvenez pas à faire fonctionner l'exemple, vous pouvez consulter la version finalisée de notre exemple : expanded-example.html.

+
+ +

Quid de Google Maps ?

+ +

Google Maps est sans doute l'API de cartographie la plus populaire. Pourquoi ne l'avons-nous pas incluse ici ? Nous avons choisi MapQuest pour plusieurs raisons :

+ + + +

Une approche pour utiliser les API tierces

+ +

Une API REST du NYTimes

+ +

Prenons un autre exemple d'API, l'API du New York Times. Cette API permet de récupérer les informations provenant du New York Times et de les afficher sur votre site. Cette API est ce qu'on appelle une API REST car elle permet de récupérer des données via des requêtes HTTP sur des URL spécifiques dans lesquelles on peut fournir des données comme des termes de recherches (souvent encodés comme paramètres dans l'URL). Ce type d'API est relativement fréquent.

+ +

Construisons un second exemple pour comprendre comment utiliser l'API du NYTimes. Au fur et à mesure nous décrirons également une approche plus générale pour consommer d'autres API tierces.

+ +

Trouver la documentation

+ +

Lorsqu'on veut utiliser une API tierce, il est toujours utile de trouver la documentation correspondante pour connaître les fonctionnalités offertes, comment les utiliser, etc. La documentation de l'API du New York Times API se situe ici : https://developer.nytimes.com/.

+ +

Obtenir une clé de développement

+ +

La plupart des API reposent sur l'obtention et l'utilisation d'une clé de développement (tant pour des raisons de sécurité que de responsabilité). Pour obtenir une clé de développement pour l'API du NYTimes, vous pouvez suivre les instructions de https://developer.nytimes.com/get-started.

+ +
    +
  1. +

    Demandez une clé pour l'API Article Search — créez une nouvelle application et sélectionnez cette API, fournissez un nom et une description pour votre application, activez le bouton sous "Article Search API" puis cliquez sur "Create").

    +
  2. +
  3. +

    Vous pouvez alors récupérer la clé d'API à partir de la page suivante.

    +
  4. +
  5. +

    Pour construire le socle de notre exemple, copiez nytimes_start.html et nytimes.css dans un nouveau répertoire sur votre ordinateur. Si vous avez déjà cloné le dépôt des exemples, vous disposez déjà d'un exemplaire de ces fichiers et vous pourrez les trouver sous le répertoire javascript/apis/third-party-apis/nytimes. L'élément <script> contient un certain nombre de variables nécessaires à l'initialisation de l'exemple. Nous allons ensuite remplir les fonctionnalités nécessaires.

    +
  6. +
+ +

Au final, on souhaite que l'application permette de saisir un terme de recherche, des dates optionnelles pour le début et la fin de la période à rechercher. Nous utiliserons alors ces paramètres afin de d'envoyer des requêtes sur l'API Article Search puis nous afficherons les résultats obtenus.

+ +

+ +

Connecter l'API à son application

+ +

Tout d'abord, vous devrez créer une connexion entre l'API et votre application. Pour cette API, vous devez fournir la clé d'API comme paramètre GET à chaque requête.

+ +
    +
  1. +

    Localisez la ligne qui suit et remplacez la valeur avec la clé de développement que vous avez obtenu plus tôt :

    + +
    var key = ' ... ';
    +
  2. +
  3. +

    Ajoutez la ligne suivante sous le commentaire // Event listeners to control the functionality. Cette ligne permet d'exécuter la fonction submitSearch() lorsque le formulaire est envoyé (quand on presse le bouton).

    + +
    searchForm.addEventListener('submit', submitSearch);
    +
  4. +
  5. +

    Sous cette nouvelle ligne, ajoutons les fonctions submitSearch() et fetchResults() :

    + +
    function submitSearch(e) {
    +  pageNumber = 0;
    +  fetchResults(e);
    +}
    +
    +function fetchResults(e) {
    +  // On utilise preventDefault() afin d'éviter
    +  // l'envoie vers notre serveur et le rafraîchissement
    +  // de la page
    +  e.preventDefault();
    +
    +  // On compose l'URL
    +  url = baseURL + '?api-key=' + key + '&page=' + pageNumber + '&q=' + searchTerm.value + '&fq=document_type:("article")';
    +
    +  if(startDate.value !== '') {
    +    url += '&begin_date=' + startDate.value;
    +  };
    +
    +  if(endDate.value !== '') {
    +    url += '&end_date=' + endDate.value;
    +  };
    +
    +}
    +
  6. +
+ +

submitSearch() commence par réinitialiser le nombre de page à 0 puis appelle fetchResults(). Cette fonction commence par appeler preventDefault() sur l'évènement afin d'empêcher l'envoi du formulaire vers notre serveur (ce qui casserait l'exemple). Ensuite, on assemble la chaîne de caractères qui formera l'URL sur laquelle on fera la requête. Dans cette URL, on commence par mettre les fragments « obligatoires » (en tout cas pour cette démonstration) :

+ + + +

Après, on utilise un ensemble d'instructions if() pour vérifier si des valeurs ont été fournies pour les champs startDate et endDate dans le formulaire. Si c'est le cas, on utilise ces valeurs pour renseigner les paramètres d'URL begin_date et/ou end_date.

+ +

Si on prend un exemple d'URL complète ainsi construite :

+ +
https://api.nytimes.com/svc/search/v2/articlesearch.json?api-key=YOUR-API-KEY-HERE&page=0&q=cats
+&fq=document_type:("article")&begin_date=20170301&end_date=20170312 
+ +
+

Note : Pour en savoir plus sur les différents paramètres d'URL qui peuvent être utilisés, vous pouvez consulter la documentation du NYTimes.

+
+ +
+

Note : Dans cet exemple, la validation du formulaire est assez rudimentaire : le terme recherché doit nécessairement être renseigné avant de pouvoir valider le formulaire grâce à l'attribut required. Les champs pour les dates doivent suivre un format particulier et elles ne seront pas envoyées tant que leur valeur ne se composera pas de 8 chiffres (en HTML, c'est ce qui est indiqué par l'attribut pattern="[0-9]{8}"). Voir la page sur la validation des données d'un formulaire pour en savoir plus sur ce fonctionnement.

+
+ +

Récupérer des données depuis l'API

+ +

Maintenant que nous avons construit notre URL, envoyons une requête à cet endroit. Pour cela, nous utiliserons l'API Fetch.

+ +

Dans la fonction fetchResults(), juste avant l'accolade de fin, ajoutez le fragment de code suivant :

+ +
// On utilise fetch() pour envoyer la requête à l'API
+fetch(url).then(function(result) {
+  return result.json();
+}).then(function(json) {
+  displayResults(json);
+});
+ +

On envoie la requête en passant la variable url comme paramètre à la fonction fetch() puis on convertit le corps de la réponse avec la fonction json() puis on passe le JSON ainsi obtenu à la fonction displayResults() afin que les données puissent être affichées dans l'interface utilisateur.

+ +

Afficher les données

+ +

Voyons maintenant comment afficher les données reçues. Dans le fichier contenant votre code, ajoutez la fonction suivante après la fonction fetchResults().

+ +
function displayResults(json) {
+  while (section.firstChild) {
+      section.removeChild(section.firstChild);
+  }
+
+  var articles = json.response.docs;
+
+  if(articles.length === 10) {
+    nav.style.display = 'block';
+  } else {
+    nav.style.display = 'none';
+  }
+
+  if(articles.length === 0) {
+    var para = document.createElement('p');
+    para.textContent = 'Aucun résultat reçu.'
+    section.appendChild(para);
+  } else {
+    for(var i = 0; i < articles.length; i++) {
+      var article = document.createElement('article');
+      var heading = document.createElement('h2');
+      var link = document.createElement('a');
+      var img = document.createElement('img');
+      var para1 = document.createElement('p');
+      var para2 = document.createElement('p');
+      var clearfix = document.createElement('div');
+
+      var current = articles[i];
+      console.log(current);
+
+      link.href = current.web_url;
+      link.textContent = current.headline.main;
+      para1.textContent = current.snippet;
+      para2.textContent = 'Mots-clés : ';
+      for(var j = 0; j < current.keywords.length; j++) {
+        var span = document.createElement('span');
+        span.textContent += current.keywords[j].value + ' ';
+        para2.appendChild(span);
+      }
+
+      if(current.multimedia.length > 0) {
+        img.src = 'http://www.nytimes.com/' + current.multimedia[0].url;
+        img.alt = current.headline.main;
+      }
+
+      clearfix.setAttribute('class','clearfix');
+
+      article.appendChild(heading);
+      heading.appendChild(link);
+      article.appendChild(img);
+      article.appendChild(para1);
+      article.appendChild(para2);
+      article.appendChild(clearfix);
+      section.appendChild(article);
+    }
+  }
+}
+ +

Il y a pas mal de code ici. Reprenons étape par étape pour l'expliquer :

+ + + +

Câbler les boutons pour la pagination

+ +

Pour que les boutons de pagination fonctionnent, on incrémente (ou on décrémente) la valeur de la variable pageNumber puis on renvoie une requête avec la nouvelle valeur incluse dans le paramètre de l'URL page. Cela fonctionne car l'API du NYTimes ne renvoie que 10 résultats à la fois. S'il y a plus de 10 résultats disponibles, la requête renverra les 10 premiers (0 à 9) lorsque le paramètre page vaut 0 dans l'URL (ou lorsqu'il n'est pas inclus du tout, c'est la valeur par défaut). Les 10 prochains résultats (10 à 19) peuvent être récupérés lorsque le paramètre page vaut 1 et ainsi de suite.

+ +

En connaissant cela, on peut écrire une fonction pour gérer la pagination.

+ +
    +
  1. +

    Après l'appel existant à addEventListener(), on ajoute les deux prochaines lignes qui appelleront les fonctions nextPage() et previousPage() lorsqu'on cliquera sur le bouton correspondant :

    + +
    nextBtn.addEventListener('click', nextPage);
    +previousBtn.addEventListener('click', previousPage);
    +
  2. +
  3. +

    À la suite, on définit le corps de ces fonctions :

    + +
    function nextPage(e) {
    +  pageNumber++;
    +  fetchResults(e);
    +};
    +
    +function previousPage(e) {
    +  if(pageNumber > 0) {
    +    pageNumber--;
    +  } else {
    +    return;
    +  }
    +  fetchResults(e);
    +};
    + +

    La première fonction est assez simple : on incrémente la variable pageNumber puis on exécute à nouveau la fonction fetchResults() afin d'afficher les prochains résultats.

    + +

    La seconde fonction est similaire, mais on prend la précaution de vérifier que pageNumber ne vaut pas déjà 0 avant de diminuer sa valeur (si la requête est envoyée avec un paramètre négatif, on pourrait avoir une erreur). Lorsque pageNumber vaut déjà 0, on sort de la fonction avec return afin d'éviter de lancer une requête pour rien (si on est déjà sur la première page, pas besoin de recharger les résultats à nouveau).

    +
  4. +
+ +
+

Note : Vous pouvez trouver l'exemple complet sur l'API du NYTimes sur GitHub.

+
+ +

Exemple d'utilisation de l'API YouTube

+ +

Nous avons également mis à disposition un autre exemple que vous pouvez étudier et adapter : exemple de recherche de vidéo YouTube. Dans cet exemple, on utilise deux API :

+ + + +

Cet exemple est intéressant car il permet d'illustrer l'utilisation combinée de deux API tierces pour construire une application. La première API est une API REST tandis que la seconde est plus proche du fonctionnement de MapQuest (des méthodes spécifiques à l'API, etc.). On notera que les deux API ont besoin qu'une bibliothèque JavaScript soit chargée sur la page. L'API REST possède des fonctions qui permettent de gérer les requêtes HTTP et de renvoyer les résultats.

+ +

+ +

Nous n'allons pas détailler plus encore cet exemple ici, vous pouvez consulter le code source qui contient des commentaires expliquant son fonctionnement. Là encore, pour utiliser vous-même l'exemple, vous aurez besoin de récupérer une clé d'API et de l'insérer dans le code afin que les exemples fonctionnent.

+ +

Résumé

+ +

Dans cet article, nous avons vu une introduction à l'utilisation des API tierces afin d'ajouter des fonctionnalités à nos sites web.

+ +

{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Fetching_data", "Learn/JavaScript/Client-side_web_APIs/Drawing_graphics", "Learn/JavaScript/Client-side_web_APIs")}}

+ +

Dans ce module

+ + diff --git a/files/fr/learn/javascript/client-side_web_apis/video_and_audio_apis/index.html b/files/fr/learn/javascript/client-side_web_apis/video_and_audio_apis/index.html new file mode 100644 index 0000000000..358458db64 --- /dev/null +++ b/files/fr/learn/javascript/client-side_web_apis/video_and_audio_apis/index.html @@ -0,0 +1,518 @@ +--- +title: APIs vidéo et audio +slug: Apprendre/JavaScript/Client-side_web_APIs/Video_and_audio_APIs +tags: + - API + - Apprendre + - Article + - Audio + - Codage + - Débutant + - Guide + - JavaScript + - Video +translation_of: Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Drawing_graphics", "Learn/JavaScript/Client-side_web_APIs/Client-side_storage", "Learn/JavaScript/Client-side_web_APIs")}}
+ +

HTML5 fournit des éléments pour intégrer du multimédia dans les documents — {{htmlelement("video")}} et {{htmlelement("audio")}} — et qui viennent avec leurs propres APIs pour contrôler la lecture, se déplacer dans le flux, etcCet article montre comment réaliser les tâches les plus communes, comme créer des contrôles de lectures personnalisés.

+ + + + + + + + + + + + +
Prérequis:Les bases du JavaScript (voir premiers pas en JavaScript, les briques Javascript, Introduction aux objets), Introduction aux APIs web
Objectif:Apprendre à utiliser les APIs du navigateur pour contrôler la lecture de audio et vidéo.
+ +

Les balises HTML5 video et audio

+ +

Les balises {{htmlelement("video")}} et {{htmlelement("audio")}} permettent d'intégrer des vidéos et de l'audio dans des pages web. Comme nous l'avons montré dans Contenu audio et vidéo, une implémentation habituelle ressemble à ça :

+ +
<video controls>
+  <source src="rabbit320.mp4" type="video/mp4">
+  <source src="rabbit320.webm" type="video/webm">
+  <p>Votre navigateur ne supporte pas la vidéo HTML5. Voici à la place <a href="rabbit320.mp4">un lien vers la vidéo</a>.</p>
+</video>
+ +

Cela crée un lecteur vidéo à l'intérieur du navigateur:

+ +

{{EmbedGHLiveSample("learning-area/html/multimedia-and-embedding/video-and-audio-content/multiple-video-formats.html", '100%', 380)}}

+ +

Vous pouvez consulter toutes fonctionnalités HTML audio et vidéo dans l'article mentionné précédemment. Pour notre utilisation ici, l'attribut le plus intéressant est {{htmlattrxref("controls", "video")}}. Il permet d'activer l'ensemble des contrôles de lecture par défaut; si vous ne le spécifiez pas, vous aucun contrôle ne sera affiché:

+ +

{{EmbedGHLiveSample("learning-area/html/multimedia-and-embedding/video-and-audio-content/multiple-video-formats-no-controls.html", '100%', 380)}}

+ +

Ce n'est pas immédiatement utile pour la lecture de vidéos, mais ça a des avantages. Les contrôles natifs des navigateurs différent complètement d'un navigateur à l'autre — ce qui est embêtant pour un support global des différents navigateurs. Un autre problème est que le contrôles natifs sont généralement assez peu accessibles au clavier.

+ +

Vous pouvez régler ces deux problèmes en cachant les contrôles natifs (en supprimant l'attribut controls) et en les remplaçant par les votres en HTML, CSS et JavaScript. Dans la prochaine section, nous verrons les outils de base à notre disposition pour faire ça.

+ +

L'API HTMLMediaElement

+ +

L'API {{domxref("HTMLMediaElement")}}, spécifiée dans HTML5, fournit des fonctionnalités qui permettent de controller des lecteurs audio et vidéo avec JavaScript — avec par exemple {{domxref("HTMLMediaElement.play()")}} ou encore {{domxref("HTMLMediaElement.pause()")}}. Cette interface est disponible à la fois pour les balises {{htmlelement("audio")}} et {{htmlelement("video")}}, les fonctionnalités utiles pour les deux étant quasiment identiques. Voyons un exemple pour découvrir ces fonctionnalités.

+ +

Notre exemple final ressemblera (et fonctionnera) comme ceci:

+ +

{{EmbedGHLiveSample("learning-area/javascript/apis/video-audio/finished/", '100%', 360)}}

+ +

Débuter

+ +

Pour commencer avec cet exemple, télechargez notre media-player-start.zip et décompressez-le dans un nouveau dossier sur votre disque dur. Si vous avez téléchargé notre dépôt d'exemples, vous le trouverez dans javascript/apis/video-audio/start/.

+ +

Si vous ouvrez la page HTML, vous devriez voir un lecteur HTML5 utilisant les contrôles natifs.

+ +

Exploration du HTML

+ +

Ouvrez le fichier HTML d'index. Vous allez voir que le HTML contient majoritairement du code pour le lecteur et ses contrôles:

+ +
<div class="player">
+  <video controls>
+    <source src="video/sintel-short.mp4" type="video/mp4">
+    <source src="video/sintel-short.mp4" type="video/webm">
+    <!-- fallback contenu ici -->
+  </video>
+  <div class="controls">
+    <button class="play" data-icon="P" aria-label="bascule lecture pause"></button>
+    <button class="stop" data-icon="S" aria-label="stop"></button>
+    <div class="timer">
+      <div></div>
+      <span aria-label="timer">00:00</span>
+    </div>
+    <button class="rwd" data-icon="B" aria-label="retour arrière"></button>
+    <button class="fwd" data-icon="F" aria-label="avance rapide"></button>
+  </div>
+</div>
+
+ + + +

Exploration du CSS

+ +

Maintenant, ouvrez le fichier CSS et jetez-y un coup d'oeil. Le CSS pour cet exemple n'est pas très compliqué, mais nous allons voir les éléments les plus intéressants ici. Tout d'abord, le style de .controls:

+ +
.controls {
+  visibility: hidden;
+  opacity: 0.5;
+  width: 400px;
+  border-radius: 10px;
+  position: absolute;
+  bottom: 20px;
+  left: 50%;
+  margin-left: -200px;
+  background-color: black;
+  box-shadow: 3px 3px 5px black;
+  transition: 1s all;
+  display: flex;
+}
+
+.player:hover .controls, player:focus .controls {
+  opacity: 1;
+}
+
+ + + +

Ensuite, voyons les icônes des boutons:

+ +
@font-face {
+   font-family: 'HeydingsControlsRegular';
+   src: url('fonts/heydings_controls-webfont.eot');
+   src: url('fonts/heydings_controls-webfont.eot?#iefix') format('embedded-opentype'),
+        url('fonts/heydings_controls-webfont.woff') format('woff'),
+        url('fonts/heydings_controls-webfont.ttf') format('truetype');
+   font-weight: normal;
+   font-style: normal;
+}
+
+button:before {
+  font-family: HeydingsControlsRegular;
+  font-size: 20px;
+  position: relative;
+  content: attr(data-icon);
+  color: #aaa;
+  text-shadow: 1px 1px 0px black;
+}
+ +

Tout d'abord, en haut du CSS, nous utilisons un bloc {{cssxref("@font-face")}} pour importer une police web personnalisée. Il s'agit d'une police d'icônes — tous les caractères de l'alphabet correspondent à des icônes que vous pouvez utiliser dans votre application.

+ +

Ensuite, nous générons du contenu pour afficher une icône sur chaque bouton:

+ + + +

Les polices d'icônes sont très cool pour de nombreuses raisons: réduire les requêtes HTTP (puisque vous n'avez pas besoin de télécharger des icônes sous forme de fichiers image), bonne scalabilité, et le fait que vous pouvez utiliser les propriétés de texte pour les formatter — comme {{cssxref("color")}} et {{cssxref("text-shadow")}}.

+ +

Dernier point mais non des moindres, le CSS du décompte:

+ +
.timer {
+  line-height: 38px;
+  font-size: 10px;
+  font-family: monospace;
+  text-shadow: 1px 1px 0px black;
+  color: white;
+  flex: 5;
+  position: relative;
+}
+
+.timer div {
+  position: absolute;
+  background-color: rgba(255,255,255,0.2);
+  left: 0;
+  top: 0;
+  width: 0;
+  height: 38px;
+  z-index: 2;
+}
+
+.timer span {
+  position: absolute;
+  z-index: 3;
+  left: 19px;
+}
+ + + +

Implémenter le JavaScript

+ +

Nous avons déjà une interface HTML et CSS assez complète; nous avons maintenant besoin de gérer les boutons pour que les contrôles fonctionnent.

+ +
    +
  1. +

    Créez un nouveau fichier JavaScript dans le même répertoire que votre fichier index.html. Nous l'appelerons custom-player.js.

    +
  2. +
  3. +

    En haut de ce fichier, insérez le code suivant:

    + +
    var media = document.querySelector('video');
    +var controls = document.querySelector('.controls');
    +
    +var play = document.querySelector('.play');
    +var stop = document.querySelector('.stop');
    +var rwd = document.querySelector('.rwd');
    +var fwd = document.querySelector('.fwd');
    +
    +var timerWrapper = document.querySelector('.timer');
    +var timer = document.querySelector('.timer span');
    +var timerBar = document.querySelector('.timer div');
    +
    + +

    Ici, nous créons des variables pour stocker les références de tous les objets que nous voulons manipuler. Nous avons trois groupes:

    + +
      +
    • L'élément <video>, et la barre de contrôle.
    • +
    • Les boutons play/pause, stop, retour arrière, et avance rapide.
    • +
    • Le <div> externe, le <span> qui décompte le temps écoulé, et le <div> interne qui affiche le progrès de la vidéo.
    • +
    +
  4. +
  5. +

    Ensuite, insérez ce qui suit en bas de votre code:

    + +
    media.removeAttribute('controls');
    +controls.style.visibility = 'visible';
    + +

    Ces deux lignes suppriment les contrôles par défaut du navigateur sur la vidéo, et rendent nos contrôles personnalisés visibles.

    +
  6. +
+ +

Lecture et pause de la vidéo

+ +

Imlémentons le contrôle le plus important — le bouton play/pause.

+ +
    +
  1. +

    Tout d'abord, ajoutez ce qui suit au bas de votre code, pour que la fonction playPauseMedia() soit invoquée quand le bouton play est cliqué:

    + +
    play.addEventListener('click', playPauseMedia);
    +
    +
  2. +
  3. +

    Maintenant, définissons playPauseMedia() — ajoutez ce qui suit, toujours au bas de votre code:

    + +
    function playPauseMedia() {
    +  if(media.paused) {
    +    play.setAttribute('data-icon','u');
    +    media.play();
    +  } else {
    +    play.setAttribute('data-icon','P');
    +    media.pause();
    +  }
    +}
    + +

    Ici, nous utilisons une instruction if pour vérifier si la vidéo est en pause. La propriété {{domxref("HTMLMediaElement.paused")}} retourne vrai si le média est en pause — c'est le cas quand la vidéo n'est pas en cours de lecture, y compris quand la vidéo est au début après son chargement. Si elle est en pause, nous définissons la valeur de l'attribut data-icon à "u", qui est une icône "en pause", et invoquons la  méthode {{domxref("HTMLMediaElement.play()")}} pour jouer le média.

    + +

    Au second clic, le bouton sera de nouveau alterné — l'icône "play" sera affiché, et la vidéo sera mise en pause avec {{domxref("HTMLMediaElement.paused()")}}.

    +
  4. +
+ +

Stopper la vidéo

+ +
    +
  1. +

    Ajoutons la possibilité d'arrêter la vidéo. Ajoutez les lignes addEventListener() suivantes au-dessous de vos ajouts précédents:

    + +
    stop.addEventListener('click', stopMedia);
    +media.addEventListener('ended', stopMedia);
    +
    + +

    L'événement {{event("click")}} est explicite — nous voulons stopper la vidéo en appelant la fonction stopMedia() quand le bouton stop est cliqué. Cependant, nous voulons également stopper la vidéo quand elle a fini de jouer — signalé par l'événement {{event("ended")}}, nous pouvons donc mettre en place un gestionnaire d'événement pour exécuter la fonction quand cet événément se produit.

    +
  2. +
  3. +

    Ensuite, définissons stopMedia() — ajoutez ce qui suit après la fonction playPauseMedia():

    + +
    function stopMedia() {
    +  media.pause();
    +  media.currentTime = 0;
    +  play.setAttribute('data-icon','P');
    +}
    +
    + +

    Il n'y a pas de méthode stop() dans l'API  HTMLMediaElement — l'équivalent du stop est de mettre pause() sur la vidéo, et de définir la propriété {{domxref("HTMLMediaElement.currentTime","currentTime")}} à 0. Définir une valeur à currentTime (en secondes) change immédiatement la position du temps du média.

    + +

    Tout ce qui nous reste à faire après ça est d'afficher l'icône "play". Que la vidéo ait été en train de jouer ou en pause, quand le bouton stop est pressé, vous voulez qu'elle doit prête à être lue.

    +
  4. +
+ +

Retour arrière et avance rapide

+ +

Il y a différentes manières d'implémenter le retour arrière et l'avance rapide; ici, nous vous montrons une manière relativement complexe de le faire, qui n'a pas de comportement inattendu quand différents boutons sont pressés dans un ordre aléatoire.

+ +
    +
  1. +

    Tout d'abord, ajoutez les lignes addEventListener() suivantes à la suite des précédentes:

    + +
    rwd.addEventListener('click', mediaBackward);
    +fwd.addEventListener('click', mediaForward);
    +
    +
  2. +
  3. +

    Maintenant, occupons-nous des fonctions des gestionnaires d'événément — ajoutez le code suivant à la suite des fonctions précédentes pour définir mediaBackward() et mediaForward():

    + +
    var intervalFwd;
    +var intervalRwd;
    +
    +function mediaBackward() {
    +  clearInterval(intervalFwd);
    +  fwd.classList.remove('active');
    +
    +  if(rwd.classList.contains('active')) {
    +    rwd.classList.remove('active');
    +    clearInterval(intervalRwd);
    +    media.play();
    +  } else {
    +    rwd.classList.add('active');
    +    media.pause();
    +    intervalRwd = setInterval(windBackward, 200);
    +  }
    +}
    +
    +function mediaForward() {
    +  clearInterval(intervalRwd);
    +  rwd.classList.remove('active');
    +
    +  if(fwd.classList.contains('active')) {
    +    fwd.classList.remove('active');
    +    clearInterval(intervalFwd);
    +    media.play();
    +  } else {
    +    fwd.classList.add('active');
    +    media.pause();
    +    intervalFwd = setInterval(windForward, 200);
    +  }
    +}
    +
    + +

    Vous remarquerez que nous commençons par initialiser deux variables — intervalFwd et intervalRwd — vous verrez à quoi elles servent plus tard.

    + +

    Voyons pas à pas mediaBackward() (mediaForward() fait la même chose, mais dans l'autre sens):

    + +
      +
    1. Nous effaçons les classes et intervales qui sont définits sur la fonctionnalité d'avance rapide — de cette manière, si on presse le bouton rwd après avoir pressé le bouton fwd, on annule l'avance rapide et la remplaçons avec le retour arrière. Si on essayait de faire les deux à la fois, le lecteur échouerait.
    2. +
    3. Nous utilisons une instruction if pour vérifier si la classe active a été définie sur le bouton rwd, ce qui indique qu'il a déjà été pressé. La propriété {{domxref("classList")}} est une propriété plutôt pratique qui existe sur chaque élément — elle contient une liste de toutes les classes définies sur l'élément, ainsi que des méthodes pour en ajouter/supprimer, etc. Nous utilisons la méthode classList.contains() pour vérifier si la liste contient la classe active. Cela retourne un booléen true/false en résultat.
    4. +
    5. Si la classe active a été définie sur le bouton rwd, nous la supprimons avec classList.remove(), effaçons l'intervale qui a été définit sur le bouton quand il a été pressé (voir ci-dessous pour plus d'explication), et utilisons {{domxref("HTMLMediaElement.play()")}} pour annuler le retour arrière et démarrer la vidéo normalement.
    6. +
    7. +

      Sinon, nous ajoutons la classe active sur le bouton rwd avec classList.add(), mettons la vidéo en pause en utilisant {{domxref("HTMLMediaElement.pause()")}}, puis définissons la variable intervalRwd en appelant {{domxref("WindowOrWorkerGlobalScope.setInterval", "setInterval()")}}. Quand elle invoquée, la fonction setInterval() créé un intervale actif, ce qui signifie qu'une fonction donnée en paramètre est exécutée toutes les x millisecondes — x est la valeur du 2ème paramètre. Ainsi, nous exécutons ici la fonction windBackward() toutes les 200 millisecondes — nous utiliserons cette fonction pour retourner la fonction en arrière de manière constante. Pour stopper un intervale actif, vous devez appeler {{domxref("WindowOrWorkerGlobalScope.clearInterval", "clearInterval()")}} en lui donnant l'intervale à arrêter en paramètre, dans notre cas il est stocké dans la variable intervalRwd (voir l'appel à clearInterval() effectué plus tôt dans la fonction).

      +
    8. +
    +
  4. +
  5. +

    Pour en finir avec cette section, nous devons définir les fonctions windBackward() et windForward() invoquées dans les appels setInterval(). Ajoutez ce qui suit après les deux fonctions précédentes:

    + +
    function windBackward() {
    +  if(media.currentTime <= 3) {
    +    rwd.classList.remove('active');
    +    clearInterval(intervalRwd);
    +    stopMedia();
    +  } else {
    +    media.currentTime -= 3;
    +  }
    +}
    +
    +function windForward() {
    +  if(media.currentTime >= media.duration - 3) {
    +    fwd.classList.remove('active');
    +    clearInterval(intervalFwd);
    +    stopMedia();
    +  } else {
    +    media.currentTime += 3;
    +  }
    +}
    + Encore une fois, nous allons voir pas à pas la première fonction, puisque les deux fonctions font la même chose mais dans le sens inverse. Dans windBackward(), nous faisons comme suit — gardez à l'esprit que la fonction est exécutée toutes les 200 millisecondes. + +
      +
    1. Nous commençons avec une instruction if qui vérifie si le temps en cours est inférieur à 3 secondes, c'est à dire si le retour arrière nous ramènerait avant le début de la vidéo. Cela provoquerait un comportement étrange. Ainsi, si c'est le cas, nous arrêtons la vidéo en appelant stopMedia(), supprimons la classe active du bouton, et stoppons l'intervale intervalRwd pour stopper le retour arrière. Si nous n'avions pas ajouté cette dernière étape, la vidéo continuerait de se remboniner éternellement.
    2. +
    3. Si le temps en cours n'est pas inférieur à 3 secondes, nous retournons en arrière de 3 secondes en exécutant media.currentTime -= 3. Dans les faits, on rembobine donc la vidéo de 3 secondes toutes les 200 millisecondes.
    4. +
    +
  6. +
+ +

Mettre à jour le temps écoulé

+ +

La dernière chose à implémenter pour notre lecteur multimédia est l'affichage du temps écoulé. Pour ce faire, nous allons exécuter une fonction pour mettre à jour le temps affiché à chaque fois que l'événement {{event("timeupdate")}} est déclenché sur l'élément <video>. La fréquence à laquelle cet événement se déclenche dépend de votre navigateur, de la puissance de votre CPU, etc (voir post stackoverflow).

+ +

Ajoutez la ligne addEventListener() suivante à la suite des autres:

+ +
media.addEventListener('timeupdate', setTime);
+ +

Maintenant, ajoutez la fonction setTime():

+ +
function setTime() {
+  var minutes = Math.floor(media.currentTime / 60);
+  var seconds = Math.floor(media.currentTime - minutes * 60);
+  var minuteValue;
+  var secondValue;
+
+  if (minutes < 10) {
+    minuteValue = '0' + minutes;
+  } else {
+    minuteValue = minutes;
+  }
+
+  if (seconds < 10) {
+    secondValue = '0' + seconds;
+  } else {
+    secondValue = seconds;
+  }
+
+  var mediaTime = minuteValue + ':' + secondValue;
+  timer.textContent = mediaTime;
+
+  var barLength = timerWrapper.clientWidth * (media.currentTime/media.duration);
+  timerBar.style.width = barLength + 'px';
+}
+
+ +

C'est une fonction assez longue, alors allons-y étape par étape:

+ +
    +
  1. Tout d'abord, nous récupérons le nombre de minutes et de secondes à partir de {{domxref("HTMLMediaElement.currentTime")}}.
  2. +
  3. Ensuite, on initialise deux variables supplémentaires — minuteValue et secondValue.
  4. +
  5. Les deux instructions if qui suivent déterminent si le nombre de minutes et secondes est inférieur à 10. Si c'est le cas, on ajoute un zéro à gauche pour afficher le numéro sur deux chiffres — comme sur une horloge digitale.
  6. +
  7. Le temps est au final la concaténation de minuteValue, un caractère deux-points, et secondValue.
  8. +
  9. Le temps qu'on vient de définir devient la valeur {{domxref("Node.textContent")}} du décompte, pour qu'il s'affiche dans l'interface utilisateur.
  10. +
  11. La largeur que nous devons donner <div> intérieur est calculée en récupérant la largeur du <div> externe (la propriété {{domxref("HTMLElement.clientWidth", "clientWidth")}} retourne la largeur de l'élément), et en la multipliant par {{domxref("HTMLMediaElement.currentTime")}} divisé par le total {{domxref("HTMLMediaElement.duration")}} du média.
  12. +
  13. Nous assignons la largeur du <div> intérieur à la valeur calculée, plus "px", il sera donc fixé à ce nombre de pixels.
  14. +
+ +

Corriger play et pause

+ +

Il nous reste un problème à régler. Si on presse les boutons play/pause ou stop pendant que le retour arrière ou l'avance rapide sont actifs, alors ça ne marchera pas. Comment corriger le code pour qu'ils annulent l'action rwd/fwd et joue/stoppe la vidéo comme on s'y attendrait? C'est relativement simple.

+ +

Tout d'abord, ajoutez les lignes qui suivent à l'intérieur de la fonction stopMedia() — n'importe où:

+ +
rwd.classList.remove('active');
+fwd.classList.remove('active');
+clearInterval(intervalRwd);
+clearInterval(intervalFwd);
+
+ +

Maintenant, ajoutez ces mêmes lignes une fois de plus, au début de la fonction playPauseMedia() (juste avant le début de l'instruction if).

+ +

À ce stade, vous pouvez supprimer les lignes équivalentes des fonctions windBackward() et windForward(), puisqu'elles ont été ajoutées à la fonction stopMedia() à la place.

+ +
+

Note: Vous pouvez améliorer votre code en créant une fonction séparée qui exécute ces lignes, et l'appeler aux endroits où vous en avez besoin plutôt que de répéter ces lignes à de multiples endroits du code. Mais nous vous laissons vous en occuper.

+
+ +
+

Note: Le code terminé est disponible sur Github (le voir en direct).

+
+ +

Sommaire

+ +

Je pense que nous vous en avons suffisamment appris dans cet article. L'API {{domxref("HTMLMediaElement")}} offre une multitude de fonctionnalités pour la création de lecteurs audio et vidéo simples, et ce n'est que le sommet de l'iceberg. La section "Voir aussi" ci-dessous vous fournirea des liens vers des fonctionnalités plus complexes et plus intéressantes.

+ +

Voici quelques suggestions de modifications à apporter à l'exemple que nous avons construit:

+ +
    +
  1. +

    Si la vidéo dure plus d'une heure, le temps écoulé va bien afficher les minutes et les secondes mais pas les heures. Changez l'exemple pour lui faire afficher les heures.

    +
  2. +
  3. +

    Parce que les éléments <audio> ont la même fonctionnalité {{domxref("HTMLMediaElement")}} de disponible, vous pouvez faire fonctionner ce lecteur avec un élément <audio>. Essayez  de le faire.

    +
  4. +
  5. +

    Trouvez un moyen de transformer le <div> interne en une véritable barre de progrès — quand vous cliquez quelque part sur la barre, vous vous déplacez à la position relative dans la vidéo. Un indice: vous pouvez trouver les valeurs X et Y des côtés gauche/droite et haut/bas d'un l'élément via la méthode getBoundingClientRect(), et vous pouvez trouver les coordonnées de la souris au moment du clic à l'intérieur de l'objet event du clic, appelé sur l'objet {{domxref("Document")}}. Par exemple:

    + +
    document.onclick = function(e) {
    +  console.log(e.x) + ',' + console.log(e.y)
    +}
    +
  6. +
+ +

Voir aussi

+ + + +

{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Drawing_graphics", "Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs", "Learn/JavaScript/Client-side_web_APIs")}}

+ +

 

+ +

Dans ce module

+ + diff --git a/files/fr/learn/javascript/first_steps/arrays/index.html b/files/fr/learn/javascript/first_steps/arrays/index.html new file mode 100644 index 0000000000..4fc38abf8d --- /dev/null +++ b/files/fr/learn/javascript/first_steps/arrays/index.html @@ -0,0 +1,528 @@ +--- +title: Les tableaux +slug: Learn/JavaScript/First_steps/tableaux +tags: + - Apprendre + - Article + - Codage + - Débutants + - JavaScript + - Lier + - Pop + - Push + - Tableaux + - décalage + - séparer +translation_of: Learn/JavaScript/First_steps/Arrays +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps/Silly_story_generator", "Learn/JavaScript/First_steps")}}
+ +

Dans le dernier article de ce module, nous examinerons les tableaux — une façon de stocker proprement une liste d'éléments de données sous un seul nom de variable. Ici nous verrons pourquoi c'est utile, puis nous apprendrons comment créer un tableau, y retrouver, y ajouter ou en enlever les éléments dedans, et quelques à‑côtés en bonus.

+ + + + + + + + + + + + +
Prérequis :Vocabulaire courant de l'informatique, bases de HTML et CSS, compréhension de ce que fait JavaScript.
Objectif :Comprendre ce que sont les tableaux et savoir comment les manipuler en JavaScript.
+ +

Qu'est‑ce qu'un tableau ?

+ +

Les tableaux sont généralement décrits comme des "objets de type liste" ; un tableau est un objet contenant plusieurs valeurs. Les objets tableau peuvent être stockés dans des variables et traités de la même manière que tout autre type de valeur, la différence étant que nous pouvons accéder à chaque valeur du tableau individuellement, et faire des choses super utiles et efficaces avec la liste des valeurs, comme boucler et faire la même chose pour chaque valeur. Peut-être que nous avons une série d'articles et leurs prix stockés dans un tableau, et nous voulons les parcourir tous et les imprimer sur une facture, tout en totalisant tous les prix ensemble et en imprimant le prix total en bas.

+ +

Sans tableaux, nous devrions stocker chaque valeur dans une variable séparée, puis appeler le code qui effectue l'affichage ou l'impression, puis ajouter séparément chaque élément. Ce serait plus long à écrire, moins efficace et cela comporterait plus de risques d'erreurs. Si nous avions 10 articles à ajouter à la facture, ce serait déjà assez mauvais, mais qu'en serait-il de 100 articles ou de 1000 ? Nous reviendrons sur cet exemple plus loin dans l'article.

+ +

Comme précédemment, initions‑nous aux bases pratiques des tableaux en entrant quelques exemples dans une console JavaScript. En voici une plus bas (vous pouvez aussi ouvrir cette console dans un onglet ou une fenêtre séparés ou utiliser la console développeur de l'explorateur si vous préférez).

+ + + +

{{ EmbedLiveSample('Hidden_code', '100%', 300) }}

+ +

Créer un tableau

+ +

On définit les valeurs d'un tableau par une liste d'éléments entre crochets droits, séparés par des virgules.

+ +
    +
  1. Disons que nous voulons mettre une liste d'achats dans un tableau — nous devons opérer comme suit. Entrez les lignes ci‑après dans la console : +
    let shopping = ['pain', 'lait', 'fromage', 'houmous', 'nouilles'];
    +shopping;
    +
  2. +
  3. Dans ce cas, chaque élément du tableau est une chaîne, mais gardez en tête que vous pouvez stocker n'importe quel élément dans un tableau — chaîne, nombre, objet, autre variable et même d'autres tableaux. Vous pouvez également mélanger et assortir les types d'articles — il n'est pas obligatoire que ce soient tous des nombres, des chaînes, etc. Essayez ceci :
  4. +
  5. +
    let sequence = [1, 1, 2, 3, 5, 8, 13];
    +let random = ['arbre', 795, [0, 1, 2]];
    +
  6. +
  7. Créez donc quelques tableaux de votre cru avant de continuer.
  8. +
+ +

Accès aux éléments de tableau et modification de ceux‑ci

+ +

Vous pouvez avoir accès isolément aux éléments dans un tableau en utilisant la notation crochet, de la même façon que nous avons eu accès aux lettres dans une chaîne.

+ +
    +
  1. Entrez ceci dans la console : +
    shopping[0];
    +// renvoie "pain"
    +
  2. +
  3. Vous pouvez aussi modifier un élément dans un tableau en donnant simplement une nouvelle valeur à l'élément. Essayez ceci : +
    shopping[0] = 'crème de sésame';
    +shopping;
    +// shopping renvoie maintenant [ "crème de sésame", "lait", "fromage", "houmous", "nouilles" ]
    + +
    Note : Nous l'avons déjà dit, mais enseigner c'est répéter — les ordinateurs commencent les décomptes à partir de 0 !
    +
  4. +
  5. Notez qu'un tableau à l'intérieur d'un tableau est appelé un tableau multidimensionnel. Vous accédez à un des éléments de ce tableau interne en chaînant deux paires de crochets. Par exemple, pour avoir accès à l'un des éléments (le troisième) du tableau élément du tableau random (voir la section précédente), vous pouvez écrire quelque chose comme :
  6. +
  7. +
    random[2][2];
    +
  8. +
  9. Poursuivez et faites quelques autres modifications dans les exemples de tableaux avant de poursuivre.
  10. +
+ +

Trouver la taille d'un tableau

+ +

Vous pouvez trouver la taille d'un tableau (le nombre d'éléments qu'il comporte) de la même façon que vous obtenez la taille (en caractères) d'un chaîne — avec la propriété {{jsxref("Array.prototype.length","length")}}. Essayez :

+ +
sequence.length;
+// renvoie 7
+ +

Il y a d'autres usages, mais le plus courant permet de dire à une boucle de poursuivre jusqu'à ce que tous les éléments du tableau aient été passés en revue. Ainsi, par exemple :

+ +
let sequence = [1, 1, 2, 3, 5, 8, 13];
+for (var i = 0; i < sequence.length; i++) {
+  console.log(sequence[i]);
+}
+ +

Vous en apprendrez plus sur les boucles dans un prochain article, mais, en résumé, ce code dit :

+ +
    +
  1. Commencer la boucle à l'élément 0 du tableau.
  2. +
  3. Arrêter de tourner quand le dernier élément du tableau sera atteint. Cela fonctionne pour n'importe quelle dimension de tableau ; dans notre cas, on sortira de la boucle à l'élément  7 (c'est bon, car le dernier élément — que nous souhaitons que la boucle traite — est le 6).
  4. +
  5. Afficher chaque élément sur la console de l'explorateur avec console.log().
  6. +
+ +

Quelques méthodes utiles pour les tableaux

+ +

Dans ce paragraphe nous examinerons quelques méthodes de tableaux à connaître. Elles permettent de scinder des chaînes en éléments de tableau et inversement, et d'ajouter de nouveaux éléments dans des tableaux.

+ +

Conversions entre chaînes et tableaux

+ +

Souvent, vous serez confronté à des données brutes contenues dans une longue chaîne de caractères, et vous voudrez peut-être en extraire les éléments utiles sous une forme plus pratique pour en faire quelque chose, comme les afficher dans un tableau de données. Pour ce faire, nous pouvons utiliser la méthode {{jsxref ("String. prototype. prototype. split ()","split ()")}}. Dans sa formulation la plus simple, elle prend un seul paramètre, le caractère servant de séparateur ; elle renverra les sous-chaînes entre séparateurs en tant qu'éléments d'un tableau.

+ +
+

Note : D'accord, techniquement parlant c'est une méthode de chaîne, et non une méthode de tableau, mais nous la mettons dans le chapitre des tableaux car elle est bien à sa place ici.

+
+ +
    +
  1. Servons‑nous en et voyons comment elle fonctionne. D'abord créons une chaîne dans la console : +
    let myData = 'Manchester,London,Liverpool,Birmingham,Leeds,Carlisle';
    +
  2. +
  3. Scindons‑la à chaque virgule : +
    let myArray = myData.split(',');
    +myArray;
    +
  4. +
  5. Pour terminer, trouvons la taille du nouveau tableau et retrouvons quelques‑uns de ses éléments : +
    myArray.length;
    +myArray[0]; // le premier élément du tableau
    +myArray[1]; // le deuxième élément du tableau
    +myArray[myArray.length-1]; // le dernier élément du tableau
    +
  6. +
  7. Vous pouvez également faire le contraire avec la méthode {{jsxref("Array.prototype.join()","join()")}}. Essayons : +
    let myNewString = myArray.join(',');
    +myNewString;
    +
  8. +
  9. Une autre façon de convertir un tableau en chaîne consiste à se servir de la méthode {{jsxref("Array.prototype.toString()","toString()")}}. toString() est plus simple au plan des arguments que join(), car elle ne prend pas de paramètre, mais elle est plus limitée. Avec join() vous pouvez diversifier les séparateurs (essayez de lancer la commande du point 4 avec un caractère autre que la virgule). +
    let dogNames = ["Rocket","Flash","Bella","Slugger"];
    +dogNames.toString(); //Rocket,Flash,Bella,Slugger
    +
  10. +
+ +

Ajout et suppression d'éléments de tableau

+ +

Nous n'avons pas encore parlé d'ajout et de suppression d'éléments de tableau — allons‑y. Nous utiliserons le tableau myArray dont nous nous sommes servis à la fin de la dernière section. Si vous n'avez pas entré les commandes de cette section dans la console, il est nécessaire de créer d'abord le tableau :

+ +
let myArray = ['Manchester', 'London', 'Liverpool', 'Birmingham', 'Leeds', 'Carlisle'];
+ +

Premièrement, pour ajouter ou supprimer un élément à la fin du tableau, vous pouvez respectivement utiliser {{jsxref("Array.prototype.push()","push()")}} et {{jsxref("Array.prototype.pop()","pop()")}}.

+ +
    +
  1. Voyons push() d'abord — notez que vous devez mettre en paramètre les éléments que vous souhaitez ajouter à la fin du tableau. Essayez ceci : + +
    myArray.push('Cardiff');
    +myArray;
    +myArray.push('Bradford', 'Brighton');
    +myArray;
    +
    +
  2. +
  3. La taille du tableau modifié est renvoyée quand l'appel de la méthode est terminé. Si vous voulez enregistrer la taille du nouveau tableau dans une variable, vous pouvez écrire quelque chose comme ceci : +
    let newLength = myArray.push('Bristol');
    +myArray;
    +newLength;
    +
  4. +
  5. Supprimer le dernier élément de la liste est très simple : il suffit de lancer pop() sur celle‑ci. Essayez : +
    myArray.pop();
    +
  6. +
  7. L'élément supprimé est renvoyé à la fin de l'appel de la méthode. Également : +
    let removedItem = myArray.pop();
    +myArray;
    +removedItem;
    +
  8. +
+ +

{{jsxref("Array.prototype.unshift()","unshift()")}} et {{jsxref("Array.prototype.shift()","shift()")}} fonctionnent exactement de la même manière, excepté qu'il travaillent sur la tête du tableau au lieu de la queue.

+ +
    +
  1. D'abord unshift() — essayez : + +
    myArray.unshift('Edinburgh');
    +myArray;
    +
  2. +
  3. Maintenant shift() — essayez ! +
    let removedItem = myArray.shift();
    +myArray;
    +removedItem;
    +
  4. +
+ +

Activité : affichons les produits !

+ +

Revenons à l'exemple que nous avons décrit plus haut — afficher les noms des produits et leurs prix pour un envoi, puis faire le total des prix et l'afficher à la fin de la liste. Dans l'exemple modifiable ci‑dessous, il y a des commentaires numérotés — chacun d'entre eux marque l'emplacement où vous devez ajouter quelque chose au code. Voici :

+ +
    +
  1. Sous le commentaire // number 1 il y a un certain nombre de chaînes de caractères, chacune précise le nom d'un produit et son prix séparé par deux‑points. Placez‑les dans un tableau ; enregistrez‑le sous le nom products.
  2. +
  3. Sur la même ligne que le commentaire // number 2 se trouve le début d'une boucle. Dans cette ligne nous avons actuellement i <= 0, test conditionnel qui fait que la  boucle stoppe immédiatement, car ce test dit « stopper dès que i est inférieur ou égal à 0 » et i part de 0. Remplacez ce test par un qui  n'arrêtera pas la boucle tant que i sera inférieur à la taille du tableau products.
  4. +
  5. Au dessous du commentaire // number 3 nous voudrions que vous écriviez une ligne de code qui scinde l'élément courant du tableau (nom:prix) en deux éléments distincts, un contenant uniquement le nom, l'autre uniquement le prix. Si vous nous ne savez pas trop comment faire, revoyez l'article relatif aux Méthodes utiles pour les chaînes de caractères pour vous aider, ou même mieux, regardez la section {{anch("Converting between strings and arrays")}} de cet article.
  6. +
  7. En plus des lignes de code ci‑dessus, vous aurez aussi à convertir les prix de chaîne de caractères en chiffres. Si vous ne vous souvenez pas comment faire, revoyez le premier article à propos des chaînes.
  8. +
  9. Il y a une variable nommée total créée et initialisée à la valeur de 0 en tête du code. Dans la boucle (sous // number 4) ajoutez une ligne qui ajoute à ce total le prix de l'article courant  à chaque itération de la boucle, de sorte que à la fin du code le prix total soit correctement inscrit sur l'envoi. Vous pourriez avoir besoin d'un opérateur d'assignation pour faire cela ;-).
  10. +
  11. Nous souhaitons que vous modifiez la ligne au‑dessous de  // number 5 de sorte que la variable itemText soit égale à « nom actuel de l'élément — $prix actuel de l'élément », par exemple « Shoes — $23.99 » dans chaque cas, de façon à ce qu'une information correcte soit affichée sur l'envoi. Il s'agit d'une simple concaténation de chaînes de caractères, chose qui doit vous être familière.
  12. +
+ + + +

{{ EmbedLiveSample('Playable_code', '100%', 600) }}

+ +

Activité : Top 5 des recherches

+ +

Une bonne utilisation des méthodes de tableaux comme {{jsxref("Array.prototype.push()","push()")}} et {{jsxref("Array.prototype.pop()","pop()")}} permet de conserver un enregistrement des éléments actuellement actifs dans une application web. Dans une scène animée, par exemple, vous pouvez avoir un tableau d'objets représentant les graphiques d'arrière-plan actuellement affichés, et vous pouvez n'en vouloir que 50 à la fois, pour des raisons de performance ou d'encombrement. Chaque fois que de nouveaux objets sont créés et ajoutés au tableau, les plus anciens peuvent être supprimés du tableau pour n'en conserver que le nombre voulu.

+ +

Dans cet exemple nous allons montrer une utilisation beaucoup plus simple — ici, nous allons vous fournir un site de recherche fictif, avec une boîte de recherche. Voici l'idée : quand un terme est entré dans la boîte de recherche, les 5 précédents termes entrés sont affichés dans la liste. Quand le nombre de termes dépasse 5, le dernier terme est supprimé chaque fois qu'un nouveau terme est ajouté ; ainsi, le 5 termes précédents sont toujours affichés.

+ +
+

Note : Dans une application réelle avec boîte de recherche, vous pourriez vraisemblablement cliquer sur un des termes de la liste pour revenir à la recherche précédente, et l'application afficherait les vrais résultats ! Mais pour le moment nous en resterons à quelque chose de simple.

+
+ +

Pour terminer l'application, il vous faut :

+ +
    +
  1. Ajouter une ligne sous le commentaire // number 1 pour ajouter la valeur qui vient d'être saisie dans la boîte au début du tableau. Cette valeur est récupérée avec searchInput.value.
  2. +
  3. Ajouter une ligne sous le commentaire // number 2  pour supprimer la valeur en fin de liste du tableau.
  4. +
+ + + +

{{ EmbedLiveSample('Playable_code_2', '100%', 600) }}

+ +

Testez vos compétences !

+ +


+ Vous avez atteint la fin de cet article, mais vous souvenez-vous des informations les plus importantes ? Vous pouvez trouver d'autres tests pour vérifier que vous avez bien fixé ces connaissances avant de continuer — voir Test de compétences : les tableaux.

+ +

Conclusion

+ +

Après la lecture de cet article, vous conviendrez que les tableaux semblent fichtrement utiles ; vous les verrez un peu partout en JavaScript, souvent associés à des boucles pour appliquer la même action à chaque élément du tableau. Nous vous indiquerons toutes les bases utiles à savoir à propos des boucles dans le prochain module, mais pour l'instant, félicitations : prenez une pause bien méritée ; vous avez étudié tous les articles du module !

+ +

La seule chose restant à faire est de procéder à l'évaluation de ce module pour tester votre compréhension de son contenu.

+ +

Voir aussi

+ + + + + +

{{PreviousMenuNext("Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps/Silly_story_generator", "Learn/JavaScript/First_steps")}}

+ +

Dans ce module

+ + diff --git a/files/fr/learn/javascript/first_steps/methode_chaine_utile/index.html b/files/fr/learn/javascript/first_steps/methode_chaine_utile/index.html deleted file mode 100644 index d81c3ccb4e..0000000000 --- a/files/fr/learn/javascript/first_steps/methode_chaine_utile/index.html +++ /dev/null @@ -1,479 +0,0 @@ ---- -title: Méthodes utiles pour les chaînes de caractères -slug: Learn/JavaScript/First_steps/methode_chaine_utile -tags: - - Apprentissage - - Article - - Codage - - Débutant - - JavaScript - - Longueur - - cas - - couper - - indexof - - majuscule - - minuscule - - remplacer -translation_of: Learn/JavaScript/First_steps/Useful_string_methods ---- -
{{LearnSidebar}}
- -
{{PreviousMenuNext("Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}
- -

À présent que nous avons vu les bases de la manipulation des chaînes de caractères, allons un cran plus loin et commençons à imaginer les opérations utiles que nous pourrions faire sur les chaînes de caractères avec les méthodes intégrées : trouver la longueur d'une chaîne, assembler ou couper des chaînes, substituer un caractère à un autre dans une chaîne, et plus encore.

- - - - - - - - - - - - -
Prérequis :Vocabulaire courant de l'informatique, bases de HTML et CSS, compréhension de ce que fait JavaScript.
Objectif :Comprendre que les chaînes de caractères sont des objets, et apprendre à utiliser certaines méthodes basiques disponibles sur ces objets pour manipuler les chaînes.
- -

Les chaînes de caractères sont des objets

- -

Nous l'avons déjà dit, et nous le redirons — tout est objet en JavaScript. Lorsque vous créez une chaîne, par exemple en utilisant :

- -
let string = 'Ceci est une chaîne';
- -

votre variable devient une instance de l'objet String, et par conséquent possède un grand nombre de propriétés et de méthodes associées. Allez sur la page de l'objet {{jsxref("String")}} et regardez la liste sur le côté de la page !

- -

Avant que votre cervelle ne commence à bouillir, pas de panique ! Vous n'avez vraiment pas besoin de connaître la plupart des méthodes de cette liste au début de cet apprentissage. Mais il est probable que vous utiliserez  certaines assez souvent. Nous allons les voir maintenant.

- -

Entrez quelques exemples dans une console vierge. En voici une ci-dessous (vous pouvez aussi ouvrir cette console dans un onglet ou une fenêtre séparés, ou utiliser la console de développement du navigateur si vous préférez).

- - - -

{{ EmbedLiveSample('Hidden_code', '100%', 300) }}

- -

Trouver la longueur d'une chaîne

- -

C'est facile — il suffit d'utiliser la propriété {{jsxref("String.prototype.length", "length")}}. Entrez ceci :

- -
let browserType = 'mozilla';
-browserType.length;
- -

Cette commande doit renvoyer le nombre 7, parce que « mozilla » comporte 7 caractères. C'est utile pour de nombreuses raisons ; par exemple, vous pourriez avoir besoin de trouver les longueurs d'une série de noms pour les afficher par taille ou faire savoir à un utilisateur qu'il a entré un nom trop long dans un champ de formulaire à partir du moment où il dépasse une certaine taille.

- -

Retrouver un caractère donné dans une chaîne

- -

Dans le même ordre d'idées, il est possible de faire renvoyer tout caractère d'une chaîne avec la notation crochets — c'est-à-dire en ajoutant des crochets ([]) à la fin du nom de la variable. Entre les crochets, mettez le rang du caractère à retrouver ; par exemple, pour retrouver le premier caractère, vous devez  écrire ceci :

- -
browserType[0];
- -

Les ordinateurs décomptent à partir de 0, pas de 1 ! Pour retrouver le dernier caractère de n'importe quelle chaîne, on peut utiliser la commande qui suit ; elle combine cette technique avec la propriété length  que nous avons vue plus haut :

- -
browserType[browserType.length-1];
- -

La longueur de « mozilla » est de 7 caractères, mais comme le décompte se fait à partir de 0, la position du caractère est 6, d'où la nécessité d'écrire length-1. Vous pourrez utiliser cette propriété pour, par exemple, trouver la première lettre d'une série de chaînes et les trier alphabétiquement.

- -

Trouver une sous-chaîne à l'intérieur d'une chaîne et l'extraire

- -
    -
  1. Parfois, vous aurez besoin de trouver si une chaîne est présente à l'intérieur d'une autre chaîne plus grande (on dit en général si une sous-chaîne est présente à l'intérieur d'une chaîne). La méthode {{jsxref("String.prototype.indexOf()", "indexOf()")}} permet de le faire ; elle prend un unique ({{glossary("parameter")}}) — la sous-chaîne recherchée. Essayez : - -
    browserType.indexOf('zilla');
    - La commande donne 2 comme résultat, car la sous-chaîne « zilla » commence à la position 2 (0, 1, 2 — donc au troisième caractère) dans « mozilla ». Un tel code s'utilise pour filtrer des chaînes. Par exemple, vous pourriez avoir une liste d'adresses web et ne vouloir afficher que celles qui contiennent « mozilla ».
  2. -
- -
    -
  1. On peut faire cela autrement, peut-être plus efficacement encore. Écrivez : -
    browserType.indexOf('vanilla');
    - Cela doit vous donner -1 comme résultat — renvoyé quand la sous-chaîne, en l'occurence « vanilla », n'est pas trouvée dans la chaîne principale.
    -
    - Vous pouvez utiliser cette propriété pour trouver tous les cas de chaînes ne contenant pas la sous-chaîne « mozilla », ou bien la contenant, si vous utilisez l'opérateur négation logique, tel que montré ci-dessous. Vous pourriez faire quelque chose comme : - -
    if(browserType.indexOf('mozilla') !== -1) {
    -  // faire des tas de choses avec la chaîne
    -}
    -
  2. -
  3. Lorsque vous savez où la sous-chaîne commence à l'intérieur de la chaîne, et savez à quel caractère elle prend fin, vous pouvez utiliser {{jsxref("String.prototype.slice()", "slice()")}} pour l'extraire. Voyez ce code : -
    browserType.slice(0,3);
    - Il renvoie « moz » — le premier paramètre est la position du caractère où doit commencer l'extraction, et le second paramètre est la position du caractère se trouvant après le dernier à extraire. Ainsi, l'extraction va de la première position à la dernière, celle-ci non comprise. On peut dire, dans notre cas, que le second paramètre est égal à la longueur de la chaîne retournée.
  4. -
  5. Également, si vous souhaitez extraire tous les caractères après un caractère donné jusqu'à la fin de la chaîne, vous n'avez pas à mettre le second paramètre ! Il suffit d'indiquer la position du caractère à partir duquel vous voulez extraire les caractères restants dans la chaîne. Essayez la commande : -
    browserType.slice(2);
    - Elle renvoie « zilla » — le caractère à la position 2 est « z » et comme nous n'avons pas mis de second paramètre, la sous-chaîne retournée comporte tous les caractères restants de la chaîne.
  6. -
- -
-

Note : Le second paramètre de slice() est optionnel : s'il n'est pas defini, l'extraction va jusqu'à la fin de la chaîne originale. Il existe aussi d'autres options, allez à la page de {{jsxref("String.prototype.slice()", "slice()")}} pour voir ces autres options.

-
- -

Changer la casse

- -

Les méthodes {{jsxref("String.prototype.toLowerCase()", "toLowerCase()")}} et {{jsxref("String.prototype.toUpperCase()", "toUpperCase()")}} s'appliquent à une chaîne et en convertissent tous les caractères, respectivement en minuscules ou en majuscules. C'est utile si, par exemple, vous souhaitez normaliser toutes les données entrées par des utilisateurs avant de les stocker dans une base de données.

- -

Essayons d'entrer les lignes suivantes et voyons ce qui se passe :

- -
let radData = 'My NaMe Is MuD';
-radData.toLowerCase();
-radData.toUpperCase();
- -

Actualiser des parties de chaîne

- -

Vous pouvez remplacer une sous-chaîne à l'intérieur d'une chaîne avec une autre sous-chaîne à l'aide de la méthode {{jsxref("String.prototype.replace()", "replace()")}}. Cela fonctionne très simplement au niveau basique, bien qu'il soit possible de faire des choses plus avancées, mais nous ne y attarderons pas maintenant.

- -

La méthode prend deux paramètres — la chaîne que vous voulez remplacer et la chaîne avec laquelle vous voulez la remplacer. Essayez avec cet exemple :

- -
browserType.replace('moz','van');
- -

À noter : pour que, dans un programme réel, la variable browserType reflète effectivement la valeur actualisée, il faut assigner à la valeur de la variable le résultat de l'opération ; cette dernière ne met pas à jour automatiquement la valeur de la sous-chaîne. Pour ce faire, il faut écrire : browserType = browserType.replace('moz','van');

- -

Apprendre en pratiquant

- -

Dans cette section, vous allez pouvoir vous entraîner à écrire du code de manipulation de chaîne. Dans chacun des exercices ci-dessous, nous avons un tableau de chaînes, une boucle qui traîte chaque valeur dans le tableau et l'affiche dans une liste à puces. Vous n'avez pas besoin de comprendre comment fonctionnent les tableaux ou les boucles dès maintenant — cela vous sera expliqué dans de prochains articles. Tout ce dont vous avez besoin dans chaque cas est d'écrire le code qui va renvoyer les chaînes dans le format souhaité.

- -

Chaque exemple est accompagné d'un bouton « Réinitialiser », que vous pouvez utiliser pour réinitialiser le code si vous faites une erreur et que vous ne parvenez pas à la corriger, et un bouton « Montrer la solution » sur lequel vous pouvez cliquer pour afficher une réponse possible si jamais vous êtes vraiment bloqué.

- -

Filtrer des messages de vœux

- -

Dans ce premier exercice, nous commencerons simplement — nous avons un tableau de carte de voeux, mais nous voulons les trier pour ne lister que les messages concernant Noël. Nous attendons de vous que vous utilisiez un test conditionnel à l'intérieur d'une structure if( ... ), pour tester chaque chaîne et ne l'afficher dans la liste que si elle contient un message concernant Noël.

- -
    -
  1. Réfléchissez d'abord à comment vérifier que le message concerne Noël. Quelle chaîne est présente dans tous ces messages, et quelle méthode pourriez-vous utiliser pour en tester la présence ?
  2. -
  3. Il vous faudra alors écrire un test conditionnel sous la forme opérande1 opérateur opérande2. La chose à gauche est-elle égale à la chose à droite ? Ou dans notre cas, l'appel de méthode de gauche renvoie-t-il le résultat de droite ?
  4. -
  5. Conseil : dans notre cas, il est probablement plus utile de tester si le résultat de l'appel de notre méthode n'est pas égal à un certain résultat.
  6. -
- - - -

{{ EmbedLiveSample('Playable_code', '100%', 490) }}

- -

Remettre les majuscules

- -

Dans cet exercice, nous avons des noms des villes du Royaume-Uni, mais les majuscules ne sont pas au bon endroit. Nous souhaitons modifier les noms pour qu'ils soient en minuscules à l'exception de la première lettre qui doit être une majuscule. Une bonne manière de faire ceci :

- -
    -
  1. Convertissez la totalité de la chaîne contenue dans la variable input en minuscules et stockez-la dans une nouvelle variable.
  2. -
  3. Récupérez la première lettre de la chaîne dans cette nouvelle variable et stockez-la dans une autre variable.
  4. -
  5. En utilisant la dernière variable comme une sous-chaîne, remplacez la première lettre de la chaîne en minuscules par la première lettre de la chaîne en minuscules transformé en majuscules. Stockez le résultat de cette procédure de remplacement dans une autre nouvelle variable.
  6. -
  7. Changez la valeur de la variable result afin qu'elle soit égale au résultat final plutôt qu'à input.
  8. -
- -
-

Note: Un conseil — les paramètres des méthodes de chaîne n'ont pas besoin d'être des chaînes, elle peuvent aussi être des variables, ou même des variables avec une méthode invoquée sur elles.

-
- - - -

{{ EmbedLiveSample('Playable_code_2', '100%', 450) }}

- -

Créer de nouvelles chaînes à partir de morceaux

- -

Dans ce dernier exercice, le tableau contient un lot de chaînes contenant des informations à propos d'arrêts de train dans le nord de l'Angleterre. Les chaînes sont des éléments de données contenant le code en trois lettres de l'arrêt, suivi par des données lisibles par machine, suivi par un point-virgule, et enfin le nom de la station lisible par un humain. Par exemple :

- -
MAN675847583748sjt567654;Manchester Piccadilly
- -

Nous voulons extraire le code de la station et son nom, et les associer dans une chaîne avec la structure suivante :

- -
MAN: Manchester Piccadilly
- -

Nous vous recommandons de procéder de la manière suivante :

- -
    -
  1. Extraire le code de trois lettres de la station et le stocker dans une nouvelle variable.
  2. -
  3. Trouver la position du caractère point-virgule.
  4. -
  5. Extraire le nom de la station lisible par un humain en utilisant la position du caractère point virgule comme référence, et le stocker dans une nouvelle variable.
  6. -
  7. Concaténer les deux nouvelles variables et une chaîne pour fabriquer la chaîne finale.
  8. -
  9. Changer la valeur de la variable result pour qu'elle soit égale à la chaîne finale, plutôt qu'à input.
  10. -
- - - -

{{ EmbedLiveSample('Playable_code_3', '100%', 485) }}

- -

Conclusion

- -

Il n'est pas possible d'éluder le fait qu'il est très important de savoir manipuler des mots et des phrases lorsqu'on programme — tout particulièrement en JavaScript, dans la mesure où les sites web servent à la communication entre les personnes. Cet article vous a indiqué, pour l'instant, les bases à connaître pour manipuler les chaînes. Ce sera utile lorsque vous aborderez des sujets plus complexes à l'avenir. Pour suivre, nous allons nous intéresser au dernier grand type de données sur lequel nous devons nous concentrer à court terme — les tableaux.

- -

{{PreviousMenuNext("Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}

diff --git a/files/fr/learn/javascript/first_steps/tableaux/index.html b/files/fr/learn/javascript/first_steps/tableaux/index.html deleted file mode 100644 index 4fc38abf8d..0000000000 --- a/files/fr/learn/javascript/first_steps/tableaux/index.html +++ /dev/null @@ -1,528 +0,0 @@ ---- -title: Les tableaux -slug: Learn/JavaScript/First_steps/tableaux -tags: - - Apprendre - - Article - - Codage - - Débutants - - JavaScript - - Lier - - Pop - - Push - - Tableaux - - décalage - - séparer -translation_of: Learn/JavaScript/First_steps/Arrays ---- -
{{LearnSidebar}}
- -
{{PreviousMenuNext("Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps/Silly_story_generator", "Learn/JavaScript/First_steps")}}
- -

Dans le dernier article de ce module, nous examinerons les tableaux — une façon de stocker proprement une liste d'éléments de données sous un seul nom de variable. Ici nous verrons pourquoi c'est utile, puis nous apprendrons comment créer un tableau, y retrouver, y ajouter ou en enlever les éléments dedans, et quelques à‑côtés en bonus.

- - - - - - - - - - - - -
Prérequis :Vocabulaire courant de l'informatique, bases de HTML et CSS, compréhension de ce que fait JavaScript.
Objectif :Comprendre ce que sont les tableaux et savoir comment les manipuler en JavaScript.
- -

Qu'est‑ce qu'un tableau ?

- -

Les tableaux sont généralement décrits comme des "objets de type liste" ; un tableau est un objet contenant plusieurs valeurs. Les objets tableau peuvent être stockés dans des variables et traités de la même manière que tout autre type de valeur, la différence étant que nous pouvons accéder à chaque valeur du tableau individuellement, et faire des choses super utiles et efficaces avec la liste des valeurs, comme boucler et faire la même chose pour chaque valeur. Peut-être que nous avons une série d'articles et leurs prix stockés dans un tableau, et nous voulons les parcourir tous et les imprimer sur une facture, tout en totalisant tous les prix ensemble et en imprimant le prix total en bas.

- -

Sans tableaux, nous devrions stocker chaque valeur dans une variable séparée, puis appeler le code qui effectue l'affichage ou l'impression, puis ajouter séparément chaque élément. Ce serait plus long à écrire, moins efficace et cela comporterait plus de risques d'erreurs. Si nous avions 10 articles à ajouter à la facture, ce serait déjà assez mauvais, mais qu'en serait-il de 100 articles ou de 1000 ? Nous reviendrons sur cet exemple plus loin dans l'article.

- -

Comme précédemment, initions‑nous aux bases pratiques des tableaux en entrant quelques exemples dans une console JavaScript. En voici une plus bas (vous pouvez aussi ouvrir cette console dans un onglet ou une fenêtre séparés ou utiliser la console développeur de l'explorateur si vous préférez).

- - - -

{{ EmbedLiveSample('Hidden_code', '100%', 300) }}

- -

Créer un tableau

- -

On définit les valeurs d'un tableau par une liste d'éléments entre crochets droits, séparés par des virgules.

- -
    -
  1. Disons que nous voulons mettre une liste d'achats dans un tableau — nous devons opérer comme suit. Entrez les lignes ci‑après dans la console : -
    let shopping = ['pain', 'lait', 'fromage', 'houmous', 'nouilles'];
    -shopping;
    -
  2. -
  3. Dans ce cas, chaque élément du tableau est une chaîne, mais gardez en tête que vous pouvez stocker n'importe quel élément dans un tableau — chaîne, nombre, objet, autre variable et même d'autres tableaux. Vous pouvez également mélanger et assortir les types d'articles — il n'est pas obligatoire que ce soient tous des nombres, des chaînes, etc. Essayez ceci :
  4. -
  5. -
    let sequence = [1, 1, 2, 3, 5, 8, 13];
    -let random = ['arbre', 795, [0, 1, 2]];
    -
  6. -
  7. Créez donc quelques tableaux de votre cru avant de continuer.
  8. -
- -

Accès aux éléments de tableau et modification de ceux‑ci

- -

Vous pouvez avoir accès isolément aux éléments dans un tableau en utilisant la notation crochet, de la même façon que nous avons eu accès aux lettres dans une chaîne.

- -
    -
  1. Entrez ceci dans la console : -
    shopping[0];
    -// renvoie "pain"
    -
  2. -
  3. Vous pouvez aussi modifier un élément dans un tableau en donnant simplement une nouvelle valeur à l'élément. Essayez ceci : -
    shopping[0] = 'crème de sésame';
    -shopping;
    -// shopping renvoie maintenant [ "crème de sésame", "lait", "fromage", "houmous", "nouilles" ]
    - -
    Note : Nous l'avons déjà dit, mais enseigner c'est répéter — les ordinateurs commencent les décomptes à partir de 0 !
    -
  4. -
  5. Notez qu'un tableau à l'intérieur d'un tableau est appelé un tableau multidimensionnel. Vous accédez à un des éléments de ce tableau interne en chaînant deux paires de crochets. Par exemple, pour avoir accès à l'un des éléments (le troisième) du tableau élément du tableau random (voir la section précédente), vous pouvez écrire quelque chose comme :
  6. -
  7. -
    random[2][2];
    -
  8. -
  9. Poursuivez et faites quelques autres modifications dans les exemples de tableaux avant de poursuivre.
  10. -
- -

Trouver la taille d'un tableau

- -

Vous pouvez trouver la taille d'un tableau (le nombre d'éléments qu'il comporte) de la même façon que vous obtenez la taille (en caractères) d'un chaîne — avec la propriété {{jsxref("Array.prototype.length","length")}}. Essayez :

- -
sequence.length;
-// renvoie 7
- -

Il y a d'autres usages, mais le plus courant permet de dire à une boucle de poursuivre jusqu'à ce que tous les éléments du tableau aient été passés en revue. Ainsi, par exemple :

- -
let sequence = [1, 1, 2, 3, 5, 8, 13];
-for (var i = 0; i < sequence.length; i++) {
-  console.log(sequence[i]);
-}
- -

Vous en apprendrez plus sur les boucles dans un prochain article, mais, en résumé, ce code dit :

- -
    -
  1. Commencer la boucle à l'élément 0 du tableau.
  2. -
  3. Arrêter de tourner quand le dernier élément du tableau sera atteint. Cela fonctionne pour n'importe quelle dimension de tableau ; dans notre cas, on sortira de la boucle à l'élément  7 (c'est bon, car le dernier élément — que nous souhaitons que la boucle traite — est le 6).
  4. -
  5. Afficher chaque élément sur la console de l'explorateur avec console.log().
  6. -
- -

Quelques méthodes utiles pour les tableaux

- -

Dans ce paragraphe nous examinerons quelques méthodes de tableaux à connaître. Elles permettent de scinder des chaînes en éléments de tableau et inversement, et d'ajouter de nouveaux éléments dans des tableaux.

- -

Conversions entre chaînes et tableaux

- -

Souvent, vous serez confronté à des données brutes contenues dans une longue chaîne de caractères, et vous voudrez peut-être en extraire les éléments utiles sous une forme plus pratique pour en faire quelque chose, comme les afficher dans un tableau de données. Pour ce faire, nous pouvons utiliser la méthode {{jsxref ("String. prototype. prototype. split ()","split ()")}}. Dans sa formulation la plus simple, elle prend un seul paramètre, le caractère servant de séparateur ; elle renverra les sous-chaînes entre séparateurs en tant qu'éléments d'un tableau.

- -
-

Note : D'accord, techniquement parlant c'est une méthode de chaîne, et non une méthode de tableau, mais nous la mettons dans le chapitre des tableaux car elle est bien à sa place ici.

-
- -
    -
  1. Servons‑nous en et voyons comment elle fonctionne. D'abord créons une chaîne dans la console : -
    let myData = 'Manchester,London,Liverpool,Birmingham,Leeds,Carlisle';
    -
  2. -
  3. Scindons‑la à chaque virgule : -
    let myArray = myData.split(',');
    -myArray;
    -
  4. -
  5. Pour terminer, trouvons la taille du nouveau tableau et retrouvons quelques‑uns de ses éléments : -
    myArray.length;
    -myArray[0]; // le premier élément du tableau
    -myArray[1]; // le deuxième élément du tableau
    -myArray[myArray.length-1]; // le dernier élément du tableau
    -
  6. -
  7. Vous pouvez également faire le contraire avec la méthode {{jsxref("Array.prototype.join()","join()")}}. Essayons : -
    let myNewString = myArray.join(',');
    -myNewString;
    -
  8. -
  9. Une autre façon de convertir un tableau en chaîne consiste à se servir de la méthode {{jsxref("Array.prototype.toString()","toString()")}}. toString() est plus simple au plan des arguments que join(), car elle ne prend pas de paramètre, mais elle est plus limitée. Avec join() vous pouvez diversifier les séparateurs (essayez de lancer la commande du point 4 avec un caractère autre que la virgule). -
    let dogNames = ["Rocket","Flash","Bella","Slugger"];
    -dogNames.toString(); //Rocket,Flash,Bella,Slugger
    -
  10. -
- -

Ajout et suppression d'éléments de tableau

- -

Nous n'avons pas encore parlé d'ajout et de suppression d'éléments de tableau — allons‑y. Nous utiliserons le tableau myArray dont nous nous sommes servis à la fin de la dernière section. Si vous n'avez pas entré les commandes de cette section dans la console, il est nécessaire de créer d'abord le tableau :

- -
let myArray = ['Manchester', 'London', 'Liverpool', 'Birmingham', 'Leeds', 'Carlisle'];
- -

Premièrement, pour ajouter ou supprimer un élément à la fin du tableau, vous pouvez respectivement utiliser {{jsxref("Array.prototype.push()","push()")}} et {{jsxref("Array.prototype.pop()","pop()")}}.

- -
    -
  1. Voyons push() d'abord — notez que vous devez mettre en paramètre les éléments que vous souhaitez ajouter à la fin du tableau. Essayez ceci : - -
    myArray.push('Cardiff');
    -myArray;
    -myArray.push('Bradford', 'Brighton');
    -myArray;
    -
    -
  2. -
  3. La taille du tableau modifié est renvoyée quand l'appel de la méthode est terminé. Si vous voulez enregistrer la taille du nouveau tableau dans une variable, vous pouvez écrire quelque chose comme ceci : -
    let newLength = myArray.push('Bristol');
    -myArray;
    -newLength;
    -
  4. -
  5. Supprimer le dernier élément de la liste est très simple : il suffit de lancer pop() sur celle‑ci. Essayez : -
    myArray.pop();
    -
  6. -
  7. L'élément supprimé est renvoyé à la fin de l'appel de la méthode. Également : -
    let removedItem = myArray.pop();
    -myArray;
    -removedItem;
    -
  8. -
- -

{{jsxref("Array.prototype.unshift()","unshift()")}} et {{jsxref("Array.prototype.shift()","shift()")}} fonctionnent exactement de la même manière, excepté qu'il travaillent sur la tête du tableau au lieu de la queue.

- -
    -
  1. D'abord unshift() — essayez : - -
    myArray.unshift('Edinburgh');
    -myArray;
    -
  2. -
  3. Maintenant shift() — essayez ! -
    let removedItem = myArray.shift();
    -myArray;
    -removedItem;
    -
  4. -
- -

Activité : affichons les produits !

- -

Revenons à l'exemple que nous avons décrit plus haut — afficher les noms des produits et leurs prix pour un envoi, puis faire le total des prix et l'afficher à la fin de la liste. Dans l'exemple modifiable ci‑dessous, il y a des commentaires numérotés — chacun d'entre eux marque l'emplacement où vous devez ajouter quelque chose au code. Voici :

- -
    -
  1. Sous le commentaire // number 1 il y a un certain nombre de chaînes de caractères, chacune précise le nom d'un produit et son prix séparé par deux‑points. Placez‑les dans un tableau ; enregistrez‑le sous le nom products.
  2. -
  3. Sur la même ligne que le commentaire // number 2 se trouve le début d'une boucle. Dans cette ligne nous avons actuellement i <= 0, test conditionnel qui fait que la  boucle stoppe immédiatement, car ce test dit « stopper dès que i est inférieur ou égal à 0 » et i part de 0. Remplacez ce test par un qui  n'arrêtera pas la boucle tant que i sera inférieur à la taille du tableau products.
  4. -
  5. Au dessous du commentaire // number 3 nous voudrions que vous écriviez une ligne de code qui scinde l'élément courant du tableau (nom:prix) en deux éléments distincts, un contenant uniquement le nom, l'autre uniquement le prix. Si vous nous ne savez pas trop comment faire, revoyez l'article relatif aux Méthodes utiles pour les chaînes de caractères pour vous aider, ou même mieux, regardez la section {{anch("Converting between strings and arrays")}} de cet article.
  6. -
  7. En plus des lignes de code ci‑dessus, vous aurez aussi à convertir les prix de chaîne de caractères en chiffres. Si vous ne vous souvenez pas comment faire, revoyez le premier article à propos des chaînes.
  8. -
  9. Il y a une variable nommée total créée et initialisée à la valeur de 0 en tête du code. Dans la boucle (sous // number 4) ajoutez une ligne qui ajoute à ce total le prix de l'article courant  à chaque itération de la boucle, de sorte que à la fin du code le prix total soit correctement inscrit sur l'envoi. Vous pourriez avoir besoin d'un opérateur d'assignation pour faire cela ;-).
  10. -
  11. Nous souhaitons que vous modifiez la ligne au‑dessous de  // number 5 de sorte que la variable itemText soit égale à « nom actuel de l'élément — $prix actuel de l'élément », par exemple « Shoes — $23.99 » dans chaque cas, de façon à ce qu'une information correcte soit affichée sur l'envoi. Il s'agit d'une simple concaténation de chaînes de caractères, chose qui doit vous être familière.
  12. -
- - - -

{{ EmbedLiveSample('Playable_code', '100%', 600) }}

- -

Activité : Top 5 des recherches

- -

Une bonne utilisation des méthodes de tableaux comme {{jsxref("Array.prototype.push()","push()")}} et {{jsxref("Array.prototype.pop()","pop()")}} permet de conserver un enregistrement des éléments actuellement actifs dans une application web. Dans une scène animée, par exemple, vous pouvez avoir un tableau d'objets représentant les graphiques d'arrière-plan actuellement affichés, et vous pouvez n'en vouloir que 50 à la fois, pour des raisons de performance ou d'encombrement. Chaque fois que de nouveaux objets sont créés et ajoutés au tableau, les plus anciens peuvent être supprimés du tableau pour n'en conserver que le nombre voulu.

- -

Dans cet exemple nous allons montrer une utilisation beaucoup plus simple — ici, nous allons vous fournir un site de recherche fictif, avec une boîte de recherche. Voici l'idée : quand un terme est entré dans la boîte de recherche, les 5 précédents termes entrés sont affichés dans la liste. Quand le nombre de termes dépasse 5, le dernier terme est supprimé chaque fois qu'un nouveau terme est ajouté ; ainsi, le 5 termes précédents sont toujours affichés.

- -
-

Note : Dans une application réelle avec boîte de recherche, vous pourriez vraisemblablement cliquer sur un des termes de la liste pour revenir à la recherche précédente, et l'application afficherait les vrais résultats ! Mais pour le moment nous en resterons à quelque chose de simple.

-
- -

Pour terminer l'application, il vous faut :

- -
    -
  1. Ajouter une ligne sous le commentaire // number 1 pour ajouter la valeur qui vient d'être saisie dans la boîte au début du tableau. Cette valeur est récupérée avec searchInput.value.
  2. -
  3. Ajouter une ligne sous le commentaire // number 2  pour supprimer la valeur en fin de liste du tableau.
  4. -
- - - -

{{ EmbedLiveSample('Playable_code_2', '100%', 600) }}

- -

Testez vos compétences !

- -


- Vous avez atteint la fin de cet article, mais vous souvenez-vous des informations les plus importantes ? Vous pouvez trouver d'autres tests pour vérifier que vous avez bien fixé ces connaissances avant de continuer — voir Test de compétences : les tableaux.

- -

Conclusion

- -

Après la lecture de cet article, vous conviendrez que les tableaux semblent fichtrement utiles ; vous les verrez un peu partout en JavaScript, souvent associés à des boucles pour appliquer la même action à chaque élément du tableau. Nous vous indiquerons toutes les bases utiles à savoir à propos des boucles dans le prochain module, mais pour l'instant, félicitations : prenez une pause bien méritée ; vous avez étudié tous les articles du module !

- -

La seule chose restant à faire est de procéder à l'évaluation de ce module pour tester votre compréhension de son contenu.

- -

Voir aussi

- - - - - -

{{PreviousMenuNext("Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps/Silly_story_generator", "Learn/JavaScript/First_steps")}}

- -

Dans ce module

- - diff --git a/files/fr/learn/javascript/first_steps/test_your_skills_colon__arrays/index.html b/files/fr/learn/javascript/first_steps/test_your_skills_colon__arrays/index.html new file mode 100644 index 0000000000..240e934831 --- /dev/null +++ b/files/fr/learn/javascript/first_steps/test_your_skills_colon__arrays/index.html @@ -0,0 +1,87 @@ +--- +title: 'Testez vos compétences: Tableaux' +slug: 'Learn/JavaScript/First_steps/Testes_vos_competence:_Tableaux' +translation_of: 'Learn/JavaScript/First_steps/Test_your_skills:_Arrays' +--- +
{{learnsidebar}}
+ +

This aim of this skill test is to assess whether you've understood our Arrays article.

+ +
+

Note: You can try out solutions in the interactive editors below, however it may be helpful to download the code and use an online tool such as CodePen, jsFiddle, or Glitch to work on the tasks.
+
+ If you get stuck, then ask us for help — see the {{anch("Assessment or further help")}} section at the bottom of this page.

+
+ +
+

Note: In the examples below, if there is an error in your code it will be outputted into the results panel on the page, to help you try to figure out the answer (or into the browser's JavaScript console, in the case of the downloadable version).

+
+ +

Arrays 1

+ +

Let's start off with some basic array practice. In this task we'd like you to create an array of three items, stored inside a variable called myArray. The items can be anything you want — how about your favourite foods or bands?

+ +

Next, modify the first two items in the array using simple bracket notation and assignment. Then add a new item to the beginning of the array.

+ +

Try updating the live code below to recreate the finished example:

+ +

{{EmbedGHLiveSample("learning-area/javascript/introduction-to-js-1/tasks/arrays/arrays1.html", '100%', 400)}}

+ +
+

Download the starting point for this task to work in your own editor or in an online editor.

+
+ +

Arrays 2

+ +

Now let's move on to another task. Here you are provided with a string to work with. We'd like you to:

+ +
    +
  1. Convert the string into an array, removing the + characters in the process. Save the result in a variable called myArray.
  2. +
  3. Store the length of the array in a variable called arrayLength.
  4. +
  5. Store the last item in the array in a variable called lastItem.
  6. +
+ +

Try updating the live code below to recreate the finished example:

+ +

{{EmbedGHLiveSample("learning-area/javascript/introduction-to-js-1/tasks/arrays/arrays2.html", '100%', 400)}}

+ +
+

Download the starting point for this task to work in your own editor or in an online editor.

+
+ +

Arrays 3

+ +

For this final array task, we provide you with a starting array, and you will work in somewhat the opposite direction. You need to:

+ +
    +
  1. Remove the last item in the array.
  2. +
  3. Add two new names to the end of the array.
  4. +
  5. Go over each item in the array and add its index number after the name inside parentheses, for example Ryu (0). Note that we don't teach how to do this in the Arrays article, so you'll have to do some research.
  6. +
  7. Finally, join the array items together in a single string called myString, with a separator of " - ".
  8. +
+ +

Try updating the live code below to recreate the finished example:

+ +

{{EmbedGHLiveSample("learning-area/javascript/introduction-to-js-1/tasks/arrays/arrays3.html", '100%', 400)}}

+ +
+

Download the starting point for this task to work in your own editor or in an online editor.

+
+ +

Assessment or further help

+ +

You can practice these examples in the Interactive Editors above.

+ +

If you would like your work assessed, or are stuck and want to ask for help:

+ +
    +
  1. Put your work into an online shareable editor such as CodePen, jsFiddle, or Glitch. You can write the code yourself, or use the starting point files linked to in the above sections.
  2. +
  3. Write a post asking for assessment and/or help at the MDN Discourse forum Learning category. Your post should include: +
      +
    • A descriptive title such as "Assessment wanted for Variables 1 skill test".
    • +
    • Details of what you have already tried, and what you would like us to do, e.g. if you are stuck and need help, or want an assessment.
    • +
    • A link to the example you want assessed or need help with, in an online shareable editor (as mentioned in step 1 above). This is a good practice to get into — it's very hard to help someone with a coding problem if you can't see their code.
    • +
    • A link to the actual task or assessment page, so we can find the question you want help with.
    • +
    +
  4. +
diff --git a/files/fr/learn/javascript/first_steps/testes_vos_competence_colon__tableaux/index.html b/files/fr/learn/javascript/first_steps/testes_vos_competence_colon__tableaux/index.html deleted file mode 100644 index 240e934831..0000000000 --- a/files/fr/learn/javascript/first_steps/testes_vos_competence_colon__tableaux/index.html +++ /dev/null @@ -1,87 +0,0 @@ ---- -title: 'Testez vos compétences: Tableaux' -slug: 'Learn/JavaScript/First_steps/Testes_vos_competence:_Tableaux' -translation_of: 'Learn/JavaScript/First_steps/Test_your_skills:_Arrays' ---- -
{{learnsidebar}}
- -

This aim of this skill test is to assess whether you've understood our Arrays article.

- -
-

Note: You can try out solutions in the interactive editors below, however it may be helpful to download the code and use an online tool such as CodePen, jsFiddle, or Glitch to work on the tasks.
-
- If you get stuck, then ask us for help — see the {{anch("Assessment or further help")}} section at the bottom of this page.

-
- -
-

Note: In the examples below, if there is an error in your code it will be outputted into the results panel on the page, to help you try to figure out the answer (or into the browser's JavaScript console, in the case of the downloadable version).

-
- -

Arrays 1

- -

Let's start off with some basic array practice. In this task we'd like you to create an array of three items, stored inside a variable called myArray. The items can be anything you want — how about your favourite foods or bands?

- -

Next, modify the first two items in the array using simple bracket notation and assignment. Then add a new item to the beginning of the array.

- -

Try updating the live code below to recreate the finished example:

- -

{{EmbedGHLiveSample("learning-area/javascript/introduction-to-js-1/tasks/arrays/arrays1.html", '100%', 400)}}

- -
-

Download the starting point for this task to work in your own editor or in an online editor.

-
- -

Arrays 2

- -

Now let's move on to another task. Here you are provided with a string to work with. We'd like you to:

- -
    -
  1. Convert the string into an array, removing the + characters in the process. Save the result in a variable called myArray.
  2. -
  3. Store the length of the array in a variable called arrayLength.
  4. -
  5. Store the last item in the array in a variable called lastItem.
  6. -
- -

Try updating the live code below to recreate the finished example:

- -

{{EmbedGHLiveSample("learning-area/javascript/introduction-to-js-1/tasks/arrays/arrays2.html", '100%', 400)}}

- -
-

Download the starting point for this task to work in your own editor or in an online editor.

-
- -

Arrays 3

- -

For this final array task, we provide you with a starting array, and you will work in somewhat the opposite direction. You need to:

- -
    -
  1. Remove the last item in the array.
  2. -
  3. Add two new names to the end of the array.
  4. -
  5. Go over each item in the array and add its index number after the name inside parentheses, for example Ryu (0). Note that we don't teach how to do this in the Arrays article, so you'll have to do some research.
  6. -
  7. Finally, join the array items together in a single string called myString, with a separator of " - ".
  8. -
- -

Try updating the live code below to recreate the finished example:

- -

{{EmbedGHLiveSample("learning-area/javascript/introduction-to-js-1/tasks/arrays/arrays3.html", '100%', 400)}}

- -
-

Download the starting point for this task to work in your own editor or in an online editor.

-
- -

Assessment or further help

- -

You can practice these examples in the Interactive Editors above.

- -

If you would like your work assessed, or are stuck and want to ask for help:

- -
    -
  1. Put your work into an online shareable editor such as CodePen, jsFiddle, or Glitch. You can write the code yourself, or use the starting point files linked to in the above sections.
  2. -
  3. Write a post asking for assessment and/or help at the MDN Discourse forum Learning category. Your post should include: -
      -
    • A descriptive title such as "Assessment wanted for Variables 1 skill test".
    • -
    • Details of what you have already tried, and what you would like us to do, e.g. if you are stuck and need help, or want an assessment.
    • -
    • A link to the example you want assessed or need help with, in an online shareable editor (as mentioned in step 1 above). This is a good practice to get into — it's very hard to help someone with a coding problem if you can't see their code.
    • -
    • A link to the actual task or assessment page, so we can find the question you want help with.
    • -
    -
  4. -
diff --git a/files/fr/learn/javascript/first_steps/useful_string_methods/index.html b/files/fr/learn/javascript/first_steps/useful_string_methods/index.html new file mode 100644 index 0000000000..d81c3ccb4e --- /dev/null +++ b/files/fr/learn/javascript/first_steps/useful_string_methods/index.html @@ -0,0 +1,479 @@ +--- +title: Méthodes utiles pour les chaînes de caractères +slug: Learn/JavaScript/First_steps/methode_chaine_utile +tags: + - Apprentissage + - Article + - Codage + - Débutant + - JavaScript + - Longueur + - cas + - couper + - indexof + - majuscule + - minuscule + - remplacer +translation_of: Learn/JavaScript/First_steps/Useful_string_methods +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}
+ +

À présent que nous avons vu les bases de la manipulation des chaînes de caractères, allons un cran plus loin et commençons à imaginer les opérations utiles que nous pourrions faire sur les chaînes de caractères avec les méthodes intégrées : trouver la longueur d'une chaîne, assembler ou couper des chaînes, substituer un caractère à un autre dans une chaîne, et plus encore.

+ + + + + + + + + + + + +
Prérequis :Vocabulaire courant de l'informatique, bases de HTML et CSS, compréhension de ce que fait JavaScript.
Objectif :Comprendre que les chaînes de caractères sont des objets, et apprendre à utiliser certaines méthodes basiques disponibles sur ces objets pour manipuler les chaînes.
+ +

Les chaînes de caractères sont des objets

+ +

Nous l'avons déjà dit, et nous le redirons — tout est objet en JavaScript. Lorsque vous créez une chaîne, par exemple en utilisant :

+ +
let string = 'Ceci est une chaîne';
+ +

votre variable devient une instance de l'objet String, et par conséquent possède un grand nombre de propriétés et de méthodes associées. Allez sur la page de l'objet {{jsxref("String")}} et regardez la liste sur le côté de la page !

+ +

Avant que votre cervelle ne commence à bouillir, pas de panique ! Vous n'avez vraiment pas besoin de connaître la plupart des méthodes de cette liste au début de cet apprentissage. Mais il est probable que vous utiliserez  certaines assez souvent. Nous allons les voir maintenant.

+ +

Entrez quelques exemples dans une console vierge. En voici une ci-dessous (vous pouvez aussi ouvrir cette console dans un onglet ou une fenêtre séparés, ou utiliser la console de développement du navigateur si vous préférez).

+ + + +

{{ EmbedLiveSample('Hidden_code', '100%', 300) }}

+ +

Trouver la longueur d'une chaîne

+ +

C'est facile — il suffit d'utiliser la propriété {{jsxref("String.prototype.length", "length")}}. Entrez ceci :

+ +
let browserType = 'mozilla';
+browserType.length;
+ +

Cette commande doit renvoyer le nombre 7, parce que « mozilla » comporte 7 caractères. C'est utile pour de nombreuses raisons ; par exemple, vous pourriez avoir besoin de trouver les longueurs d'une série de noms pour les afficher par taille ou faire savoir à un utilisateur qu'il a entré un nom trop long dans un champ de formulaire à partir du moment où il dépasse une certaine taille.

+ +

Retrouver un caractère donné dans une chaîne

+ +

Dans le même ordre d'idées, il est possible de faire renvoyer tout caractère d'une chaîne avec la notation crochets — c'est-à-dire en ajoutant des crochets ([]) à la fin du nom de la variable. Entre les crochets, mettez le rang du caractère à retrouver ; par exemple, pour retrouver le premier caractère, vous devez  écrire ceci :

+ +
browserType[0];
+ +

Les ordinateurs décomptent à partir de 0, pas de 1 ! Pour retrouver le dernier caractère de n'importe quelle chaîne, on peut utiliser la commande qui suit ; elle combine cette technique avec la propriété length  que nous avons vue plus haut :

+ +
browserType[browserType.length-1];
+ +

La longueur de « mozilla » est de 7 caractères, mais comme le décompte se fait à partir de 0, la position du caractère est 6, d'où la nécessité d'écrire length-1. Vous pourrez utiliser cette propriété pour, par exemple, trouver la première lettre d'une série de chaînes et les trier alphabétiquement.

+ +

Trouver une sous-chaîne à l'intérieur d'une chaîne et l'extraire

+ +
    +
  1. Parfois, vous aurez besoin de trouver si une chaîne est présente à l'intérieur d'une autre chaîne plus grande (on dit en général si une sous-chaîne est présente à l'intérieur d'une chaîne). La méthode {{jsxref("String.prototype.indexOf()", "indexOf()")}} permet de le faire ; elle prend un unique ({{glossary("parameter")}}) — la sous-chaîne recherchée. Essayez : + +
    browserType.indexOf('zilla');
    + La commande donne 2 comme résultat, car la sous-chaîne « zilla » commence à la position 2 (0, 1, 2 — donc au troisième caractère) dans « mozilla ». Un tel code s'utilise pour filtrer des chaînes. Par exemple, vous pourriez avoir une liste d'adresses web et ne vouloir afficher que celles qui contiennent « mozilla ».
  2. +
+ +
    +
  1. On peut faire cela autrement, peut-être plus efficacement encore. Écrivez : +
    browserType.indexOf('vanilla');
    + Cela doit vous donner -1 comme résultat — renvoyé quand la sous-chaîne, en l'occurence « vanilla », n'est pas trouvée dans la chaîne principale.
    +
    + Vous pouvez utiliser cette propriété pour trouver tous les cas de chaînes ne contenant pas la sous-chaîne « mozilla », ou bien la contenant, si vous utilisez l'opérateur négation logique, tel que montré ci-dessous. Vous pourriez faire quelque chose comme : + +
    if(browserType.indexOf('mozilla') !== -1) {
    +  // faire des tas de choses avec la chaîne
    +}
    +
  2. +
  3. Lorsque vous savez où la sous-chaîne commence à l'intérieur de la chaîne, et savez à quel caractère elle prend fin, vous pouvez utiliser {{jsxref("String.prototype.slice()", "slice()")}} pour l'extraire. Voyez ce code : +
    browserType.slice(0,3);
    + Il renvoie « moz » — le premier paramètre est la position du caractère où doit commencer l'extraction, et le second paramètre est la position du caractère se trouvant après le dernier à extraire. Ainsi, l'extraction va de la première position à la dernière, celle-ci non comprise. On peut dire, dans notre cas, que le second paramètre est égal à la longueur de la chaîne retournée.
  4. +
  5. Également, si vous souhaitez extraire tous les caractères après un caractère donné jusqu'à la fin de la chaîne, vous n'avez pas à mettre le second paramètre ! Il suffit d'indiquer la position du caractère à partir duquel vous voulez extraire les caractères restants dans la chaîne. Essayez la commande : +
    browserType.slice(2);
    + Elle renvoie « zilla » — le caractère à la position 2 est « z » et comme nous n'avons pas mis de second paramètre, la sous-chaîne retournée comporte tous les caractères restants de la chaîne.
  6. +
+ +
+

Note : Le second paramètre de slice() est optionnel : s'il n'est pas defini, l'extraction va jusqu'à la fin de la chaîne originale. Il existe aussi d'autres options, allez à la page de {{jsxref("String.prototype.slice()", "slice()")}} pour voir ces autres options.

+
+ +

Changer la casse

+ +

Les méthodes {{jsxref("String.prototype.toLowerCase()", "toLowerCase()")}} et {{jsxref("String.prototype.toUpperCase()", "toUpperCase()")}} s'appliquent à une chaîne et en convertissent tous les caractères, respectivement en minuscules ou en majuscules. C'est utile si, par exemple, vous souhaitez normaliser toutes les données entrées par des utilisateurs avant de les stocker dans une base de données.

+ +

Essayons d'entrer les lignes suivantes et voyons ce qui se passe :

+ +
let radData = 'My NaMe Is MuD';
+radData.toLowerCase();
+radData.toUpperCase();
+ +

Actualiser des parties de chaîne

+ +

Vous pouvez remplacer une sous-chaîne à l'intérieur d'une chaîne avec une autre sous-chaîne à l'aide de la méthode {{jsxref("String.prototype.replace()", "replace()")}}. Cela fonctionne très simplement au niveau basique, bien qu'il soit possible de faire des choses plus avancées, mais nous ne y attarderons pas maintenant.

+ +

La méthode prend deux paramètres — la chaîne que vous voulez remplacer et la chaîne avec laquelle vous voulez la remplacer. Essayez avec cet exemple :

+ +
browserType.replace('moz','van');
+ +

À noter : pour que, dans un programme réel, la variable browserType reflète effectivement la valeur actualisée, il faut assigner à la valeur de la variable le résultat de l'opération ; cette dernière ne met pas à jour automatiquement la valeur de la sous-chaîne. Pour ce faire, il faut écrire : browserType = browserType.replace('moz','van');

+ +

Apprendre en pratiquant

+ +

Dans cette section, vous allez pouvoir vous entraîner à écrire du code de manipulation de chaîne. Dans chacun des exercices ci-dessous, nous avons un tableau de chaînes, une boucle qui traîte chaque valeur dans le tableau et l'affiche dans une liste à puces. Vous n'avez pas besoin de comprendre comment fonctionnent les tableaux ou les boucles dès maintenant — cela vous sera expliqué dans de prochains articles. Tout ce dont vous avez besoin dans chaque cas est d'écrire le code qui va renvoyer les chaînes dans le format souhaité.

+ +

Chaque exemple est accompagné d'un bouton « Réinitialiser », que vous pouvez utiliser pour réinitialiser le code si vous faites une erreur et que vous ne parvenez pas à la corriger, et un bouton « Montrer la solution » sur lequel vous pouvez cliquer pour afficher une réponse possible si jamais vous êtes vraiment bloqué.

+ +

Filtrer des messages de vœux

+ +

Dans ce premier exercice, nous commencerons simplement — nous avons un tableau de carte de voeux, mais nous voulons les trier pour ne lister que les messages concernant Noël. Nous attendons de vous que vous utilisiez un test conditionnel à l'intérieur d'une structure if( ... ), pour tester chaque chaîne et ne l'afficher dans la liste que si elle contient un message concernant Noël.

+ +
    +
  1. Réfléchissez d'abord à comment vérifier que le message concerne Noël. Quelle chaîne est présente dans tous ces messages, et quelle méthode pourriez-vous utiliser pour en tester la présence ?
  2. +
  3. Il vous faudra alors écrire un test conditionnel sous la forme opérande1 opérateur opérande2. La chose à gauche est-elle égale à la chose à droite ? Ou dans notre cas, l'appel de méthode de gauche renvoie-t-il le résultat de droite ?
  4. +
  5. Conseil : dans notre cas, il est probablement plus utile de tester si le résultat de l'appel de notre méthode n'est pas égal à un certain résultat.
  6. +
+ + + +

{{ EmbedLiveSample('Playable_code', '100%', 490) }}

+ +

Remettre les majuscules

+ +

Dans cet exercice, nous avons des noms des villes du Royaume-Uni, mais les majuscules ne sont pas au bon endroit. Nous souhaitons modifier les noms pour qu'ils soient en minuscules à l'exception de la première lettre qui doit être une majuscule. Une bonne manière de faire ceci :

+ +
    +
  1. Convertissez la totalité de la chaîne contenue dans la variable input en minuscules et stockez-la dans une nouvelle variable.
  2. +
  3. Récupérez la première lettre de la chaîne dans cette nouvelle variable et stockez-la dans une autre variable.
  4. +
  5. En utilisant la dernière variable comme une sous-chaîne, remplacez la première lettre de la chaîne en minuscules par la première lettre de la chaîne en minuscules transformé en majuscules. Stockez le résultat de cette procédure de remplacement dans une autre nouvelle variable.
  6. +
  7. Changez la valeur de la variable result afin qu'elle soit égale au résultat final plutôt qu'à input.
  8. +
+ +
+

Note: Un conseil — les paramètres des méthodes de chaîne n'ont pas besoin d'être des chaînes, elle peuvent aussi être des variables, ou même des variables avec une méthode invoquée sur elles.

+
+ + + +

{{ EmbedLiveSample('Playable_code_2', '100%', 450) }}

+ +

Créer de nouvelles chaînes à partir de morceaux

+ +

Dans ce dernier exercice, le tableau contient un lot de chaînes contenant des informations à propos d'arrêts de train dans le nord de l'Angleterre. Les chaînes sont des éléments de données contenant le code en trois lettres de l'arrêt, suivi par des données lisibles par machine, suivi par un point-virgule, et enfin le nom de la station lisible par un humain. Par exemple :

+ +
MAN675847583748sjt567654;Manchester Piccadilly
+ +

Nous voulons extraire le code de la station et son nom, et les associer dans une chaîne avec la structure suivante :

+ +
MAN: Manchester Piccadilly
+ +

Nous vous recommandons de procéder de la manière suivante :

+ +
    +
  1. Extraire le code de trois lettres de la station et le stocker dans une nouvelle variable.
  2. +
  3. Trouver la position du caractère point-virgule.
  4. +
  5. Extraire le nom de la station lisible par un humain en utilisant la position du caractère point virgule comme référence, et le stocker dans une nouvelle variable.
  6. +
  7. Concaténer les deux nouvelles variables et une chaîne pour fabriquer la chaîne finale.
  8. +
  9. Changer la valeur de la variable result pour qu'elle soit égale à la chaîne finale, plutôt qu'à input.
  10. +
+ + + +

{{ EmbedLiveSample('Playable_code_3', '100%', 485) }}

+ +

Conclusion

+ +

Il n'est pas possible d'éluder le fait qu'il est très important de savoir manipuler des mots et des phrases lorsqu'on programme — tout particulièrement en JavaScript, dans la mesure où les sites web servent à la communication entre les personnes. Cet article vous a indiqué, pour l'instant, les bases à connaître pour manipuler les chaînes. Ce sera utile lorsque vous aborderez des sujets plus complexes à l'avenir. Pour suivre, nous allons nous intéresser au dernier grand type de données sur lequel nous devons nous concentrer à court terme — les tableaux.

+ +

{{PreviousMenuNext("Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}

diff --git a/files/fr/learn/javascript/index.html b/files/fr/learn/javascript/index.html new file mode 100644 index 0000000000..a10f2deb2d --- /dev/null +++ b/files/fr/learn/javascript/index.html @@ -0,0 +1,61 @@ +--- +title: JavaScript +slug: Apprendre/JavaScript +tags: + - Débutant + - Développement + - JavaScript + - Modules + - scripts +translation_of: Learn/JavaScript +--- +

{{LearnSidebar}}

+ +

{{Glossary('JavaScript')}} est un langage de programmation qui vous permet de mettre en œuvre des éléments complexes sur des pages Web (une page Web contenant plus que de simples informations statiques). Chaque fois qu'une page affiche des mises à jour de contenu en temps réel, des cartes interactives, des animations graphiques 2D / 3D ou un juke-box vidéo défilant, etc. — vous pouvez parier que JavaScript est probablement impliqué.

+ +

Parcours d'apprentissage

+ +

JavaScript est sans doute plus difficile à apprendre que les technologies connexes telles que HTML et CSS. Avant d'essayer d'apprendre le JavaScript, il est fortement conseillé de se familiariser d'abord avec au moins ces deux technologies, et peut-être aussi avec d'autres. Commencez par travailler sur les modules suivants :

+ + + +

Avoir une expérience antérieure avec d'autres langages de programmation peut également aider.

+ +

Après vous être familiarisé avec les bases de JavaScript, vous devriez être en mesure d'en apprendre davantage sur des sujets plus avancés, par exemple :

+ + + +

Modules

+ +

Cette rubrique contient les modules suivants, dans l'ordre suggéré pour les aborder :

+ +
+
Premiers pas en JavaScript
+
Dans notre premier module JavaScript, nous répondons d'abord à des questions fondamentales telles que «qu'est-ce que le JavaScript ?», «à quoi cela ressemble-t-il ?» et «que peut-il faire ?», avant de passer à votre première expérience pratique d'écriture de JavaScript. Après cela, nous discutons en détail de certaines fonctionnalités clés de JavaScript, telles que les variables, les chaînes, les nombres et les tableaux.
+
JavaScript les blocs
+
Dans ce module, nous continuons de couvrir toutes les fonctions clés fondamentales de JavaScript, en nous concentrant sur les types de blocs de code les plus courants, tels que les instructions conditionnelles, les boucles, les fonctions et les événements. Vous avez déjà vu ce genre de choses dans le cours, mais seulement en passant, nous en discuterons explicitement ici.
+
Introduction aux objets JavaScript
+
En JavaScript, la plupart des éléments sont des objets, depuis les principales fonctionnalités de JavaScript comme les chaînes et les tableaux jusqu'aux API du navigateur construites sur JavaScript. Vous pouvez même créer vos propres objets pour encapsuler des fonctions et des variables associées dans des paquets efficaces. La nature orientée objet de JavaScript est importante à comprendre, si vous voulez aller plus loin dans la connaissance du langage et rédiger un code plus efficace. C'est pourquoi nous avons conçu ce module pour vous aider. Ici, nous enseignons la théorie et la syntaxe des objets en détail, regardons comment créer vos propres objets et expliquons quelles sont les données JSON et comment les utiliser.
+
API Web côté client
+
Lors de l'écriture de JavaScript côté client, pour des sites Web ou des applications, vous n'irez pas très loin avant de commencer à utiliser des interfaces API, pour manipuler différents aspects du navigateur et du système d'exploitation sur lequel le site fonctionne, ou même des données d'autres sites Web ou des services. Dans ce module, nous explorerons quelles sont les API et comment utiliser certaines des API les plus courantes que vous rencontrerez souvent dans votre travail de développement.
+
+ +

Résoudre les problèmes JavaScript courants

+ +

Utiliser JavaScript pour résoudre des problèmes courants fournit des liens vers des sections expliquant comment utiliser JavaScript pour résoudre des problèmes très courants lors de la création d'une page Web.

+ +

Voir aussi

+ +
+
JavaScript sur MDN
+
Principal point d'entrée de la documentation JavaScript de base sur MDN, vous y trouverez de nombreux documents de référence sur tous les aspects du langage JavaScript, ainsi que des tutoriels avancés destinés aux programmeurs en JavaScript expérimentés.
+
Codage des mathématiques
+
Une excellente série de tutoriels vidéo (anglophones) sur les mathématiques que vous devez comprendre pour être un programmeur efficace, par Keith Peters.
+
diff --git a/files/fr/learn/javascript/objects/adding_bouncing_balls_features/index.html b/files/fr/learn/javascript/objects/adding_bouncing_balls_features/index.html new file mode 100644 index 0000000000..36232925ec --- /dev/null +++ b/files/fr/learn/javascript/objects/adding_bouncing_balls_features/index.html @@ -0,0 +1,208 @@ +--- +title: Ajouter des fonctionnalités à notre exercice des balles rebondissantes +slug: >- + Learn/JavaScript/Objects/Ajouter_des_fonctionnalités_à_notre_démo_de_balles_rebondissantes +tags: + - Apprentissage + - CodingScripting + - Débutant + - Evaluation + - JavaScript + - OOJS + - Objet + - Orienté objet +translation_of: Learn/JavaScript/Objects/Adding_bouncing_balls_features +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Objects/Object_building_practice", "", "Learn/JavaScript/Objects")}}
+ +

Dans cet exercice, vous devrez utiliser le jeu des balles rebondissantes de l'article précédent comme base, pour y ajouter de nouvelles fonctionnalitées intéressantes.

+ + + + + + + + + + + + +
Prérequis:Avant de vous lancer dans cet exercice, il est fortement conseillé d'avoir vus et compris tous les précédents articles de ce module.
Objectifs:Tester votre connaissance du Javascript orienté objet en conception et en pratique.
+ +

Pour commencer

+ +

Pour commencer, faite une copie locale de index-finished.html, style.css, et main-finished.js de l'article précédent, dans un nouveau dossier.

+ +
+

Note: Vous pouvez utiliser un site comme JSBin ou Thimble. Vous pouvez copier vos codes HTML, CSS et JavaScript dans l'un d'entre eux. Si celui que vous utilisez ne possède pas de fenêtres séparées pour les différents langages, ajoutez les dans des balises <script>/<style> dans votre code HTML.

+
+ +

Le projet en bref

+ +

Notre jeu des balles est assez sympa, mais maintenant il s'agit de le rendre plus interactif en y ajoutant un viseur controlé par l'utilisateur, qui va détruire une balle si il l'a touche. Nous voulons aussi testé votre capacité en programmation orienté objet en créant un object Shape() dont le viseur et les balles peuvent hériter. Pour terminer nous voulons créer un compteur qui permet d'afficher combien de balle il nous reste encore à détruire.

+ +

Ce screenshot vous donne une idée du résultat final:

+ +

+ + + +

Si vous voulez en savoir plus regardez l'exemple finit finished example (N'en profitez pas pour récupérer le code source !)

+ +

Vos objectifs

+ +

Cette section décrit ce que vous aurez à faire.

+ +

Créons nos nouveaux objets

+ +

Pour commencer, modifions le constructeur de l'objet Ball() pour qu'il devienne le constructeur de Shape() puis créons en un nouveau pour Ball() :

+ +
    +
  1. Le constructeur Shape() devra définir les propriétés x, y, velX, et velY de la même manière que le constructeur Ball() auparavent, mais sans les propriétés color et size.
  2. +
  3. Shape() doit aussi définir une nouvelle propriété exists, qui servira à identifier les balles qu'il reste à détruire dans la fenêtre (celles qui n'on pas encore été détruites). Elle doit retourner un booléen (true/false).
  4. +
  5. Le constructeur Ball() doit hériter des propriétés x, y, velX, velY, et exists du constructeur Shape().
  6. +
  7. Ball() doit aussi définir les propriétés color et size, comme à l'origine.
  8. +
  9. N'oubliez pas de définir le prototype de Ball() et son constructeur de manière approprié.
  10. +
+ +

Les méthodes draw(), update(), et collisionDetect() doivent fonctionnées comme avant, sans être modifiées.

+ +

Vous devrez ajouter un nouveau paramètre au constructeur new Ball() ( ... ) — le paramètre exists doit être le 5ème et être égal à  true.

+ +

Vous pouvez recharger la page — Tout doit fonctionner comme avant même après les modifications que vous avez effectuées sur les objets.

+ +

Définition du EvilCircle() (viseur)

+ +

Il est temps de vous équipez ! — le EvilCircle()! Dans notre jeu nous allons créer un viseur, mais nous allons nous servir de l'objet Shape() pour le définir. Vous voudrez certainement en ajouter un (plusieurs) autre plus tard, qu'un autre joueur ou l'ordinateur pourra contrôler. Vous n'irez probablement pas bien loin avec un seul viseur, mais ce sera suffisant pour le moment !

+ +

Le constructeur du EvilCircle() doit hériter des propriétés x, y, velX, velY, et exists de Shape(), mais velX et velY doivent toujours être égales à 20.

+ +

Vous devriez utiliser quelque chose comme Shape.call(this, x, y, 20, 20, exists);

+ +

Le constructeur doit aussi définir ses propres propriétés:

+ + + +

Une fois de plus, souvenez vous de définir vos propriétés héritées en paramètre du constructeur et de définir le prototype et son constructeur de manière appropriée.

+ +

Définir les méthodes du EvilCircle() (viseur)

+ +

EvilCircle() doit avoir quatre méthodes, comme définie en dessous.

+ +

draw()

+ +

Cette méthode doit avoir la même fonction que celle de Ball(): soit dessiner l'objet dans le canvas. Elle fonctionnera quasiment de la même manière, copiez la fonction Ball.prototype.draw. Puis appliquez les modifications suivantes:

+ + + +

checkBounds()

+ +

Cette méthode à la même fonction que la première partie de Ball() update() — Savoir si le viseur va hors de l'écran, et l'arrêter si besoin. Une fois encore, copié la méthode Ball.prototype.update, mais en effectuant quelques changements:

+ + + +

setControls()

+ +

Cette méthode ajoute un écouteur d'évènement onkeydown à l'objet window ce qui permettra en enfonçant certaine touche du clavier de déplacer le viseur dans la fenêtre. Insérez le code suivant dans la méthode:

+ +
var _this = this;
+window.onkeydown = function(e) {
+    if (e.keyCode === 65) {
+      _this.x -= _this.velX;
+    } else if (e.keyCode === 68) {
+      _this.x += _this.velX;
+    } else if (e.keyCode === 87) {
+      _this.y -= _this.velY;
+    } else if (e.keyCode === 83) {
+      _this.y += _this.velY;
+    }
+  }
+ +

Quand une touche est enfoncée, la propriété keyCode de l'objet event est consultée pour savoir quelle touche est enfoncée. Si c'est une des touches spécifiée, alors le viseur ce déplacera à gauche, à droite, en haut ou en bas.

+ + + +

collisionDetect()

+ +

Cette méthode fonctionne d'une manière similaire à Ball() collisionDetect(), copier celle-ci pour vous en servir comme base. Il y a deux différences:

+ + + +

Insérer le viseur dans notre programme

+ +

Maintenant que nous avons définit notre viseur, on a besoin de le faire apparaître à l'écran. Pour ce faire on doit appliquer quelques modifications à la fonction loop().

+ + + +

Implémenter le compteur de score

+ +

Pour implémenter le compteur de score, suivez les étapes suivantes:

+ +
    +
  1. Dans votre fichier HTML, ajoutez un élement {{HTMLElement("p")}} qui contiendra le texte suivant "Ball count: ", juste en dessous de l'élément {{HTMLElement("h1")}} .
  2. +
  3. Dans votre fichier CSS, ajouter les règlesz suivantes: +
    p {
    +  position: absolute;
    +  margin: 0;
    +  top: 35px;
    +  right: 5px;
    +  color: #aaa;
    +}
    +
  4. +
  5. Dans votre JavaScript, effectuez les modifications suivante: +
      +
    • Créez une variable qui contiendra la référence vers le paragraphe.
    • +
    • Stocker et afficher le nombre de balle présentent à l'écran.
    • +
    • Incrémentez le compteur de balle à chaque fois qu'une balle apparait à l'écran.
    • +
    • Décrementez le compteur à chaque fois qu'une balle est détruite par le viseur.
    • +
    +
  6. +
+ +

Conseils et astuces

+ + + +

Evaluation

+ +

Si vous effectuez cette évalutation dans le cadre d'un cours, vous devriez pouvoir fournir votre travail à votre professeur/mentor pour correction. Si vous apprenez par vous même, vous pouvez obtenir la correction sur discussion thread for this exercise, ou sur #mdn IRC channel sur Mozilla IRC. Tout d'abord effectuez cet exercice — vous n'obtiendrez jamais rien en trichant !

+ +

{{PreviousMenuNext("Learn/JavaScript/Objects/Object_building_practice", "", "Learn/JavaScript/Objects")}}

+ +

Dans ce Module

+ + diff --git "a/files/fr/learn/javascript/objects/ajouter_des_fonctionnalit\303\251s_\303\240_notre_d\303\251mo_de_balles_rebondissantes/index.html" "b/files/fr/learn/javascript/objects/ajouter_des_fonctionnalit\303\251s_\303\240_notre_d\303\251mo_de_balles_rebondissantes/index.html" deleted file mode 100644 index 36232925ec..0000000000 --- "a/files/fr/learn/javascript/objects/ajouter_des_fonctionnalit\303\251s_\303\240_notre_d\303\251mo_de_balles_rebondissantes/index.html" +++ /dev/null @@ -1,208 +0,0 @@ ---- -title: Ajouter des fonctionnalités à notre exercice des balles rebondissantes -slug: >- - Learn/JavaScript/Objects/Ajouter_des_fonctionnalités_à_notre_démo_de_balles_rebondissantes -tags: - - Apprentissage - - CodingScripting - - Débutant - - Evaluation - - JavaScript - - OOJS - - Objet - - Orienté objet -translation_of: Learn/JavaScript/Objects/Adding_bouncing_balls_features ---- -
{{LearnSidebar}}
- -
{{PreviousMenuNext("Learn/JavaScript/Objects/Object_building_practice", "", "Learn/JavaScript/Objects")}}
- -

Dans cet exercice, vous devrez utiliser le jeu des balles rebondissantes de l'article précédent comme base, pour y ajouter de nouvelles fonctionnalitées intéressantes.

- - - - - - - - - - - - -
Prérequis:Avant de vous lancer dans cet exercice, il est fortement conseillé d'avoir vus et compris tous les précédents articles de ce module.
Objectifs:Tester votre connaissance du Javascript orienté objet en conception et en pratique.
- -

Pour commencer

- -

Pour commencer, faite une copie locale de index-finished.html, style.css, et main-finished.js de l'article précédent, dans un nouveau dossier.

- -
-

Note: Vous pouvez utiliser un site comme JSBin ou Thimble. Vous pouvez copier vos codes HTML, CSS et JavaScript dans l'un d'entre eux. Si celui que vous utilisez ne possède pas de fenêtres séparées pour les différents langages, ajoutez les dans des balises <script>/<style> dans votre code HTML.

-
- -

Le projet en bref

- -

Notre jeu des balles est assez sympa, mais maintenant il s'agit de le rendre plus interactif en y ajoutant un viseur controlé par l'utilisateur, qui va détruire une balle si il l'a touche. Nous voulons aussi testé votre capacité en programmation orienté objet en créant un object Shape() dont le viseur et les balles peuvent hériter. Pour terminer nous voulons créer un compteur qui permet d'afficher combien de balle il nous reste encore à détruire.

- -

Ce screenshot vous donne une idée du résultat final:

- -

- - - -

Si vous voulez en savoir plus regardez l'exemple finit finished example (N'en profitez pas pour récupérer le code source !)

- -

Vos objectifs

- -

Cette section décrit ce que vous aurez à faire.

- -

Créons nos nouveaux objets

- -

Pour commencer, modifions le constructeur de l'objet Ball() pour qu'il devienne le constructeur de Shape() puis créons en un nouveau pour Ball() :

- -
    -
  1. Le constructeur Shape() devra définir les propriétés x, y, velX, et velY de la même manière que le constructeur Ball() auparavent, mais sans les propriétés color et size.
  2. -
  3. Shape() doit aussi définir une nouvelle propriété exists, qui servira à identifier les balles qu'il reste à détruire dans la fenêtre (celles qui n'on pas encore été détruites). Elle doit retourner un booléen (true/false).
  4. -
  5. Le constructeur Ball() doit hériter des propriétés x, y, velX, velY, et exists du constructeur Shape().
  6. -
  7. Ball() doit aussi définir les propriétés color et size, comme à l'origine.
  8. -
  9. N'oubliez pas de définir le prototype de Ball() et son constructeur de manière approprié.
  10. -
- -

Les méthodes draw(), update(), et collisionDetect() doivent fonctionnées comme avant, sans être modifiées.

- -

Vous devrez ajouter un nouveau paramètre au constructeur new Ball() ( ... ) — le paramètre exists doit être le 5ème et être égal à  true.

- -

Vous pouvez recharger la page — Tout doit fonctionner comme avant même après les modifications que vous avez effectuées sur les objets.

- -

Définition du EvilCircle() (viseur)

- -

Il est temps de vous équipez ! — le EvilCircle()! Dans notre jeu nous allons créer un viseur, mais nous allons nous servir de l'objet Shape() pour le définir. Vous voudrez certainement en ajouter un (plusieurs) autre plus tard, qu'un autre joueur ou l'ordinateur pourra contrôler. Vous n'irez probablement pas bien loin avec un seul viseur, mais ce sera suffisant pour le moment !

- -

Le constructeur du EvilCircle() doit hériter des propriétés x, y, velX, velY, et exists de Shape(), mais velX et velY doivent toujours être égales à 20.

- -

Vous devriez utiliser quelque chose comme Shape.call(this, x, y, 20, 20, exists);

- -

Le constructeur doit aussi définir ses propres propriétés:

- - - -

Une fois de plus, souvenez vous de définir vos propriétés héritées en paramètre du constructeur et de définir le prototype et son constructeur de manière appropriée.

- -

Définir les méthodes du EvilCircle() (viseur)

- -

EvilCircle() doit avoir quatre méthodes, comme définie en dessous.

- -

draw()

- -

Cette méthode doit avoir la même fonction que celle de Ball(): soit dessiner l'objet dans le canvas. Elle fonctionnera quasiment de la même manière, copiez la fonction Ball.prototype.draw. Puis appliquez les modifications suivantes:

- - - -

checkBounds()

- -

Cette méthode à la même fonction que la première partie de Ball() update() — Savoir si le viseur va hors de l'écran, et l'arrêter si besoin. Une fois encore, copié la méthode Ball.prototype.update, mais en effectuant quelques changements:

- - - -

setControls()

- -

Cette méthode ajoute un écouteur d'évènement onkeydown à l'objet window ce qui permettra en enfonçant certaine touche du clavier de déplacer le viseur dans la fenêtre. Insérez le code suivant dans la méthode:

- -
var _this = this;
-window.onkeydown = function(e) {
-    if (e.keyCode === 65) {
-      _this.x -= _this.velX;
-    } else if (e.keyCode === 68) {
-      _this.x += _this.velX;
-    } else if (e.keyCode === 87) {
-      _this.y -= _this.velY;
-    } else if (e.keyCode === 83) {
-      _this.y += _this.velY;
-    }
-  }
- -

Quand une touche est enfoncée, la propriété keyCode de l'objet event est consultée pour savoir quelle touche est enfoncée. Si c'est une des touches spécifiée, alors le viseur ce déplacera à gauche, à droite, en haut ou en bas.

- - - -

collisionDetect()

- -

Cette méthode fonctionne d'une manière similaire à Ball() collisionDetect(), copier celle-ci pour vous en servir comme base. Il y a deux différences:

- - - -

Insérer le viseur dans notre programme

- -

Maintenant que nous avons définit notre viseur, on a besoin de le faire apparaître à l'écran. Pour ce faire on doit appliquer quelques modifications à la fonction loop().

- - - -

Implémenter le compteur de score

- -

Pour implémenter le compteur de score, suivez les étapes suivantes:

- -
    -
  1. Dans votre fichier HTML, ajoutez un élement {{HTMLElement("p")}} qui contiendra le texte suivant "Ball count: ", juste en dessous de l'élément {{HTMLElement("h1")}} .
  2. -
  3. Dans votre fichier CSS, ajouter les règlesz suivantes: -
    p {
    -  position: absolute;
    -  margin: 0;
    -  top: 35px;
    -  right: 5px;
    -  color: #aaa;
    -}
    -
  4. -
  5. Dans votre JavaScript, effectuez les modifications suivante: -
      -
    • Créez une variable qui contiendra la référence vers le paragraphe.
    • -
    • Stocker et afficher le nombre de balle présentent à l'écran.
    • -
    • Incrémentez le compteur de balle à chaque fois qu'une balle apparait à l'écran.
    • -
    • Décrementez le compteur à chaque fois qu'une balle est détruite par le viseur.
    • -
    -
  6. -
- -

Conseils et astuces

- - - -

Evaluation

- -

Si vous effectuez cette évalutation dans le cadre d'un cours, vous devriez pouvoir fournir votre travail à votre professeur/mentor pour correction. Si vous apprenez par vous même, vous pouvez obtenir la correction sur discussion thread for this exercise, ou sur #mdn IRC channel sur Mozilla IRC. Tout d'abord effectuez cet exercice — vous n'obtiendrez jamais rien en trichant !

- -

{{PreviousMenuNext("Learn/JavaScript/Objects/Object_building_practice", "", "Learn/JavaScript/Objects")}}

- -

Dans ce Module

- - diff --git a/files/fr/learn/javascript/objects/heritage/index.html b/files/fr/learn/javascript/objects/heritage/index.html deleted file mode 100644 index 9359b6f4ee..0000000000 --- a/files/fr/learn/javascript/objects/heritage/index.html +++ /dev/null @@ -1,260 +0,0 @@ ---- -title: L'héritage au sein de JavaScript -slug: Learn/JavaScript/Objects/Heritage -tags: - - Apprendre - - Article - - Débutant - - Héritage - - JS Orienté Objet - - JavaScript - - Objet - - Programmation orientée objet - - Prototype -translation_of: Learn/JavaScript/Objects/Inheritance ---- -
-

{{LearnSidebar}}

- -

{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}

- -

Les présentations ayant été faites pour les concepts du JavaScript orienté objet, cet article détaille comment il est possible de créer une classe fille qui hérite des propriétés de sa classe mère. Nous verrons ensuite quelques conseils quant à l'utilisation du JavaScript orienté objet.

- - - - - - - - - - - - -
Pré-requis :Une connaissance générale de l'informatique, des notions d'HTML et CSS, une connaissance des bases en JavaScript (voir Premiers pas et Blocs de construction) ainsi que des notions de JavaScript orienté objet (JSOO) (voir Introduction aux objets).
Objectif :Comprendre comment implémenter l'héritage en JavaScript.
- -

Héritage prototypique

- -

Nous avons déjà vu le concept d'héritage en action, nous avons vu comment la chaîne de prototypage fonctionnait, et comment les propriétés de cette chaîne sont lues de manière ascendante. En revanche,nous n'avons utilisé pratiquement que quelques fonctionnalités déjà intégrées dans le navigateur pour le faire. Comment créer un objet JavaScript qui hérite d'un autre objet ?

- -

Certains pensent que JavaScript n'est pas un véritable langage orienté objet. Dans les langages orientés objets classiques, on définit des classes objet et on peut ensuite définir laquelle hérite d'une autre (voir C++ inheritance en anglais pour des exemples simples). JavasScript utilise une approche différente : les objets héritant d'un autre n'ont pas de fonctionnalités copiées d'un autre objet, au lieu de ça, ils héritent des fonctionnalités via les liens de la chaîne de prototypage (on parle alors d'un héritage prototypique).

- -

Voyons comment cela se passe avec un exemple concret.

- -

Pour commencer

- -

Tout d'abord, faites une copie du fichier oojs-class-inheritance-start.html (voir la démo). Vous y trouverez le constructeur Personne() que nous avons utilisé jusque là dans l'ensemble des modules, néanmoins il y a un léger changement : nous n'avons défini que les attributs au sein du constructeur.

- -
function Personne(prenom, nom, age, genre, interets) {
-  this.nom = {
-    prenom,
-    nom
-  };
-  this.age = age;
-  this.genre = genre;
-  this.interets = interets;
-};
- -

L'ensemble des méthodes est défini dans le prototype :

- -
Personne.prototype.saluer = function() {
-  alert('Salut! Je suis ' + this.nom.prenom + '.');
-};
- -

Essayons de créer une classe Professeur similaire à celle que nous avons utilisée jusqu'ici dans les autres modules d'initiations à l'approche objet. Ainsi, cette classe hérite de Personne mais possède aussi :

- -
    -
  1. Un nouvel attribut matière — qui contiendra la matière que le professeur enseigne.
  2. -
  3. Une méthode saluer un peu plus élaborée, qui sera un peu plus formelle que la méthode de base, cela sera plus approprié, lorsque le professeur s'adrressera à des étudiants, par exemple.
  4. -
- -

Définissons le constructeur Professeur()

- -

La première chose à faire est de créer le constructeur Professeur() via l'ajout du code suivant :

- -
function Professeur(prenom, nom, age, genre, interets, matiere) {
-  Personne.call(this, prenom, nom, age, genre, interets);
-
-  this.matiere = matiere;
-}
- -

Cela ressemble beaucoup au constructeur Personne mais il y a quelque chose que nous n'avons pas encore vu : la fonction call(). Cette fonction permet d'appeler une fonction définie ailleurs dans le contexte actuel. Le premier paramètre spécifie la valeur de this que l'on souhaite utiliser lors que l'on utilisera la fonction, les paramètres suivants seront les paramètres qui pourront être passés en arguments lorsqu'elle sera appelée.

- -

Nous voulons que le constructeur Professeur() aie les mêmes attributs que Personne(), nous les spécifions donc dans l'appel fait via la fonction call().

- -

La dernière ligne au sein du constructeur sert simplement à définir l'attribut matière que les professeurs enseignent, ce qui n'est pas valable pour les personnes génériques.

- -

Notez que nous aurions très bien pu écrire tout simplement ceci :

- -
function Professeur(prenom, nom, age, genre, interets, matiere) {
-  this.nom_complet = {
-    prenom,
-    nom
-  };
-  this.age = age;
-  this.genre = genre;
-  this.interets = interets;
-  this.matiere = matiere;
-}
- -

Cependant cela aurait eu pour effet de redéfinir les attributs à nouveau, sans les hériter de Personne(), ce qui n'est pas vraiment le but que nous voulons atteindre lorsque l'on parle de l'héritage, cela rajoute aussi des lignes de code inutiles.

- -

 

- -

Hériter d'un constructeur sans paramètres

- -

Notez que si les valeurs des propriétés du constructeur dont vous héritez ne proviennent pas de paramètres, vous n'avez nullement besoin de les specifier comme arguments additionnels dans l'appel de la fonction call(). Donc, par exemple, si vous avez quelque chose d'aussi simple que ceci :

- -
function Brick() {
-  this.width = 10;
-  this.height = 20;
-}
- -

Vous pouvez hériter des propriétés width et height en procédant comme ceci (Mais  également en suivant bien sûr les différentes étapes décrites ci dessous) :

- -
function BlueGlassBrick() {
-  Brick.call(this);
-
-  this.opacity = 0.5;
-  this.color = 'blue';
-}
- -

Notez que nous n'avons spécifié que this au sein de call() — Aucun autre paramètre n'est requis puisque nous n'héritons ici d'aucune propriété provenant de la classe parente qui soit spécifiée via paramètres.  

- -

Définir le prototype de Professeur() et son constructeur référent.

- -

Pour le moment tout va bien, mais nous avons un petit problème. Nous avons défini un  nouveau constructeur et ce dernier possède une propriété prototype, qui par défaut ne contient qu'une référence à la fonction constructrice elle même. En revanche il ne contient pas les méthodes de la propriété prototype du constructeur Personne(). Pour le constater, vous pouvez par exemple entrer Professeur.prototype.constructor dans la console JavaScript pour voir ce qu'il en est. Le nouveau constructeur n'a en aucun cas hérité de ces méthodes. Pour le constater, comparez les sorties de Personne.prototype.saluer et de Professeur.prototype.saluer

- -

Notre classe Professeur() doit hériter des méthodes définies dans le prototype de Personne(). Aussi comment procéder pour obtenir ce résultat ?

- -

Ajoutez la ligne suivante à la suite du bloc de code que nous venons d'ajouter :

- -
Professeur.prototype = Object.create(Personne.prototype);
- -
    -
  1. Ici, notre ami create() vient nous aider à nouveau. Dans ce cas, on l'utilise afin de créer un nouvel objet que nous assignons à Professeur.prototype. Le nouvel objet possède Personne.prototype désormais comme son prototype et héritera ainsi, si et quand le besoin se fera sentir, de toutes les méthodes disponible sur Personne.prototype
  2. -
  3. Nous avons également besoin de faire encore une chose avant de continuer. Après avoir ajouté la ligne précédente, le constructeur du prototype de Professeur() est désormais équivalent à celui de Personne(), parce que nous avons défini Professeur.prototype pour référencer un objet qui hérite ses propriétés de  Personne.prototype ! Essayez, après avoir sauvegardé votre code et rechargé la page, d'entrer Professeur.prototype.constructor dans la console pour vérifier.
  4. -
  5. Cela peut devenir problématique, autant le corriger dès maintenant. C'est possible via l'ajout de la ligne de code suivante à la fin : -
    Professeur.prototype.constructor = Professeur;
    -
  6. -
  7. -

    A présent, si vous sauvegardez et rafraichissez après avoir écrit Professeur.prototype.constructor, cela devrait retourner Professeur(), et en plus nous héritons maintenant de Personne() !

    -
  8. -
- -

Donner au prototype de Professeur() une nouvelle fonction saluer()

- -

Pour terminer notre code, nous devons définir une nouvelle fonction saluer() sur le constructeur de Professeur().

- -

La façon la plus facile d'accomplir cela est de la définir sur le prototype de Professeur() — ajoutez ceci à la suite de votre code :

- -
Professeur.prototype.saluer = function() {
-  var prefix;
-
-  if (this.genre === 'mâle' || this.genre === 'Mâle' || this.genre === 'm' || this.genre === 'M') {
-    prefix = 'M.';
-  } else if (this.genre === 'femelle' || this.genre === 'Femelle' || this.genre === 'f' || this.genre === 'F') {
-    prefix = 'Mme';
-  } else {
-    prefix = '';
-  }
-
-  alert('Bonjour. Mon nom est ' + prefix + ' ' + this.nom_complet.nom + ', et j\'enseigne ' + this.matiere + '.');
-};
- -

Ceci affiche la salutation du professeur, qui utilise le titre de civilité approprié à son genre, au moyen d'une instruction conditionnelle.

- -

 

- -

Exécuter l'exemple

- -

Une fois tout le code saisi, essayez de créer une instance d'objet Professeur() en ajoutant à la fin de votre JavaScript (ou à l'endroit de votre choix) :

- -
var professeur1 = new Professeur('Cédric', 'Villani', 44, 'm', ['football', 'cuisine'], 'les mathématiques');
- -

Sauvegardez et actualisez, et essayez d'accéder aux propriétés et méthodes de votre nouvel objet professeur1, par exemple :

- -
professeur1.nom_complet.nom;
-professeur1.interets[0];
-professeur1.bio();
-professeur1.matiere;
-professeur1.saluer();Ffa
- -

Tout cela devrait parfaitement fonctionner. Les instructions des lignes 1,2,3  et 6 accèdent à des membres hérités de la classe générique Personne() via son constructeur, tandis que la ligne 4 accède de façon plus spécifique à un membre qui n'est disponible que via le constructeur de la classe spécialisée Professeur().

- -

Note: Si vous rencontrez un problème afin de faire fonctionner ce code comparez le à notre version finalisée (Ou regarder tourner notre demo en ligne).

- -

La méthode que nous avons détaillée ici n'est pas la seule permettant de mettre en place l'héritage de classes en JavaScript, mais elle fonctionne parfaitement et elle vous permet d'avoir une bonne idée de comment implémenter l'héritage en JavaScript.

- -

Vous pourriez également être intéressé par certaines des nouvelles fonctionnalités de {{glossary("ECMAScript")}} qui nous permettent de mettre en place l'héritage d'une façon beaucoup plus élégante en JavaScript (Voir Classes). Nous ne les avons pas développées ici parce qu'elles ne sont actuellement pas supportées par tous les navigateurs. Toutes les autres constructions dont nous avons discuté dans cette série d'articles sont supportées par IE9 et les versions moins récentes et il existe des méthodes qui prennent plus en  charge les navigateurs moins récents.

- -

Un moyen habituel est d'utiliser les librairies JavaScript — La plupart des options populaires ont une sélection de fonctionnalités disponibles pour réaliser l'héritage plus facilement et plus rapidement.

- -

CoffeeScript par exemple fournit les fonctionnalités class, extends, etc.

- -

Un exercice plus complexe.

- -

Dans notre section sur la programmation orientée objet nous avons également inclus  une classe Etudiant comme un concept qui hérite de toutes les fonctionnalités de la classe Personne, et qui a également une méthode saluer() differente de celle de Personne qui est beaucoup moins formelle que la méthode saluer() de Professeur(). Jetez un oeil à ce à quoi ressemble la méthode saluer() de la classe Etudiant dans cette section et essayez d'implémenter votre propre constructeur Etudiant() qui hérite de toutes les fonctionnalités de Personne() et la fonction saluer() différente.

- -

Note: Si vous rencontrez un problème afin de faire fonctionner ce code comparez le à notre version finalisée (Ou regarder tourner notre demo en ligne).

- -

Résumé sur les membres de l'Objet

- -

Pour résumer, vous avez de façon basique trois types de propriétés/méthodes à prendre en compte :

- -
    -
  1. Celles définies au sein d'un constructeur et passées en paramètres aux instances de l'objet. Celles là ne sont pas difficiles à repérer — Dans votre propre code personnalisé, elles sont les membres définis en utilisant les lignes comme this.x = x ; Dans les codes préconstruits propres aux navigateurs, ils sont les membres seulement accessibles aux instances d'objet (usuellement créés en appelant un constructeur via l'utilisation du mot clé new, exemple : var myInstance = new myConstructor()).
  2. -
  3. Celles définies directement sur les constructeurs eux mêmes et accessibles uniquement sur les constructeurs. Celles là sont communément présentes uniquement dans les objets préconstruits des navigateurs et sont reconnus par le fait d'être directement chaînées sur un constructeur et non sur une instance. Par exemple, Object.keys().
  4. -
  5. Celles définies sur un prototype de constructeur qui sont héritées par toutes les instances des classes d'objet. Celles là incluent n'importe quel membre défini sur un prototype de constructeur, exemple : myConstructor.prototype.x().
  6. -
- -

Si vous êtes encore dans la confusion par rapport aux différents types ne vous inquiétez pas c'est normal — vous êtes encore entrain d'apprendre et la familiarité apparaîtra avec la pratique.

- -

Quand devez-vous utiliser  l'héritage en JavaScript?

- -

Particulièrement après ce dernier article, vous pourriez penser "woa c'est compliqué". Bien, vous avez vu juste, prototypes et héritages représentent une partie des aspects les plus complexes de JavaScript, mais une bonne partie de la puissance et de la flexibilité de JavaScript vient de sa structure Objet et de l'héritage et il est vraiment très important de comprendre comment cela fonctionne. 

- -

D'une certaine manière, vous utilisez l'héritage à plein temps — Que vous utilisiez différentes fonctionnalités d'une WebAPI , ou une méthode/propriété définie par défaut  sur un objet prédéfini du navigateur que vous invoquez sur vos chaînes de caractères, tableaux etc., vous utilisez de façon implicite l'héritage. 

- -

En termes d'utilisation de l'héritage dans votre propre code, vous ne l'utiliserez probablement pas si souvent et spécialement pour débuter avec, et dans les petits projets — C'est une perte de temps d'utiliser les objets et l'héritage par amour pour cette pratique quand vous n'en avez pas besoin. Mais à mesure que les bases de votre code s'élargissent vous trouverez cette façon de faire probablement très utile. Si vous trouvez utile et plus pratique de commencer en créant un certain nombre d'objets spécialisés partageant les mêmes fonctionnalités, alors créer un objet générique qui contiendra toutes les fonctionnalités communes dont les objets spécialisés hériteront vous apparaîtra être une pratique peut être plus confortable et efficace par la suite. 

- -

Note: A cause de la manière dont JavaScript fonctionne, avec la chaîne de prototype, etc., le partage de fonctionnalités entre objet est souvent appelée délégation — Les objets spécialisés délèguent cette fonctionnalité à l'objet de type générique. C'est certainement beaucoup plus précis que de l'appeler héritage, puisque la fonctionnalité "héritée" n'est pas copiée dans les objets qui "héritent". Au contraire, elle demeure dans l'objet générique.

- -

Lorsque vous utilisez l'héritage, il est conseillé de ne pas avoir trop de degrés d'héritage et de toujours garder minutieusement trace de l'endroit où vous définissez vos propriétés et méthodes. Il est possible de commencer à écrire un code qui modifie temporairement les prototypes des objets prédéfinis du navigateur mais vous ne devriez pas le faire à moins que n'ayiez une très bonne raison. Trop de degrés d'héritages peut conduire à une confusion sans fin et une peine sans fin quand vous essayez de déboguer un tel code. 

- -

En définitive, les objets sont juste une autre forme de réutilisation de code comme les fonctions et les boucles avec leurs propres rôles et avantages. Si vous trouvez utile de créer un lot de variables et fonctions relatives et que vous voulez les retracer ensemble et les empaqueter de façon ordonnée, un objet est une bonne idée. Les objets sont également très utiles quand vous souhaitez passer une collection de données d'un endroit à un autre. Toutes ces choses peuvent être accomplies sans l'utilisation d'un constructeur ou de l'héritage. Si vous n'avez besoin que d'une seule instance, l'utilisation d'un simple objet littéral serait certainement un choix beaucoup plus judicieux et vous n'avez certainement pas besoin de l'héritage.

- -

Résumé

- -

Cet article a couvert le reste du coeur de la théorie du JSOO et des syntaxes que nous pensons que vous devriez connaître maintenant. A cet stade vous devriez comprendre l'objet JavaScript et les bases de la POO, les prototypes et l'héritage par prototype, comment créer les classes (constructeurs) et les instances d'objet, ajouter des fonctionnalités aux classes, et créer des sous classes qui héritent d'autres classes. 

- -

Dans le prochain article, nous jetterons un regard sur comment travailler avec le (JSON),  un format commun d'échange de données écrit en utilisant les objets JavaScript.

- -

Voir aussi

- - - -

{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}

- -

 

- -

Dans ce module

- - - -

 

-
- -

 

diff --git a/files/fr/learn/javascript/objects/inheritance/index.html b/files/fr/learn/javascript/objects/inheritance/index.html new file mode 100644 index 0000000000..9359b6f4ee --- /dev/null +++ b/files/fr/learn/javascript/objects/inheritance/index.html @@ -0,0 +1,260 @@ +--- +title: L'héritage au sein de JavaScript +slug: Learn/JavaScript/Objects/Heritage +tags: + - Apprendre + - Article + - Débutant + - Héritage + - JS Orienté Objet + - JavaScript + - Objet + - Programmation orientée objet + - Prototype +translation_of: Learn/JavaScript/Objects/Inheritance +--- +
+

{{LearnSidebar}}

+ +

{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}

+ +

Les présentations ayant été faites pour les concepts du JavaScript orienté objet, cet article détaille comment il est possible de créer une classe fille qui hérite des propriétés de sa classe mère. Nous verrons ensuite quelques conseils quant à l'utilisation du JavaScript orienté objet.

+ + + + + + + + + + + + +
Pré-requis :Une connaissance générale de l'informatique, des notions d'HTML et CSS, une connaissance des bases en JavaScript (voir Premiers pas et Blocs de construction) ainsi que des notions de JavaScript orienté objet (JSOO) (voir Introduction aux objets).
Objectif :Comprendre comment implémenter l'héritage en JavaScript.
+ +

Héritage prototypique

+ +

Nous avons déjà vu le concept d'héritage en action, nous avons vu comment la chaîne de prototypage fonctionnait, et comment les propriétés de cette chaîne sont lues de manière ascendante. En revanche,nous n'avons utilisé pratiquement que quelques fonctionnalités déjà intégrées dans le navigateur pour le faire. Comment créer un objet JavaScript qui hérite d'un autre objet ?

+ +

Certains pensent que JavaScript n'est pas un véritable langage orienté objet. Dans les langages orientés objets classiques, on définit des classes objet et on peut ensuite définir laquelle hérite d'une autre (voir C++ inheritance en anglais pour des exemples simples). JavasScript utilise une approche différente : les objets héritant d'un autre n'ont pas de fonctionnalités copiées d'un autre objet, au lieu de ça, ils héritent des fonctionnalités via les liens de la chaîne de prototypage (on parle alors d'un héritage prototypique).

+ +

Voyons comment cela se passe avec un exemple concret.

+ +

Pour commencer

+ +

Tout d'abord, faites une copie du fichier oojs-class-inheritance-start.html (voir la démo). Vous y trouverez le constructeur Personne() que nous avons utilisé jusque là dans l'ensemble des modules, néanmoins il y a un léger changement : nous n'avons défini que les attributs au sein du constructeur.

+ +
function Personne(prenom, nom, age, genre, interets) {
+  this.nom = {
+    prenom,
+    nom
+  };
+  this.age = age;
+  this.genre = genre;
+  this.interets = interets;
+};
+ +

L'ensemble des méthodes est défini dans le prototype :

+ +
Personne.prototype.saluer = function() {
+  alert('Salut! Je suis ' + this.nom.prenom + '.');
+};
+ +

Essayons de créer une classe Professeur similaire à celle que nous avons utilisée jusqu'ici dans les autres modules d'initiations à l'approche objet. Ainsi, cette classe hérite de Personne mais possède aussi :

+ +
    +
  1. Un nouvel attribut matière — qui contiendra la matière que le professeur enseigne.
  2. +
  3. Une méthode saluer un peu plus élaborée, qui sera un peu plus formelle que la méthode de base, cela sera plus approprié, lorsque le professeur s'adrressera à des étudiants, par exemple.
  4. +
+ +

Définissons le constructeur Professeur()

+ +

La première chose à faire est de créer le constructeur Professeur() via l'ajout du code suivant :

+ +
function Professeur(prenom, nom, age, genre, interets, matiere) {
+  Personne.call(this, prenom, nom, age, genre, interets);
+
+  this.matiere = matiere;
+}
+ +

Cela ressemble beaucoup au constructeur Personne mais il y a quelque chose que nous n'avons pas encore vu : la fonction call(). Cette fonction permet d'appeler une fonction définie ailleurs dans le contexte actuel. Le premier paramètre spécifie la valeur de this que l'on souhaite utiliser lors que l'on utilisera la fonction, les paramètres suivants seront les paramètres qui pourront être passés en arguments lorsqu'elle sera appelée.

+ +

Nous voulons que le constructeur Professeur() aie les mêmes attributs que Personne(), nous les spécifions donc dans l'appel fait via la fonction call().

+ +

La dernière ligne au sein du constructeur sert simplement à définir l'attribut matière que les professeurs enseignent, ce qui n'est pas valable pour les personnes génériques.

+ +

Notez que nous aurions très bien pu écrire tout simplement ceci :

+ +
function Professeur(prenom, nom, age, genre, interets, matiere) {
+  this.nom_complet = {
+    prenom,
+    nom
+  };
+  this.age = age;
+  this.genre = genre;
+  this.interets = interets;
+  this.matiere = matiere;
+}
+ +

Cependant cela aurait eu pour effet de redéfinir les attributs à nouveau, sans les hériter de Personne(), ce qui n'est pas vraiment le but que nous voulons atteindre lorsque l'on parle de l'héritage, cela rajoute aussi des lignes de code inutiles.

+ +

 

+ +

Hériter d'un constructeur sans paramètres

+ +

Notez que si les valeurs des propriétés du constructeur dont vous héritez ne proviennent pas de paramètres, vous n'avez nullement besoin de les specifier comme arguments additionnels dans l'appel de la fonction call(). Donc, par exemple, si vous avez quelque chose d'aussi simple que ceci :

+ +
function Brick() {
+  this.width = 10;
+  this.height = 20;
+}
+ +

Vous pouvez hériter des propriétés width et height en procédant comme ceci (Mais  également en suivant bien sûr les différentes étapes décrites ci dessous) :

+ +
function BlueGlassBrick() {
+  Brick.call(this);
+
+  this.opacity = 0.5;
+  this.color = 'blue';
+}
+ +

Notez que nous n'avons spécifié que this au sein de call() — Aucun autre paramètre n'est requis puisque nous n'héritons ici d'aucune propriété provenant de la classe parente qui soit spécifiée via paramètres.  

+ +

Définir le prototype de Professeur() et son constructeur référent.

+ +

Pour le moment tout va bien, mais nous avons un petit problème. Nous avons défini un  nouveau constructeur et ce dernier possède une propriété prototype, qui par défaut ne contient qu'une référence à la fonction constructrice elle même. En revanche il ne contient pas les méthodes de la propriété prototype du constructeur Personne(). Pour le constater, vous pouvez par exemple entrer Professeur.prototype.constructor dans la console JavaScript pour voir ce qu'il en est. Le nouveau constructeur n'a en aucun cas hérité de ces méthodes. Pour le constater, comparez les sorties de Personne.prototype.saluer et de Professeur.prototype.saluer

+ +

Notre classe Professeur() doit hériter des méthodes définies dans le prototype de Personne(). Aussi comment procéder pour obtenir ce résultat ?

+ +

Ajoutez la ligne suivante à la suite du bloc de code que nous venons d'ajouter :

+ +
Professeur.prototype = Object.create(Personne.prototype);
+ +
    +
  1. Ici, notre ami create() vient nous aider à nouveau. Dans ce cas, on l'utilise afin de créer un nouvel objet que nous assignons à Professeur.prototype. Le nouvel objet possède Personne.prototype désormais comme son prototype et héritera ainsi, si et quand le besoin se fera sentir, de toutes les méthodes disponible sur Personne.prototype
  2. +
  3. Nous avons également besoin de faire encore une chose avant de continuer. Après avoir ajouté la ligne précédente, le constructeur du prototype de Professeur() est désormais équivalent à celui de Personne(), parce que nous avons défini Professeur.prototype pour référencer un objet qui hérite ses propriétés de  Personne.prototype ! Essayez, après avoir sauvegardé votre code et rechargé la page, d'entrer Professeur.prototype.constructor dans la console pour vérifier.
  4. +
  5. Cela peut devenir problématique, autant le corriger dès maintenant. C'est possible via l'ajout de la ligne de code suivante à la fin : +
    Professeur.prototype.constructor = Professeur;
    +
  6. +
  7. +

    A présent, si vous sauvegardez et rafraichissez après avoir écrit Professeur.prototype.constructor, cela devrait retourner Professeur(), et en plus nous héritons maintenant de Personne() !

    +
  8. +
+ +

Donner au prototype de Professeur() une nouvelle fonction saluer()

+ +

Pour terminer notre code, nous devons définir une nouvelle fonction saluer() sur le constructeur de Professeur().

+ +

La façon la plus facile d'accomplir cela est de la définir sur le prototype de Professeur() — ajoutez ceci à la suite de votre code :

+ +
Professeur.prototype.saluer = function() {
+  var prefix;
+
+  if (this.genre === 'mâle' || this.genre === 'Mâle' || this.genre === 'm' || this.genre === 'M') {
+    prefix = 'M.';
+  } else if (this.genre === 'femelle' || this.genre === 'Femelle' || this.genre === 'f' || this.genre === 'F') {
+    prefix = 'Mme';
+  } else {
+    prefix = '';
+  }
+
+  alert('Bonjour. Mon nom est ' + prefix + ' ' + this.nom_complet.nom + ', et j\'enseigne ' + this.matiere + '.');
+};
+ +

Ceci affiche la salutation du professeur, qui utilise le titre de civilité approprié à son genre, au moyen d'une instruction conditionnelle.

+ +

 

+ +

Exécuter l'exemple

+ +

Une fois tout le code saisi, essayez de créer une instance d'objet Professeur() en ajoutant à la fin de votre JavaScript (ou à l'endroit de votre choix) :

+ +
var professeur1 = new Professeur('Cédric', 'Villani', 44, 'm', ['football', 'cuisine'], 'les mathématiques');
+ +

Sauvegardez et actualisez, et essayez d'accéder aux propriétés et méthodes de votre nouvel objet professeur1, par exemple :

+ +
professeur1.nom_complet.nom;
+professeur1.interets[0];
+professeur1.bio();
+professeur1.matiere;
+professeur1.saluer();Ffa
+ +

Tout cela devrait parfaitement fonctionner. Les instructions des lignes 1,2,3  et 6 accèdent à des membres hérités de la classe générique Personne() via son constructeur, tandis que la ligne 4 accède de façon plus spécifique à un membre qui n'est disponible que via le constructeur de la classe spécialisée Professeur().

+ +

Note: Si vous rencontrez un problème afin de faire fonctionner ce code comparez le à notre version finalisée (Ou regarder tourner notre demo en ligne).

+ +

La méthode que nous avons détaillée ici n'est pas la seule permettant de mettre en place l'héritage de classes en JavaScript, mais elle fonctionne parfaitement et elle vous permet d'avoir une bonne idée de comment implémenter l'héritage en JavaScript.

+ +

Vous pourriez également être intéressé par certaines des nouvelles fonctionnalités de {{glossary("ECMAScript")}} qui nous permettent de mettre en place l'héritage d'une façon beaucoup plus élégante en JavaScript (Voir Classes). Nous ne les avons pas développées ici parce qu'elles ne sont actuellement pas supportées par tous les navigateurs. Toutes les autres constructions dont nous avons discuté dans cette série d'articles sont supportées par IE9 et les versions moins récentes et il existe des méthodes qui prennent plus en  charge les navigateurs moins récents.

+ +

Un moyen habituel est d'utiliser les librairies JavaScript — La plupart des options populaires ont une sélection de fonctionnalités disponibles pour réaliser l'héritage plus facilement et plus rapidement.

+ +

CoffeeScript par exemple fournit les fonctionnalités class, extends, etc.

+ +

Un exercice plus complexe.

+ +

Dans notre section sur la programmation orientée objet nous avons également inclus  une classe Etudiant comme un concept qui hérite de toutes les fonctionnalités de la classe Personne, et qui a également une méthode saluer() differente de celle de Personne qui est beaucoup moins formelle que la méthode saluer() de Professeur(). Jetez un oeil à ce à quoi ressemble la méthode saluer() de la classe Etudiant dans cette section et essayez d'implémenter votre propre constructeur Etudiant() qui hérite de toutes les fonctionnalités de Personne() et la fonction saluer() différente.

+ +

Note: Si vous rencontrez un problème afin de faire fonctionner ce code comparez le à notre version finalisée (Ou regarder tourner notre demo en ligne).

+ +

Résumé sur les membres de l'Objet

+ +

Pour résumer, vous avez de façon basique trois types de propriétés/méthodes à prendre en compte :

+ +
    +
  1. Celles définies au sein d'un constructeur et passées en paramètres aux instances de l'objet. Celles là ne sont pas difficiles à repérer — Dans votre propre code personnalisé, elles sont les membres définis en utilisant les lignes comme this.x = x ; Dans les codes préconstruits propres aux navigateurs, ils sont les membres seulement accessibles aux instances d'objet (usuellement créés en appelant un constructeur via l'utilisation du mot clé new, exemple : var myInstance = new myConstructor()).
  2. +
  3. Celles définies directement sur les constructeurs eux mêmes et accessibles uniquement sur les constructeurs. Celles là sont communément présentes uniquement dans les objets préconstruits des navigateurs et sont reconnus par le fait d'être directement chaînées sur un constructeur et non sur une instance. Par exemple, Object.keys().
  4. +
  5. Celles définies sur un prototype de constructeur qui sont héritées par toutes les instances des classes d'objet. Celles là incluent n'importe quel membre défini sur un prototype de constructeur, exemple : myConstructor.prototype.x().
  6. +
+ +

Si vous êtes encore dans la confusion par rapport aux différents types ne vous inquiétez pas c'est normal — vous êtes encore entrain d'apprendre et la familiarité apparaîtra avec la pratique.

+ +

Quand devez-vous utiliser  l'héritage en JavaScript?

+ +

Particulièrement après ce dernier article, vous pourriez penser "woa c'est compliqué". Bien, vous avez vu juste, prototypes et héritages représentent une partie des aspects les plus complexes de JavaScript, mais une bonne partie de la puissance et de la flexibilité de JavaScript vient de sa structure Objet et de l'héritage et il est vraiment très important de comprendre comment cela fonctionne. 

+ +

D'une certaine manière, vous utilisez l'héritage à plein temps — Que vous utilisiez différentes fonctionnalités d'une WebAPI , ou une méthode/propriété définie par défaut  sur un objet prédéfini du navigateur que vous invoquez sur vos chaînes de caractères, tableaux etc., vous utilisez de façon implicite l'héritage. 

+ +

En termes d'utilisation de l'héritage dans votre propre code, vous ne l'utiliserez probablement pas si souvent et spécialement pour débuter avec, et dans les petits projets — C'est une perte de temps d'utiliser les objets et l'héritage par amour pour cette pratique quand vous n'en avez pas besoin. Mais à mesure que les bases de votre code s'élargissent vous trouverez cette façon de faire probablement très utile. Si vous trouvez utile et plus pratique de commencer en créant un certain nombre d'objets spécialisés partageant les mêmes fonctionnalités, alors créer un objet générique qui contiendra toutes les fonctionnalités communes dont les objets spécialisés hériteront vous apparaîtra être une pratique peut être plus confortable et efficace par la suite. 

+ +

Note: A cause de la manière dont JavaScript fonctionne, avec la chaîne de prototype, etc., le partage de fonctionnalités entre objet est souvent appelée délégation — Les objets spécialisés délèguent cette fonctionnalité à l'objet de type générique. C'est certainement beaucoup plus précis que de l'appeler héritage, puisque la fonctionnalité "héritée" n'est pas copiée dans les objets qui "héritent". Au contraire, elle demeure dans l'objet générique.

+ +

Lorsque vous utilisez l'héritage, il est conseillé de ne pas avoir trop de degrés d'héritage et de toujours garder minutieusement trace de l'endroit où vous définissez vos propriétés et méthodes. Il est possible de commencer à écrire un code qui modifie temporairement les prototypes des objets prédéfinis du navigateur mais vous ne devriez pas le faire à moins que n'ayiez une très bonne raison. Trop de degrés d'héritages peut conduire à une confusion sans fin et une peine sans fin quand vous essayez de déboguer un tel code. 

+ +

En définitive, les objets sont juste une autre forme de réutilisation de code comme les fonctions et les boucles avec leurs propres rôles et avantages. Si vous trouvez utile de créer un lot de variables et fonctions relatives et que vous voulez les retracer ensemble et les empaqueter de façon ordonnée, un objet est une bonne idée. Les objets sont également très utiles quand vous souhaitez passer une collection de données d'un endroit à un autre. Toutes ces choses peuvent être accomplies sans l'utilisation d'un constructeur ou de l'héritage. Si vous n'avez besoin que d'une seule instance, l'utilisation d'un simple objet littéral serait certainement un choix beaucoup plus judicieux et vous n'avez certainement pas besoin de l'héritage.

+ +

Résumé

+ +

Cet article a couvert le reste du coeur de la théorie du JSOO et des syntaxes que nous pensons que vous devriez connaître maintenant. A cet stade vous devriez comprendre l'objet JavaScript et les bases de la POO, les prototypes et l'héritage par prototype, comment créer les classes (constructeurs) et les instances d'objet, ajouter des fonctionnalités aux classes, et créer des sous classes qui héritent d'autres classes. 

+ +

Dans le prochain article, nous jetterons un regard sur comment travailler avec le (JSON),  un format commun d'échange de données écrit en utilisant les objets JavaScript.

+ +

Voir aussi

+ + + +

{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}

+ +

 

+ +

Dans ce module

+ + + +

 

+
+ +

 

diff --git "a/files/fr/learn/javascript/objects/js_orient\303\251-objet/index.html" "b/files/fr/learn/javascript/objects/js_orient\303\251-objet/index.html" deleted file mode 100644 index c16e9a230e..0000000000 --- "a/files/fr/learn/javascript/objects/js_orient\303\251-objet/index.html" +++ /dev/null @@ -1,278 +0,0 @@ ---- -title: Le JavaScript orienté objet pour débutants -slug: Learn/JavaScript/Objects/JS_orienté-objet -tags: - - Apprendre - - Débutant - - Guide - - JavaScript - - OOJS - - OOP - - POO -translation_of: Learn/JavaScript/Objects/Object-oriented_JS ---- -
{{LearnSidebar}}
- -
{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}
- -

Après avoir parcouru les fondamentaux, nous allons aborder en détail le JavaScript orienté objet (JSOO). Cet article présente une approche simple de la programmation orientée objet (POO) et détaille comment JavaScript émule des classes objet au travers des méthodes constructeur et comment instancier ces objets.

- - - - - - - - - - - - -
Pré-requis :Connaissances de base en informatique et compréhension des notions HTML et CSS, notions de JavaScript (voir Premiers pas et Blocs de construction)
Objectif :Comprendre les concepts de base derrière la programmation orientée objet et comment ils s'appliquent à JavaScript ( « tout est objet » ) et comment créer des constructeurs et instancier des objets.
- -

La programmation orientée objet de loin

- -

Pour commencer, donnons une vue simplifiée et de haut niveau de ce qu'est la programmation orientée objet (POO). On parle d'une vision simplifiée étant donnée que la POO peut devenir très vite complexe et qu'être exhaustif rendrait probablement la découverte plus confuse et difficile qu'autre chose. L'idée de base de la POO consiste à utiliser des objets pour modéliser les objets du monde réel que l'on souhaite représenter dans nos programmes et/ou de fournir un moyen simple d'accéder à une fonctionnalité qu'il serait difficile d'utiliser autrement.

- -

Les objets peuvent contenir des données et du code représentant de l'information au sujet de la chose que l'on essaie de modéliser ainsi que des fonctionnalités ou un comportement que l'on souhaite lui appliquer. Les données (et bien souvent les fonctions) associées à un objet peuvent être stockées (le terme officiel est encapsulé) à l'intérieur d'un paquet objet. Il est possible de donner un nom spécifique à un paquet objet afin  d'y faire référence, on parle alors d'espace de noms ou namespace, il sera ainsi plus facile de le manipuler et d'y accéder. Les objets peuvent aussi servir pour stocker des données et les transférer facilement sur un réseau.

- -

Définissons un modèle objet

- -

Nous allons voir un programme simple qui affiche des informations à propos des élèves et des professeurs d'une école. Nous allons aborder la théorie de la programmation orientée objet de manière générale sans l'appliquer à un langage particulier.

- -

Pour débuter, nous pouvons réutiliser l'objet Personne que nous avons créé dans notre premier article, il définit un ensemble de données et actions d'une personne. Il existe tout un tas de choses que nous pourrions savoir au sujet d'une personne (son adresse, sa taille, sa pointure, son ADN, son numéro de passeport, ses traits particuliers significatifs… ). En l'occurrence, nous souhaitons uniquement afficher son nom, son âge, ses passions, écrire une petite introduction à son sujet en utilisant ces données et lui apprendre à se présenter. On parle alors d'abstraction : créer un modèle simplifié de quelque chose de complexe mais qui ne contient que les aspects qui nous intéressent. Il sera alors plus simple de manipuler ce modèle objet simplifié dans le cadre de notre programme.

- -

Classe Personne avec attributs élémentaires

- -

Dans plusieurs langages de POO, la définition d'un objet est appelé une classe (comme on le verra ci-après, JavaScript se base sur un mécanisme et une terminologie différente). En réalité ce n'est pas vraiment un objet mais plutôt un modèle qui définit les propriétés que notre objet doit avoir.

- -

Créons des objets

- -

À partir de notre classe, nous pouvons créer des objets, on parle alors d'instancier des objets, une classe objet a alors une instance. Il s'agit d'objets qui contiennent les données et attributs définis dans une classe. À partir de notre classe Personne, nous pouvons modéliser des personnes réelles :

- -

Instantiation on a Personn Class for JS examples (fr)

- -

Lorsque l'instance d'un objet est créée, on appelle la fonction constructeur de la classe pour la créer. On parle d'instanciation d'un objet — l'objet ainsi créé est instancié à partir de la classe.

- -

Classes filles

- -

Pour notre exemple, nous n'allons pas nous contenter de personnes génériques — nous pourrions utiliser des professeurs, des étudiants, qui sont des types un peu plus spécifiques de personnes. En POO, il est possible de créer de nouvelles classes à partir d'autres classes — ces classes filles nouvellement créées peuvent hériter des propriétés et des attributs de leur classe mère. Il est donc possible d'avoir des attributs partagés à l'ensemble des classes plutôt que de les dupliquer. Si besoin, il est possible d'ajouter des fonctions et attributs spécifiques sur chaque classe fille.

- -

Inheritance principle with French text for JS example

- -

Cela s'avère très utile puisque les étudiants et les professeurs se ressemblent sur de nombreux aspects : ils ont un nom, un genre, un âge, il est donc utile de ne définir ces attributs qu'une seule fois. Il est aussi possible de redéfinir le même attribut dans différentes classes étant donné que l'attribut appartiendra à chaque fois à un nom d'espace différent. On pourra ainsi avoir différentes formes de salutations : « Hey, je m'appelle [prénom] » pour les étudiants ( « Hey je m'appelle Sam » ) tandis que les professeurs pourront dire quelque chose d'un peu plus formel comme « Bonjour, mon nom est [Titre][Nom] et j'enseigne [matière] » par exemple « Bonjour mon nom est M. Griffiths et j'enseigne la chimie ».

- -
-

Note : On parle de polymorphisme, lorsque des objets réutilisent la même propriété,  mais c'est juste pour info, vous embêtez pas.

-
- -

Une fois la classe fille créée il est alors possible de l'instancier et de créer des objets. Par exemple :

- -

Professor instantiation example for JS fr

- -

Dans la suite de l'article, nous nous intéresserons à la mise en œuvre de la programmation orientée objet (POO) au sein de JavaScript.

- -

Constructeurs et instances d'objet

- -

Certains disent que le JavaScript n'est pas vraiment un langage de programmation orienté objet — Il n'existe pas, en JavaScript d'élément class pour créer des classes alors que c'est le cas dans plusieurs langages orientés objet. JavaScript quant à lui, utilise des fonctions spéciales appelées constructeurs pour définir les objets et leurs propriétés. Ces constructeurs s'avèrent utiles, puisque bien souvent, nous ne savons pas combien d'objets nous allons définir, les constructeurs nous permettent de créer autant d'objets que nécessaire et d'y associer des données et des fonctions au fur et à mesure.

- -

Lorsqu'un objet est instancié à partir d'une fonction constructeur, les fonctions de la classe ne sont pas copiées directement dans l'objet comme dans la plupart des langages orientés objet (OO). En JavaScript, les fonctions sont liées grâce à une chaîne de référence appelée chaîne prototype (voir Prototypes Objet). Il ne s'agit donc pas d'une véritable instanciation au sens strict puisque JavaScript utilise un mécanisme différent pour partager des fonctionnalités entre les objets.

- -
-

Note : Ne pas être un "langage classique de POO" n'est pas nécessairement un défaut. Comme nous le mentionnions au début de l'article, la POO peut très vite devenir compliquée et JavaScript, grâce à ses différences parvient à utiliser certains concepts avancés tout en restant abordable.

-
- -

Voyons comment créer des classes via les constructeurs et les utiliser pour instancier des objets en JavaScript. Nous allons commencer par faire une copie locale du fichier oojs.html que nous avons vu dans notre premier article sur les objets.

- -

Un exemple simple

- -
    -
  1. Tout d'abord ; voyons comment définir une personne au travers d'une fonction classique. Vous pouvez ajouter l'exemple ci-dessous dans votre code existant : -
    function creerNouvellePersonne(nom) {
    -  var obj = {};
    -  obj.nom = nom;
    -  obj.salutation = function() {
    -    alert('Salut ! Je m\'appelle ' + this.nom + '.');
    -  };
    -  return obj;
    -}
    -
  2. -
  3. Vous pouvez désormais créer une personne en appelant cette fonction, essayez en copiant les lignes suivantes dans la console JavaScript de votre navigateur : -
    var salva = creerNouvellePersonne('Salva');
    -salva.nom;
    -salva.salutation();
    - Ça fonctionne bien, mais on peut améliorer notre exemple. Si l'on sait que l'on va créer un objet, pourquoi créer un objet vide pour l'utiliser ensuite ? Heureusement, JavaScript est là et possède des fonctions adaptées comme les constructeurs. À l'abordage !
  4. -
  5. Remplacez la fonction précédente par celle-ci : -
    function Personne(nom) {
    -  this.nom = nom;
    -  this.salutation = function() {
    -    alert('Bonjour ! Je m\'appelle ' + this.nom + '.');
    -  };
    -}
    -
  6. -
- -

Le constructeur est l'équivalent JavaScript d'une classe. Il possède l'ensemble des fonctionnalités d'une fonction, cependant il ne renvoie rien et ne crée pas d'objet explicitement. Il se contente de définir les propriétés et les méthodes associées. Il y a aussi l'utilisation du mot-clé this, ce mot-clé sert au sein d'une instance qui sera créée à y faire référence, ainsi l'attribut nom sera, pour l'instance, égal au nom passé en argument de la fonction constructrice, la méthode salutation() retournera elle aussi le nom passé en argument de la fonction constructrice.

- -
-

Note : Les fonctions de type constructeur commencent généralement par une majuscule. Cette convention d'écriture permet de repérer les constructeurs plus facilement dans le code.

-
- -

Comment pouvons-nous utiliser un constructeur ?

- -
    -
  1. Ajoutez les lignes suivantes au code déjà existant : -
    var personne1 = new Personne('Bob');
    -var personne2 = new Personne('Sarah');
    -
  2. -
  3. Enregistrez votre code et relancez le dans votre navigateur puis essayez d'entrer les lignes suivantes dans la console : -
    personne1.nom
    -personne1.salutation()
    -personne2.nom
    -personne2.salutation()
    -
  4. -
- -

Pas mal ! Vous voyez désormais que nous avons deux nouveaux objets sur cette page, chaque objet étant stocké dans un espace de nom différent, pour y accéder il faut utiliser personne1 et personne2 pour préfixer les fonctions et attributs. Ce rangement permet de ne pas tout casser et de ne pas rentrer en collision avec d'autres fonctionnalités. Cependant les objets disposent du même attribut nom et de la même méthode salutation(). Heureusement, les attributs et les méthodes utilisent this ce qui leur permet d'utiliser les valeurs propres à chaque instance et de ne pas les mélanger.

- -

Revoyons l'appel au constructeur :

- -
var personne1 = new Personne('Bob');
-var personne2 = new Personne('Sarah');
- -

Dans chaque cas, le mot clé new est utilisé pour dire au navigateur que nous souhaitons définir une nouvelle instance, il est suivi du nom de la fonction que l'on utilise et de ses paramètres fournis entre parenthèses, le résultat est stocké dans une variable. Chaque instance est créée à partir de cette définition :

- -
function Personne(nom) {
-  this.nom = nom;
-  this.salutation = function() {
-    alert('Bonjour ! Je m\'appelle ' + this.nom + '.');
-  };
-}
- -

Une fois les objets créés, les variables personne1 et personne2 contiennent les objets suivants :

- -
{
-  nom: 'Bob',
-  salutation: function() {
-    alert('Bonjour ! Je m\'appelle ' + this.nom + '.');
-  }
-}
-
-{
-  nom: 'Sarah',
-  salutation: function() {
-    alert('Bonjour ! Je m\'appelle ' + this.nom + '.');
-  }
-}
- -

On peut remarquer qu'à chaque appel de notre fonction constructrice nous définissons salutation() à chaque fois. Cela peut être évité via la définition de la fonction au sein du prototype, ce que nous verrons plus tard.

- -

Créons une version finalisée de notre constructeur

- -

L'exemple que nous avons utilisé jusqu'à présent était destiné à aborder les notions de base des constructeurs. Créons un constructeur digne de ce nom pour notre fonction constructrice Personne().

- -
    -
  1. Vous pouvez retirer le code que vous aviez ajouté précédemment pour le remplacer par le constructeur suivant, c'est la même fonction, ça reste un constructeur, nous avons juste ajouté quelques détails : -
    function Personne(prenom, nom, age, genre, interets) {
    -  this.nom = {
    -    prenom,
    -    nom
    -  };
    -  this.age = age;
    -  this.genre = genre;
    -  this.interets = interets;
    -  this.bio = function() {
    -    alert(this.nom.prenom + ' ' + this.nom.nom + ' a ' + this.age + ' ans. Il aime ' + this.interets[0] + ' et ' + this.interets[1] + '.');
    -  };
    -  this.salutation = function() {
    -    alert('Bonjour ! Je m\'appelle ' + this.nom.prenom + '.');
    -  };
    -};
    -
  2. -
  3. Vous pouvez ajouter la ligne ci-dessous pour créer une instance à partir du constructeur : -
    var personne1 = new Personne('Bob', 'Smith', 32, 'homme', ['musique', 'ski']);
    -
  4. -
- -

Vous pouvez accéder aux fonctions des objets instanciés de la même manière qu'avant :

- -
personne1['age']
-personne1.interets[1]
-personne1.bio()
-// etc.
- -
-

Note : Si vous avez du mal à faire fonctionner cet exemple, vous pouvez comparez votre travail avec notre version (voir oojs-class-finished.html (vous pouvez aussi jeter un œil à la démo)

-
- -

Exercices

- -

Vous pouvez démarrer en instanciant de nouveaux objets puis en essayant de modifier et d'accéder à leurs attributs respectifs.

- -

D'autre part, il y a quelques améliorations possibles pour notre méthode bio(). En effet elle affiche systématiquement le pronom 'il', même si votre personne est une femme ou bien préfère se définir par un autre genre. De plus, la biographie n'inclut que deux passions, même s'il y en a plus dans la liste. Essayez d'améliorer cette méthode. Vous pourrez mettre votre code à l'intérieur du constructeur (vous aurez probablement besoin de quelques structures conditionnelles et d'une boucle). Réflechissez à la syntaxe des phrases qui devra s'adapter en fonction du genre et du nombre de passions listées.

- -
-

Note: Si vous êtes bloqués, nous avons mis une réponse possible sur notre dépôt GitHub (la démo) —tentez d'abord l'aventure avant d'aller regarder la réponse !

-
- -

D'autres manières d'instancier des objets

- -

Jusque là nous n'avons abordé que deux manières différentes pour créer une instance d'objet, la déclarer de manière explicite et en utilisant le constructeur.

- -

Elles sont toutes les deux valables, mais il en existe d'autres. Afin que vous les reconnaissiez lorsque vous vous baladez sur le Web, nous en avons listées quelques unes.

- -

Le constructeur Object()

- -

Vous pouvez en premier lieu utiliser le constructeur Object() pour créer un nouvel objet. Oui, même les objets génériques ont leur propre constructeur, qui génère un objet vide.

- -
    -
  1. Essayez la commande suivante dans la console JavaScript de votre navigateur : -
    var personne1 = new Object();
    -
  2. -
  3. On stocke ainsi un objet vide dans la variable personne1. Vous pouvez ensuite ajouter des attributs et des méthodes à cet objet en utilisant la notation point ou parenthèses comme vous le souhaitez. -
    personne1.nom = 'Chris';
    -personne1['age'] = 38;
    -personne1.salutation = function() {
    -  alert('Bonjour ! Je m\'appelle ' + this.nom + '.');
    -};
    -
  4. -
  5. Vous pouvez aussi passer un objet en paramètre du constructeur Object(), afin de prédéfinir certains attributs et méthodes. -
    var personne1 = new Object({
    -  nom: 'Chris',
    -  age: 38,
    -  salutation: function() {
    -    alert('Bonjour ! Je m\'appelle ' + this.nom + '.');
    -  }
    -});
    -
  6. -
- -

Via la méthode create()

- -

Les constructeurs permettent de structurer le code : vous pouvez avoir l'ensemble de vos constructeurs au même endroit et ensuite créer les instances suivant vos besoins, en identifiant clairement leur origine.  

- -

Cependant, on peut vouloir créér des instances d'un objet, sans forcément définir un constructeur au préalable. (Particulierement si l'on a peu d'instances de cet object). JavaScript intègre directement une méthode appelée create() qui rend cela possible. Elle permet d'instancier un objet à partir d'un objet existant  .

- -
    -
  1. Essayez d'ajouter la ligne suivante dans votre console JavaScript : -
    var personne2 = Object.create(personne1);
    -
  2. -
  3. Maintenant : -
    personne2.nom
    -personne2.salutation()
    -
  4. -
- -

personne2 a été créée à partir de personne1 — et elle possède les mêmes propriétés. 

- -

L'inconvénient de create() est qu'elle n'est pas supportée par IE8. Ainsi, utiliser les constructeurs peut s'avérer plus judicieux lorsqu'il s'agit de supporter les anciens navigateurs Web.

- -

Nous verrons les détails et les effets de create() plus tard.

- -

Résumé

- -

Cet article vous a donné un aperçu simplifié de la programmation orientée objet. Tout n'y a pas été détaillé mais ça vous permet de vous faire une idée. Nous avons vu comment JavaScript s'appuyait sur un certain nombre de principes orienté objet tout en ayant un certain nombre de particularités. Nous avons aussi vu comment implémenter des classes en JavaScript via la fonction constructeur ainsi que les différentes manières de générer des instances d'objets.

- -

Dans le prochain article, nous explorerons le monde des objets prototypes en JavaScript.

- -

{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}

diff --git a/files/fr/learn/javascript/objects/la_construction_d_objet_en_pratique/index.html b/files/fr/learn/javascript/objects/la_construction_d_objet_en_pratique/index.html deleted file mode 100644 index a2ab4270eb..0000000000 --- a/files/fr/learn/javascript/objects/la_construction_d_objet_en_pratique/index.html +++ /dev/null @@ -1,316 +0,0 @@ ---- -title: La construction d'objet en pratique -slug: Learn/JavaScript/Objects/la_construction_d_objet_en_pratique -tags: - - Apprendre - - Article - - Canvas - - Débutant - - JavaScript - - Manuel - - Objets - - Tutoriel -translation_of: Learn/JavaScript/Objects/Object_building_practice ---- -
{{LearnSidebar}}
- -
{{PreviousMenuNext("Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects/Adding_bouncing_balls_features", "Learn/JavaScript/Objects")}}
- -

Dans l'article précédent, nous avons passé en revue l'essentiel de la théorie de l'objet Javascript et sa syntaxe détaillée, vous donnant ainsi des bases solides sur lesquelles commencer. Dans le présent article nous plongeons dans un exercice pratique afin d'accroître votre savoir-faire dans la construction d'objets entièrement personnalisés donnant un résultat plutôt amusant et très coloré.

- - - - - - - - - - - - -
Pré-requis : -

Connaissance basique de l'informatique, une compréhension basique du HTML et du CSS, une familiarité avec  les bases du JavaScript (voir Premiers pas et Les blocs de construction) et les bases de la programmation objet en JavaScript (voir Introduction aux objets). 

-
Objectif : -

Acquérir plus de pratique dans l'utilisation des objets et des techniques orientées objet dans un contexte "monde réel".

-
- -

Faisons bondir quelques balles

- -

Dans cet article, nous écrirons une démo classique de "balles bondissantes", pour vous montrer à quel point les objets peuvent être utiles en JavaScript. Nos petites balles bondiront partout sur notre écran et changeront de couleurs lorsqu'elles se toucheront. L'exemple finalisé ressemblera un peu à ceci : 

- -

- -
    -
- -

Cet exemple utilise l'API Canvas  pour dessiner les balles sur l'écran, et l'API requestAnimationFrame  pour animer l'ensemble de l'affichage — Nul besoin d'avoir une connaissance préalable de ces APIs, nous expérons qu'une fois cet article terminé, vous aurez envie d'en faire une exploration approfondie. Tout le long du parcours nous utiliserons certains objets formidables et vous montrerons nombre de techniques sympathiques comme des balles bondissantes sur les murs et la vérification de balles qui s'entrechoquent (encore connue sous l'appelation détection de collision).

- -

Pour commencer, faites des copies locales de nos fichiers index.html, style.css, et main.js. Ces fichiers contiennent respectivement :

- -
    -
  1. Un document  HTML très simple contenant un élément {{HTMLElement("h1")}} , un élément {{HTMLElement("canvas")}} pour dessiner nos balles dessus et des élements  pour appliquer notre CSS et notre JavaScript à notre HTML ;
  2. -
  3. Quelques styles très simples qui servent principalement à mettre en forme et placer le <h1>, et se débarasser de toutes barres de défilement ou de marges autour du pourtour de notre page (afin que cela paraisse plus sympathique et élégant) ;
  4. -
  5. Un peu de JavaScript qui sert à paramétrer l'élément  <canvas> et fournir les fonctions globalles que nous utiliserons.
  6. -
- -

La première partie du script ressemble à ceci :

- -
const canvas = document.querySelector('canvas');
-
-const ctx = canvas.getContext('2d');
-
-const width = canvas.width = window.innerWidth;
-const height = canvas.height = window.innerHeight;
- -

Ce script prend une référence à l'élément  <canvas> et ensuite invoque la méthode  getContext() sur lui, nous donnant ainsi un contexte sur lequel nous pouvons commencer à dessiner. La variable résultante  (ctx)  est l'objet qui représente directement la surface du Canvas où nous pouvons dessiner et qui nous permet de dessiner des formes 2D sur ce dernier. 

- -

Après, nous configurons  les variables width (largeur) et height(hauteur),  et la largeur et la hauteur de l'élément canvas (représentés par les propriétés  canvas.width et canvas.height ) afin qu'elles soient identiques à la fenêtre du navigateur (la surface sur laquelle apparaît la page web— Ceci peut être tiré des propriétés {{domxref("Window.innerWidth")}} et {{domxref("Window.innerHeight")}}).

- -

Vous verrez qu'ici nous enchaînons les assignations des valeurs des différentes variables ensemble à des fins de rapidité. Ceci est parfaitement autorisé.

- -

Le dernier morceau du script ressemble à ceci :

- -
function random(min, max) {
-  var num = Math.floor(Math.random() * (max - min + 1)) + min;
-  return num;
-}
- -

Cette fonction prend deux nombres comme arguments, et renvoie un nombre compris entre les deux. 

- -

Modéliser une balle dans notre programme

- -

Notre programme met en œuvre beaucoup de balles bondissant partout sur l'écran. Comme nos balles se comporteront toutes de la même façon, cela semble tout à fait sensé de les représenter avec un objet. Commençons donc en ajoutant le constructeur suivant à la fin de notre code.

- -
function Ball(x, y, velX, velY, color, size) {
-  this.x = x;
-  this.y = y;
-  this.velX = velX;
-  this.velY = velY;
-  this.color = color;
-  this.size = size;
-}
- -

Ici, nous incluons des paramètres qui définissent  des propriétés dont chaque balle aura besoin pour fonctionner dans notre programme :

- - - -

Ceci règle le problème des propriétés mais qu'en est il des méthodes ? Nous voulons maintenant amener nos balles à faire quelque chose dans notre programme.

- -

Dessiner la balle

- -

En premier lieu ajoutez la méthode draw() au prototype de Ball() :

- -
Ball.prototype.draw = function() {
-  ctx.beginPath();
-  ctx.fillStyle = this.color;
-  ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
-  ctx.fill();
-}
- -

En utilisant cette fonction, nous pouvons dire à notre balle de se dessiner sur l'écran en appelant une série de membres du contexte 2D du canvas que nous avons défini plus tôt  (ctx). Le contexte est comme le papier et maintenant nous allons demander à notre stylo d'y dessiner quelque chose :

- - - -

Vous pouvez déjà commencer à tester votre objet.

- -
    -
  1. Sauvegardez le code et chargez le fichier html dans un navigateur.
  2. -
  3. Ouvrez la console JavaScript du navigateur et actualisez la page afin que la taille du canvas change et prenne la petite taille restante de la fenêtre lorsque la console est ouverte.
  4. -
  5. Tapez dans la console ce qui suit afin de créer une nouvelle instance de balle : -
    let testBall = new Ball(50, 100, 4, 4, 'blue', 10);
    -
  6. -
  7. Essayez d'appeler ses membres : -
    testBall.x
    -testBall.size
    -testBall.color
    -testBall.draw()
    -
  8. -
  9. Lorsque vous entrerez la dernière ligne, vous devriez voir la balle se dessiner quelque part sur votre canvas.
  10. -
- -

Mettre à jour les données de la balle

- -

Nous pouvons dessiner la balle dans n'importe quelle position, mais actuellement pour commencer à la bouger nous aurons besoin d'une sorte de fonction de mise à jour. Insérez donc le code suivant à la fin de votre fichier JavaScript pour ajouter une méthode update() au prototype de Ball():

- -
Ball.prototype.update = function() {
-  if ((this.x + this.size) >= width) {
-    this.velX = -(this.velX);
-  }
-
-  if ((this.x - this.size) <= 0) {
-    this.velX = -(this.velX);
-  }
-
-  if ((this.y + this.size) >= height) {
-    this.velY = -(this.velY);
-  }
-
-  if ((this.y - this.size) <= 0) {
-    this.velY = -(this.velY);
-  }
-
-  this.x += this.velX;
-  this.y += this.velY;
-}
- -

Les quatre premières parties de la fonction vérifient si la balle a atteint le rebord  du canvas. Si c'est le cas, nous inversons la polarité de la vitesse appropriée pour faire bouger la balle dans le sens opposé. Donc par exemple, si la balle se déplaçait vers le haut (positif velY) alors la vitesse verticale est changée afin qu'elle commence à bouger plutôt vers le bas (negatif velY).

- -

Dans les quatre cas nous :

- - - -

Dans chaque cas, nous incluons la taille size de la balle dans les calculs parce que les coordonnées  x/y  sont situées au centre de la balle mais nous voulons que le pourtour de la balle rebondisse sur le rebord  — nous ne voulons pas que la balle sorte à moité hors de l'écran avant de commencer à rebondir vers l'arrière.

- -

Les deux dernières lignes ajoutent la valeur velX à la coordonnée x et la valeur velY à la coordonnée y — la balle est en effet mise en mouvement chaque fois que cette méthode est invoquée.

- -

Cela suffira pour l'instant, passons à l'animation !

- -

Animer la balle

- -

Maintenant, rendons cela amusant. Nous allons commencer à ajouter des balles au canvas et à les animer.

- -
    -
  1. Tout d'abord, nous avons besoin d'un endroit où stocker toutes nos balles. Le tableau suivant fera ce travail — ajoutez-le au bas de votre code maintenant : - -
    let balls = [];
    -
    - -
    while (balls.length < 25) {
    -  let size = random(10,20);
    -  let ball = new Ball(
    -    // ball position always drawn at least one ball width
    -    // away from the edge of the canvas, to avoid drawing errors
    -    random(0 + size,width - size),
    -    random(0 + size,height - size),
    -    random(-7,7),
    -    random(-7,7),
    -    'rgb(' + random(0,255) + ',' + random(0,255) + ',' + random(0,255) +')',
    -    size
    -  );
    -
    -  balls.push(ball);
    -}
    - Tous les programmes qui animent les choses impliquent généralement une boucle d'animation, qui sert à mettre à jour les informations dans le programme et à restituer ensuite la vue résultante sur chaque image de l'animation. C'est la base de la plupart des jeux et autres programmes similaires.
  2. -
  3. Ajoutez ce qui suit au bas de votre code maintenant : -
    function loop() {
    -  ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
    -  ctx.fillRect(0, 0, width, height);
    -
    -  for (let i = 0; i < balls.length; i++) {
    -    balls[i].draw();
    -    balls[i].update();
    -  }
    -
    -  requestAnimationFrame(loop);
    -}
    - -

    Notre fonction loop() fonctionne comme suit :

    - -
      -
    • On définit la couleur de remplissage du canvas en noir semi-transparent, puis dessine un rectangle de couleur sur toute la largeur et la hauteur du canvas, en utilisant fillRect() (les quatre paramètres fournissent une coordonnée de départ et une largeur et une hauteur pour le rectangle dessiné ). Cela sert à masquer le dessin de l'image précédente avant que la suivante ne soit dessinée. Si vous ne faites pas cela, vous verrez juste de longs serpents se faufiler autour de la toile au lieu de balles qui bougent ! La couleur du remplissage est définie sur semi-transparent, rgba (0,0,0,.25), pour permettre aux quelques images précédentes de briller légèrement, produisant les petites traînées derrière les balles lorsqu'elles se déplacent. Si vous avez changé 0.25 à 1, vous ne les verrez plus du tout. Essayez de faire varier ce dernier nombre (entre 0 et 1) pour voir l'effet qu'il a.
    • -
    • On crée un nouvel objet Ball() avec des attributs générées aléatoirement grâce à la fonction random(), puis on ajoute l'objet au tableau, mais seulement lorsque le nombre de balles dans le tableau est inférieur à 25. Donc quand on a 25 balles à l'écran, plus aucune balle supplémentaire n'apparaît. Vous pouvez essayer de faire varier le nombre dans balls.length <25 pour obtenir plus, ou moins de balles à l'écran. En fonction de la puissance de traitement de votre ordinateur / navigateur, spécifier plusieurs milliers de boules peut ralentir l'animation de façon très significative !
    • -
    • Le programme boucle à travers tous les objets du tableau sur chacun desquels il exécute la fonction draw() et update() pour dessiner à l'écran chaque balle et faire les mise à jour de chaque attribut vant le prochain rafraîchissement.
    • -
    • Exécute à nouveau la fonction à l'aide de la méthode requestAnimationFrame()  lorsque cette méthode est exécutée en permanence et a reçu le même nom de fonction, elle exécute cette fonction un nombre défini de fois par seconde pour créer une animation fluide. Cela se fait généralement de manière récursive  ce qui signifie que la fonction s'appelle elle-même à chaque fois qu'elle s'exécute, de sorte qu'elle sera répétée encore et encore.
    • -
    -
  4. -
  5. Finallement mais non moins important, ajoutez la ligne suivante au bas de votre code — nous devons appeler la fonction une fois pour démarrer l'animation. -
    loop();
    -
  6. -
- -

Voilà pour les bases — essayez d'enregistrer et de rafraîchir pour tester vos balles bondissantes!

- -

Ajouter la détection de collision

- -

Maintenant, pour un peu de plaisir, ajoutons une détection de collision à notre programme, afin que nos balles sachent quand elles ont frappé une autre balle.

- -
    -
  1. Tout d'abord, ajoutez la définition de méthode suivante ci-dessous où vous avez défini la méthode update() (c'est-à-dire le bloc Ball.prototype.update). - -
    Ball.prototype.collisionDetect = function() {
    -  for (let j = 0; j < balls.length; j++) {
    -    if (!(this === balls[j])) {
    -      const dx = this.x - balls[j].x;
    -      const dy = this.y - balls[j].y;
    -      const distance = Math.sqrt(dx * dx + dy * dy);
    -
    -      if (distance < this.size + balls[j].size) {
    -        balls[j].color = this.color = 'rgb(' + random(0, 255) + ',' + random(0, 255) + ',' + random(0, 255) +')';
    -      }
    -    }
    -  }
    -}
    - -

    Cette méthode est un peu complexe, donc ne vous inquiétez pas si vous ne comprenez pas exactement comment cela fonctionne pour le moment. Regardons cela pas-à-pas :

    - -
      -
    • Pour chaque balle b, nous devons vérifier chaque autre balle pour voir si elle est entrée en collision avec b. Pour ce faire, on inspecte toutes les balles du tableau balls[] dans une boucle for.
    • -
    • Immédiatement à l'intérieur de cette boucle for, une instruction if vérifie si la balle courante  b' , inspectée dans la boucle, n'est égale à la balle b. Le code correspondant est :  b'!== b. En effet, nous ne voulons pas vérifier si une balle b est entrée en collision avec elle-même ! Nous contrôlons donc si la balle actuelle bdont la méthode collisionDetect() est invoquéeest distincte de la balle b' inspectée dans la boucleAinsi le bloc de code venant après l'instruction if ne s'exécutera que si les balles b et b' ne sont pas identiques.
    • -
    • Un algorithme classique permet ensuite de vérifier la superposition de deux disques. Ceci est expliqué plus loin dans 2D collision detection.
    • -
    • Si une collision est détectée, le code à l'intérieur de l'instruction interne if est exécuté. Dans ce cas, nous définissons simplement la propriété color des deux cercles à une nouvelle couleur aléatoire. Nous aurions pu faire quelque chose de bien plus complexe, comme faire rebondir les balles de façon réaliste, mais cela aurait été beaucoup plus complexe à mettre en œuvre. Pour de telles simulations de physique, les développeurs ont tendance à utiliser des bibliothèques de jeux ou de physiques telles que PhysicsJS, matter.js, Phaser, etc.
    • -
    -
  2. -
  3. Vous devez également appeler cette méthode dans chaque image de l'animation. Ajouter le code ci-dessous  juste après la ligne balls[i].update();: -
    balls[i].collisionDetect();
    -
  4. -
  5. Enregistrez et rafraîchissez la démo à nouveau, et vous verrez vos balles changer de couleur quand elles entrent en collision !
  6. -
- -
-

Note : Si vous avez des difficultés à faire fonctionner cet exemple, essayez de comparer votre code JavaScript avec notre version finale (voir également la démo en ligne).

-
- -

Résumé

- -

Nous espérons que vous vous êtes amusé à écrire votre propre exemple de balles aléatoires bondissantes comme dans le monde réel, en utilisant diverses techniques orientées objet et divers objets d'un bout à l'autre du module ! Nous espérons vous avoir offert un aperçu utile de l'utilisation des objets.
-
- C'est tout pour les articles sur les objets
il ne vous reste plus qu'à tester vos compétences dans l'évaluation sur les objets.

- -

Voir aussi

- - - -

{{PreviousMenuNext("Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects/Adding_bouncing_balls_features", "Learn/JavaScript/Objects")}}

- - - -

Dans ce module

- - diff --git a/files/fr/learn/javascript/objects/object-oriented_js/index.html b/files/fr/learn/javascript/objects/object-oriented_js/index.html new file mode 100644 index 0000000000..c16e9a230e --- /dev/null +++ b/files/fr/learn/javascript/objects/object-oriented_js/index.html @@ -0,0 +1,278 @@ +--- +title: Le JavaScript orienté objet pour débutants +slug: Learn/JavaScript/Objects/JS_orienté-objet +tags: + - Apprendre + - Débutant + - Guide + - JavaScript + - OOJS + - OOP + - POO +translation_of: Learn/JavaScript/Objects/Object-oriented_JS +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}
+ +

Après avoir parcouru les fondamentaux, nous allons aborder en détail le JavaScript orienté objet (JSOO). Cet article présente une approche simple de la programmation orientée objet (POO) et détaille comment JavaScript émule des classes objet au travers des méthodes constructeur et comment instancier ces objets.

+ + + + + + + + + + + + +
Pré-requis :Connaissances de base en informatique et compréhension des notions HTML et CSS, notions de JavaScript (voir Premiers pas et Blocs de construction)
Objectif :Comprendre les concepts de base derrière la programmation orientée objet et comment ils s'appliquent à JavaScript ( « tout est objet » ) et comment créer des constructeurs et instancier des objets.
+ +

La programmation orientée objet de loin

+ +

Pour commencer, donnons une vue simplifiée et de haut niveau de ce qu'est la programmation orientée objet (POO). On parle d'une vision simplifiée étant donnée que la POO peut devenir très vite complexe et qu'être exhaustif rendrait probablement la découverte plus confuse et difficile qu'autre chose. L'idée de base de la POO consiste à utiliser des objets pour modéliser les objets du monde réel que l'on souhaite représenter dans nos programmes et/ou de fournir un moyen simple d'accéder à une fonctionnalité qu'il serait difficile d'utiliser autrement.

+ +

Les objets peuvent contenir des données et du code représentant de l'information au sujet de la chose que l'on essaie de modéliser ainsi que des fonctionnalités ou un comportement que l'on souhaite lui appliquer. Les données (et bien souvent les fonctions) associées à un objet peuvent être stockées (le terme officiel est encapsulé) à l'intérieur d'un paquet objet. Il est possible de donner un nom spécifique à un paquet objet afin  d'y faire référence, on parle alors d'espace de noms ou namespace, il sera ainsi plus facile de le manipuler et d'y accéder. Les objets peuvent aussi servir pour stocker des données et les transférer facilement sur un réseau.

+ +

Définissons un modèle objet

+ +

Nous allons voir un programme simple qui affiche des informations à propos des élèves et des professeurs d'une école. Nous allons aborder la théorie de la programmation orientée objet de manière générale sans l'appliquer à un langage particulier.

+ +

Pour débuter, nous pouvons réutiliser l'objet Personne que nous avons créé dans notre premier article, il définit un ensemble de données et actions d'une personne. Il existe tout un tas de choses que nous pourrions savoir au sujet d'une personne (son adresse, sa taille, sa pointure, son ADN, son numéro de passeport, ses traits particuliers significatifs… ). En l'occurrence, nous souhaitons uniquement afficher son nom, son âge, ses passions, écrire une petite introduction à son sujet en utilisant ces données et lui apprendre à se présenter. On parle alors d'abstraction : créer un modèle simplifié de quelque chose de complexe mais qui ne contient que les aspects qui nous intéressent. Il sera alors plus simple de manipuler ce modèle objet simplifié dans le cadre de notre programme.

+ +

Classe Personne avec attributs élémentaires

+ +

Dans plusieurs langages de POO, la définition d'un objet est appelé une classe (comme on le verra ci-après, JavaScript se base sur un mécanisme et une terminologie différente). En réalité ce n'est pas vraiment un objet mais plutôt un modèle qui définit les propriétés que notre objet doit avoir.

+ +

Créons des objets

+ +

À partir de notre classe, nous pouvons créer des objets, on parle alors d'instancier des objets, une classe objet a alors une instance. Il s'agit d'objets qui contiennent les données et attributs définis dans une classe. À partir de notre classe Personne, nous pouvons modéliser des personnes réelles :

+ +

Instantiation on a Personn Class for JS examples (fr)

+ +

Lorsque l'instance d'un objet est créée, on appelle la fonction constructeur de la classe pour la créer. On parle d'instanciation d'un objet — l'objet ainsi créé est instancié à partir de la classe.

+ +

Classes filles

+ +

Pour notre exemple, nous n'allons pas nous contenter de personnes génériques — nous pourrions utiliser des professeurs, des étudiants, qui sont des types un peu plus spécifiques de personnes. En POO, il est possible de créer de nouvelles classes à partir d'autres classes — ces classes filles nouvellement créées peuvent hériter des propriétés et des attributs de leur classe mère. Il est donc possible d'avoir des attributs partagés à l'ensemble des classes plutôt que de les dupliquer. Si besoin, il est possible d'ajouter des fonctions et attributs spécifiques sur chaque classe fille.

+ +

Inheritance principle with French text for JS example

+ +

Cela s'avère très utile puisque les étudiants et les professeurs se ressemblent sur de nombreux aspects : ils ont un nom, un genre, un âge, il est donc utile de ne définir ces attributs qu'une seule fois. Il est aussi possible de redéfinir le même attribut dans différentes classes étant donné que l'attribut appartiendra à chaque fois à un nom d'espace différent. On pourra ainsi avoir différentes formes de salutations : « Hey, je m'appelle [prénom] » pour les étudiants ( « Hey je m'appelle Sam » ) tandis que les professeurs pourront dire quelque chose d'un peu plus formel comme « Bonjour, mon nom est [Titre][Nom] et j'enseigne [matière] » par exemple « Bonjour mon nom est M. Griffiths et j'enseigne la chimie ».

+ +
+

Note : On parle de polymorphisme, lorsque des objets réutilisent la même propriété,  mais c'est juste pour info, vous embêtez pas.

+
+ +

Une fois la classe fille créée il est alors possible de l'instancier et de créer des objets. Par exemple :

+ +

Professor instantiation example for JS fr

+ +

Dans la suite de l'article, nous nous intéresserons à la mise en œuvre de la programmation orientée objet (POO) au sein de JavaScript.

+ +

Constructeurs et instances d'objet

+ +

Certains disent que le JavaScript n'est pas vraiment un langage de programmation orienté objet — Il n'existe pas, en JavaScript d'élément class pour créer des classes alors que c'est le cas dans plusieurs langages orientés objet. JavaScript quant à lui, utilise des fonctions spéciales appelées constructeurs pour définir les objets et leurs propriétés. Ces constructeurs s'avèrent utiles, puisque bien souvent, nous ne savons pas combien d'objets nous allons définir, les constructeurs nous permettent de créer autant d'objets que nécessaire et d'y associer des données et des fonctions au fur et à mesure.

+ +

Lorsqu'un objet est instancié à partir d'une fonction constructeur, les fonctions de la classe ne sont pas copiées directement dans l'objet comme dans la plupart des langages orientés objet (OO). En JavaScript, les fonctions sont liées grâce à une chaîne de référence appelée chaîne prototype (voir Prototypes Objet). Il ne s'agit donc pas d'une véritable instanciation au sens strict puisque JavaScript utilise un mécanisme différent pour partager des fonctionnalités entre les objets.

+ +
+

Note : Ne pas être un "langage classique de POO" n'est pas nécessairement un défaut. Comme nous le mentionnions au début de l'article, la POO peut très vite devenir compliquée et JavaScript, grâce à ses différences parvient à utiliser certains concepts avancés tout en restant abordable.

+
+ +

Voyons comment créer des classes via les constructeurs et les utiliser pour instancier des objets en JavaScript. Nous allons commencer par faire une copie locale du fichier oojs.html que nous avons vu dans notre premier article sur les objets.

+ +

Un exemple simple

+ +
    +
  1. Tout d'abord ; voyons comment définir une personne au travers d'une fonction classique. Vous pouvez ajouter l'exemple ci-dessous dans votre code existant : +
    function creerNouvellePersonne(nom) {
    +  var obj = {};
    +  obj.nom = nom;
    +  obj.salutation = function() {
    +    alert('Salut ! Je m\'appelle ' + this.nom + '.');
    +  };
    +  return obj;
    +}
    +
  2. +
  3. Vous pouvez désormais créer une personne en appelant cette fonction, essayez en copiant les lignes suivantes dans la console JavaScript de votre navigateur : +
    var salva = creerNouvellePersonne('Salva');
    +salva.nom;
    +salva.salutation();
    + Ça fonctionne bien, mais on peut améliorer notre exemple. Si l'on sait que l'on va créer un objet, pourquoi créer un objet vide pour l'utiliser ensuite ? Heureusement, JavaScript est là et possède des fonctions adaptées comme les constructeurs. À l'abordage !
  4. +
  5. Remplacez la fonction précédente par celle-ci : +
    function Personne(nom) {
    +  this.nom = nom;
    +  this.salutation = function() {
    +    alert('Bonjour ! Je m\'appelle ' + this.nom + '.');
    +  };
    +}
    +
  6. +
+ +

Le constructeur est l'équivalent JavaScript d'une classe. Il possède l'ensemble des fonctionnalités d'une fonction, cependant il ne renvoie rien et ne crée pas d'objet explicitement. Il se contente de définir les propriétés et les méthodes associées. Il y a aussi l'utilisation du mot-clé this, ce mot-clé sert au sein d'une instance qui sera créée à y faire référence, ainsi l'attribut nom sera, pour l'instance, égal au nom passé en argument de la fonction constructrice, la méthode salutation() retournera elle aussi le nom passé en argument de la fonction constructrice.

+ +
+

Note : Les fonctions de type constructeur commencent généralement par une majuscule. Cette convention d'écriture permet de repérer les constructeurs plus facilement dans le code.

+
+ +

Comment pouvons-nous utiliser un constructeur ?

+ +
    +
  1. Ajoutez les lignes suivantes au code déjà existant : +
    var personne1 = new Personne('Bob');
    +var personne2 = new Personne('Sarah');
    +
  2. +
  3. Enregistrez votre code et relancez le dans votre navigateur puis essayez d'entrer les lignes suivantes dans la console : +
    personne1.nom
    +personne1.salutation()
    +personne2.nom
    +personne2.salutation()
    +
  4. +
+ +

Pas mal ! Vous voyez désormais que nous avons deux nouveaux objets sur cette page, chaque objet étant stocké dans un espace de nom différent, pour y accéder il faut utiliser personne1 et personne2 pour préfixer les fonctions et attributs. Ce rangement permet de ne pas tout casser et de ne pas rentrer en collision avec d'autres fonctionnalités. Cependant les objets disposent du même attribut nom et de la même méthode salutation(). Heureusement, les attributs et les méthodes utilisent this ce qui leur permet d'utiliser les valeurs propres à chaque instance et de ne pas les mélanger.

+ +

Revoyons l'appel au constructeur :

+ +
var personne1 = new Personne('Bob');
+var personne2 = new Personne('Sarah');
+ +

Dans chaque cas, le mot clé new est utilisé pour dire au navigateur que nous souhaitons définir une nouvelle instance, il est suivi du nom de la fonction que l'on utilise et de ses paramètres fournis entre parenthèses, le résultat est stocké dans une variable. Chaque instance est créée à partir de cette définition :

+ +
function Personne(nom) {
+  this.nom = nom;
+  this.salutation = function() {
+    alert('Bonjour ! Je m\'appelle ' + this.nom + '.');
+  };
+}
+ +

Une fois les objets créés, les variables personne1 et personne2 contiennent les objets suivants :

+ +
{
+  nom: 'Bob',
+  salutation: function() {
+    alert('Bonjour ! Je m\'appelle ' + this.nom + '.');
+  }
+}
+
+{
+  nom: 'Sarah',
+  salutation: function() {
+    alert('Bonjour ! Je m\'appelle ' + this.nom + '.');
+  }
+}
+ +

On peut remarquer qu'à chaque appel de notre fonction constructrice nous définissons salutation() à chaque fois. Cela peut être évité via la définition de la fonction au sein du prototype, ce que nous verrons plus tard.

+ +

Créons une version finalisée de notre constructeur

+ +

L'exemple que nous avons utilisé jusqu'à présent était destiné à aborder les notions de base des constructeurs. Créons un constructeur digne de ce nom pour notre fonction constructrice Personne().

+ +
    +
  1. Vous pouvez retirer le code que vous aviez ajouté précédemment pour le remplacer par le constructeur suivant, c'est la même fonction, ça reste un constructeur, nous avons juste ajouté quelques détails : +
    function Personne(prenom, nom, age, genre, interets) {
    +  this.nom = {
    +    prenom,
    +    nom
    +  };
    +  this.age = age;
    +  this.genre = genre;
    +  this.interets = interets;
    +  this.bio = function() {
    +    alert(this.nom.prenom + ' ' + this.nom.nom + ' a ' + this.age + ' ans. Il aime ' + this.interets[0] + ' et ' + this.interets[1] + '.');
    +  };
    +  this.salutation = function() {
    +    alert('Bonjour ! Je m\'appelle ' + this.nom.prenom + '.');
    +  };
    +};
    +
  2. +
  3. Vous pouvez ajouter la ligne ci-dessous pour créer une instance à partir du constructeur : +
    var personne1 = new Personne('Bob', 'Smith', 32, 'homme', ['musique', 'ski']);
    +
  4. +
+ +

Vous pouvez accéder aux fonctions des objets instanciés de la même manière qu'avant :

+ +
personne1['age']
+personne1.interets[1]
+personne1.bio()
+// etc.
+ +
+

Note : Si vous avez du mal à faire fonctionner cet exemple, vous pouvez comparez votre travail avec notre version (voir oojs-class-finished.html (vous pouvez aussi jeter un œil à la démo)

+
+ +

Exercices

+ +

Vous pouvez démarrer en instanciant de nouveaux objets puis en essayant de modifier et d'accéder à leurs attributs respectifs.

+ +

D'autre part, il y a quelques améliorations possibles pour notre méthode bio(). En effet elle affiche systématiquement le pronom 'il', même si votre personne est une femme ou bien préfère se définir par un autre genre. De plus, la biographie n'inclut que deux passions, même s'il y en a plus dans la liste. Essayez d'améliorer cette méthode. Vous pourrez mettre votre code à l'intérieur du constructeur (vous aurez probablement besoin de quelques structures conditionnelles et d'une boucle). Réflechissez à la syntaxe des phrases qui devra s'adapter en fonction du genre et du nombre de passions listées.

+ +
+

Note: Si vous êtes bloqués, nous avons mis une réponse possible sur notre dépôt GitHub (la démo) —tentez d'abord l'aventure avant d'aller regarder la réponse !

+
+ +

D'autres manières d'instancier des objets

+ +

Jusque là nous n'avons abordé que deux manières différentes pour créer une instance d'objet, la déclarer de manière explicite et en utilisant le constructeur.

+ +

Elles sont toutes les deux valables, mais il en existe d'autres. Afin que vous les reconnaissiez lorsque vous vous baladez sur le Web, nous en avons listées quelques unes.

+ +

Le constructeur Object()

+ +

Vous pouvez en premier lieu utiliser le constructeur Object() pour créer un nouvel objet. Oui, même les objets génériques ont leur propre constructeur, qui génère un objet vide.

+ +
    +
  1. Essayez la commande suivante dans la console JavaScript de votre navigateur : +
    var personne1 = new Object();
    +
  2. +
  3. On stocke ainsi un objet vide dans la variable personne1. Vous pouvez ensuite ajouter des attributs et des méthodes à cet objet en utilisant la notation point ou parenthèses comme vous le souhaitez. +
    personne1.nom = 'Chris';
    +personne1['age'] = 38;
    +personne1.salutation = function() {
    +  alert('Bonjour ! Je m\'appelle ' + this.nom + '.');
    +};
    +
  4. +
  5. Vous pouvez aussi passer un objet en paramètre du constructeur Object(), afin de prédéfinir certains attributs et méthodes. +
    var personne1 = new Object({
    +  nom: 'Chris',
    +  age: 38,
    +  salutation: function() {
    +    alert('Bonjour ! Je m\'appelle ' + this.nom + '.');
    +  }
    +});
    +
  6. +
+ +

Via la méthode create()

+ +

Les constructeurs permettent de structurer le code : vous pouvez avoir l'ensemble de vos constructeurs au même endroit et ensuite créer les instances suivant vos besoins, en identifiant clairement leur origine.  

+ +

Cependant, on peut vouloir créér des instances d'un objet, sans forcément définir un constructeur au préalable. (Particulierement si l'on a peu d'instances de cet object). JavaScript intègre directement une méthode appelée create() qui rend cela possible. Elle permet d'instancier un objet à partir d'un objet existant  .

+ +
    +
  1. Essayez d'ajouter la ligne suivante dans votre console JavaScript : +
    var personne2 = Object.create(personne1);
    +
  2. +
  3. Maintenant : +
    personne2.nom
    +personne2.salutation()
    +
  4. +
+ +

personne2 a été créée à partir de personne1 — et elle possède les mêmes propriétés. 

+ +

L'inconvénient de create() est qu'elle n'est pas supportée par IE8. Ainsi, utiliser les constructeurs peut s'avérer plus judicieux lorsqu'il s'agit de supporter les anciens navigateurs Web.

+ +

Nous verrons les détails et les effets de create() plus tard.

+ +

Résumé

+ +

Cet article vous a donné un aperçu simplifié de la programmation orientée objet. Tout n'y a pas été détaillé mais ça vous permet de vous faire une idée. Nous avons vu comment JavaScript s'appuyait sur un certain nombre de principes orienté objet tout en ayant un certain nombre de particularités. Nous avons aussi vu comment implémenter des classes en JavaScript via la fonction constructeur ainsi que les différentes manières de générer des instances d'objets.

+ +

Dans le prochain article, nous explorerons le monde des objets prototypes en JavaScript.

+ +

{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}

diff --git a/files/fr/learn/javascript/objects/object_building_practice/index.html b/files/fr/learn/javascript/objects/object_building_practice/index.html new file mode 100644 index 0000000000..a2ab4270eb --- /dev/null +++ b/files/fr/learn/javascript/objects/object_building_practice/index.html @@ -0,0 +1,316 @@ +--- +title: La construction d'objet en pratique +slug: Learn/JavaScript/Objects/la_construction_d_objet_en_pratique +tags: + - Apprendre + - Article + - Canvas + - Débutant + - JavaScript + - Manuel + - Objets + - Tutoriel +translation_of: Learn/JavaScript/Objects/Object_building_practice +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects/Adding_bouncing_balls_features", "Learn/JavaScript/Objects")}}
+ +

Dans l'article précédent, nous avons passé en revue l'essentiel de la théorie de l'objet Javascript et sa syntaxe détaillée, vous donnant ainsi des bases solides sur lesquelles commencer. Dans le présent article nous plongeons dans un exercice pratique afin d'accroître votre savoir-faire dans la construction d'objets entièrement personnalisés donnant un résultat plutôt amusant et très coloré.

+ + + + + + + + + + + + +
Pré-requis : +

Connaissance basique de l'informatique, une compréhension basique du HTML et du CSS, une familiarité avec  les bases du JavaScript (voir Premiers pas et Les blocs de construction) et les bases de la programmation objet en JavaScript (voir Introduction aux objets). 

+
Objectif : +

Acquérir plus de pratique dans l'utilisation des objets et des techniques orientées objet dans un contexte "monde réel".

+
+ +

Faisons bondir quelques balles

+ +

Dans cet article, nous écrirons une démo classique de "balles bondissantes", pour vous montrer à quel point les objets peuvent être utiles en JavaScript. Nos petites balles bondiront partout sur notre écran et changeront de couleurs lorsqu'elles se toucheront. L'exemple finalisé ressemblera un peu à ceci : 

+ +

+ +
    +
+ +

Cet exemple utilise l'API Canvas  pour dessiner les balles sur l'écran, et l'API requestAnimationFrame  pour animer l'ensemble de l'affichage — Nul besoin d'avoir une connaissance préalable de ces APIs, nous expérons qu'une fois cet article terminé, vous aurez envie d'en faire une exploration approfondie. Tout le long du parcours nous utiliserons certains objets formidables et vous montrerons nombre de techniques sympathiques comme des balles bondissantes sur les murs et la vérification de balles qui s'entrechoquent (encore connue sous l'appelation détection de collision).

+ +

Pour commencer, faites des copies locales de nos fichiers index.html, style.css, et main.js. Ces fichiers contiennent respectivement :

+ +
    +
  1. Un document  HTML très simple contenant un élément {{HTMLElement("h1")}} , un élément {{HTMLElement("canvas")}} pour dessiner nos balles dessus et des élements  pour appliquer notre CSS et notre JavaScript à notre HTML ;
  2. +
  3. Quelques styles très simples qui servent principalement à mettre en forme et placer le <h1>, et se débarasser de toutes barres de défilement ou de marges autour du pourtour de notre page (afin que cela paraisse plus sympathique et élégant) ;
  4. +
  5. Un peu de JavaScript qui sert à paramétrer l'élément  <canvas> et fournir les fonctions globalles que nous utiliserons.
  6. +
+ +

La première partie du script ressemble à ceci :

+ +
const canvas = document.querySelector('canvas');
+
+const ctx = canvas.getContext('2d');
+
+const width = canvas.width = window.innerWidth;
+const height = canvas.height = window.innerHeight;
+ +

Ce script prend une référence à l'élément  <canvas> et ensuite invoque la méthode  getContext() sur lui, nous donnant ainsi un contexte sur lequel nous pouvons commencer à dessiner. La variable résultante  (ctx)  est l'objet qui représente directement la surface du Canvas où nous pouvons dessiner et qui nous permet de dessiner des formes 2D sur ce dernier. 

+ +

Après, nous configurons  les variables width (largeur) et height(hauteur),  et la largeur et la hauteur de l'élément canvas (représentés par les propriétés  canvas.width et canvas.height ) afin qu'elles soient identiques à la fenêtre du navigateur (la surface sur laquelle apparaît la page web— Ceci peut être tiré des propriétés {{domxref("Window.innerWidth")}} et {{domxref("Window.innerHeight")}}).

+ +

Vous verrez qu'ici nous enchaînons les assignations des valeurs des différentes variables ensemble à des fins de rapidité. Ceci est parfaitement autorisé.

+ +

Le dernier morceau du script ressemble à ceci :

+ +
function random(min, max) {
+  var num = Math.floor(Math.random() * (max - min + 1)) + min;
+  return num;
+}
+ +

Cette fonction prend deux nombres comme arguments, et renvoie un nombre compris entre les deux. 

+ +

Modéliser une balle dans notre programme

+ +

Notre programme met en œuvre beaucoup de balles bondissant partout sur l'écran. Comme nos balles se comporteront toutes de la même façon, cela semble tout à fait sensé de les représenter avec un objet. Commençons donc en ajoutant le constructeur suivant à la fin de notre code.

+ +
function Ball(x, y, velX, velY, color, size) {
+  this.x = x;
+  this.y = y;
+  this.velX = velX;
+  this.velY = velY;
+  this.color = color;
+  this.size = size;
+}
+ +

Ici, nous incluons des paramètres qui définissent  des propriétés dont chaque balle aura besoin pour fonctionner dans notre programme :

+ + + +

Ceci règle le problème des propriétés mais qu'en est il des méthodes ? Nous voulons maintenant amener nos balles à faire quelque chose dans notre programme.

+ +

Dessiner la balle

+ +

En premier lieu ajoutez la méthode draw() au prototype de Ball() :

+ +
Ball.prototype.draw = function() {
+  ctx.beginPath();
+  ctx.fillStyle = this.color;
+  ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
+  ctx.fill();
+}
+ +

En utilisant cette fonction, nous pouvons dire à notre balle de se dessiner sur l'écran en appelant une série de membres du contexte 2D du canvas que nous avons défini plus tôt  (ctx). Le contexte est comme le papier et maintenant nous allons demander à notre stylo d'y dessiner quelque chose :

+ + + +

Vous pouvez déjà commencer à tester votre objet.

+ +
    +
  1. Sauvegardez le code et chargez le fichier html dans un navigateur.
  2. +
  3. Ouvrez la console JavaScript du navigateur et actualisez la page afin que la taille du canvas change et prenne la petite taille restante de la fenêtre lorsque la console est ouverte.
  4. +
  5. Tapez dans la console ce qui suit afin de créer une nouvelle instance de balle : +
    let testBall = new Ball(50, 100, 4, 4, 'blue', 10);
    +
  6. +
  7. Essayez d'appeler ses membres : +
    testBall.x
    +testBall.size
    +testBall.color
    +testBall.draw()
    +
  8. +
  9. Lorsque vous entrerez la dernière ligne, vous devriez voir la balle se dessiner quelque part sur votre canvas.
  10. +
+ +

Mettre à jour les données de la balle

+ +

Nous pouvons dessiner la balle dans n'importe quelle position, mais actuellement pour commencer à la bouger nous aurons besoin d'une sorte de fonction de mise à jour. Insérez donc le code suivant à la fin de votre fichier JavaScript pour ajouter une méthode update() au prototype de Ball():

+ +
Ball.prototype.update = function() {
+  if ((this.x + this.size) >= width) {
+    this.velX = -(this.velX);
+  }
+
+  if ((this.x - this.size) <= 0) {
+    this.velX = -(this.velX);
+  }
+
+  if ((this.y + this.size) >= height) {
+    this.velY = -(this.velY);
+  }
+
+  if ((this.y - this.size) <= 0) {
+    this.velY = -(this.velY);
+  }
+
+  this.x += this.velX;
+  this.y += this.velY;
+}
+ +

Les quatre premières parties de la fonction vérifient si la balle a atteint le rebord  du canvas. Si c'est le cas, nous inversons la polarité de la vitesse appropriée pour faire bouger la balle dans le sens opposé. Donc par exemple, si la balle se déplaçait vers le haut (positif velY) alors la vitesse verticale est changée afin qu'elle commence à bouger plutôt vers le bas (negatif velY).

+ +

Dans les quatre cas nous :

+ + + +

Dans chaque cas, nous incluons la taille size de la balle dans les calculs parce que les coordonnées  x/y  sont situées au centre de la balle mais nous voulons que le pourtour de la balle rebondisse sur le rebord  — nous ne voulons pas que la balle sorte à moité hors de l'écran avant de commencer à rebondir vers l'arrière.

+ +

Les deux dernières lignes ajoutent la valeur velX à la coordonnée x et la valeur velY à la coordonnée y — la balle est en effet mise en mouvement chaque fois que cette méthode est invoquée.

+ +

Cela suffira pour l'instant, passons à l'animation !

+ +

Animer la balle

+ +

Maintenant, rendons cela amusant. Nous allons commencer à ajouter des balles au canvas et à les animer.

+ +
    +
  1. Tout d'abord, nous avons besoin d'un endroit où stocker toutes nos balles. Le tableau suivant fera ce travail — ajoutez-le au bas de votre code maintenant : + +
    let balls = [];
    +
    + +
    while (balls.length < 25) {
    +  let size = random(10,20);
    +  let ball = new Ball(
    +    // ball position always drawn at least one ball width
    +    // away from the edge of the canvas, to avoid drawing errors
    +    random(0 + size,width - size),
    +    random(0 + size,height - size),
    +    random(-7,7),
    +    random(-7,7),
    +    'rgb(' + random(0,255) + ',' + random(0,255) + ',' + random(0,255) +')',
    +    size
    +  );
    +
    +  balls.push(ball);
    +}
    + Tous les programmes qui animent les choses impliquent généralement une boucle d'animation, qui sert à mettre à jour les informations dans le programme et à restituer ensuite la vue résultante sur chaque image de l'animation. C'est la base de la plupart des jeux et autres programmes similaires.
  2. +
  3. Ajoutez ce qui suit au bas de votre code maintenant : +
    function loop() {
    +  ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
    +  ctx.fillRect(0, 0, width, height);
    +
    +  for (let i = 0; i < balls.length; i++) {
    +    balls[i].draw();
    +    balls[i].update();
    +  }
    +
    +  requestAnimationFrame(loop);
    +}
    + +

    Notre fonction loop() fonctionne comme suit :

    + +
      +
    • On définit la couleur de remplissage du canvas en noir semi-transparent, puis dessine un rectangle de couleur sur toute la largeur et la hauteur du canvas, en utilisant fillRect() (les quatre paramètres fournissent une coordonnée de départ et une largeur et une hauteur pour le rectangle dessiné ). Cela sert à masquer le dessin de l'image précédente avant que la suivante ne soit dessinée. Si vous ne faites pas cela, vous verrez juste de longs serpents se faufiler autour de la toile au lieu de balles qui bougent ! La couleur du remplissage est définie sur semi-transparent, rgba (0,0,0,.25), pour permettre aux quelques images précédentes de briller légèrement, produisant les petites traînées derrière les balles lorsqu'elles se déplacent. Si vous avez changé 0.25 à 1, vous ne les verrez plus du tout. Essayez de faire varier ce dernier nombre (entre 0 et 1) pour voir l'effet qu'il a.
    • +
    • On crée un nouvel objet Ball() avec des attributs générées aléatoirement grâce à la fonction random(), puis on ajoute l'objet au tableau, mais seulement lorsque le nombre de balles dans le tableau est inférieur à 25. Donc quand on a 25 balles à l'écran, plus aucune balle supplémentaire n'apparaît. Vous pouvez essayer de faire varier le nombre dans balls.length <25 pour obtenir plus, ou moins de balles à l'écran. En fonction de la puissance de traitement de votre ordinateur / navigateur, spécifier plusieurs milliers de boules peut ralentir l'animation de façon très significative !
    • +
    • Le programme boucle à travers tous les objets du tableau sur chacun desquels il exécute la fonction draw() et update() pour dessiner à l'écran chaque balle et faire les mise à jour de chaque attribut vant le prochain rafraîchissement.
    • +
    • Exécute à nouveau la fonction à l'aide de la méthode requestAnimationFrame()  lorsque cette méthode est exécutée en permanence et a reçu le même nom de fonction, elle exécute cette fonction un nombre défini de fois par seconde pour créer une animation fluide. Cela se fait généralement de manière récursive  ce qui signifie que la fonction s'appelle elle-même à chaque fois qu'elle s'exécute, de sorte qu'elle sera répétée encore et encore.
    • +
    +
  4. +
  5. Finallement mais non moins important, ajoutez la ligne suivante au bas de votre code — nous devons appeler la fonction une fois pour démarrer l'animation. +
    loop();
    +
  6. +
+ +

Voilà pour les bases — essayez d'enregistrer et de rafraîchir pour tester vos balles bondissantes!

+ +

Ajouter la détection de collision

+ +

Maintenant, pour un peu de plaisir, ajoutons une détection de collision à notre programme, afin que nos balles sachent quand elles ont frappé une autre balle.

+ +
    +
  1. Tout d'abord, ajoutez la définition de méthode suivante ci-dessous où vous avez défini la méthode update() (c'est-à-dire le bloc Ball.prototype.update). + +
    Ball.prototype.collisionDetect = function() {
    +  for (let j = 0; j < balls.length; j++) {
    +    if (!(this === balls[j])) {
    +      const dx = this.x - balls[j].x;
    +      const dy = this.y - balls[j].y;
    +      const distance = Math.sqrt(dx * dx + dy * dy);
    +
    +      if (distance < this.size + balls[j].size) {
    +        balls[j].color = this.color = 'rgb(' + random(0, 255) + ',' + random(0, 255) + ',' + random(0, 255) +')';
    +      }
    +    }
    +  }
    +}
    + +

    Cette méthode est un peu complexe, donc ne vous inquiétez pas si vous ne comprenez pas exactement comment cela fonctionne pour le moment. Regardons cela pas-à-pas :

    + +
      +
    • Pour chaque balle b, nous devons vérifier chaque autre balle pour voir si elle est entrée en collision avec b. Pour ce faire, on inspecte toutes les balles du tableau balls[] dans une boucle for.
    • +
    • Immédiatement à l'intérieur de cette boucle for, une instruction if vérifie si la balle courante  b' , inspectée dans la boucle, n'est égale à la balle b. Le code correspondant est :  b'!== b. En effet, nous ne voulons pas vérifier si une balle b est entrée en collision avec elle-même ! Nous contrôlons donc si la balle actuelle bdont la méthode collisionDetect() est invoquéeest distincte de la balle b' inspectée dans la boucleAinsi le bloc de code venant après l'instruction if ne s'exécutera que si les balles b et b' ne sont pas identiques.
    • +
    • Un algorithme classique permet ensuite de vérifier la superposition de deux disques. Ceci est expliqué plus loin dans 2D collision detection.
    • +
    • Si une collision est détectée, le code à l'intérieur de l'instruction interne if est exécuté. Dans ce cas, nous définissons simplement la propriété color des deux cercles à une nouvelle couleur aléatoire. Nous aurions pu faire quelque chose de bien plus complexe, comme faire rebondir les balles de façon réaliste, mais cela aurait été beaucoup plus complexe à mettre en œuvre. Pour de telles simulations de physique, les développeurs ont tendance à utiliser des bibliothèques de jeux ou de physiques telles que PhysicsJS, matter.js, Phaser, etc.
    • +
    +
  2. +
  3. Vous devez également appeler cette méthode dans chaque image de l'animation. Ajouter le code ci-dessous  juste après la ligne balls[i].update();: +
    balls[i].collisionDetect();
    +
  4. +
  5. Enregistrez et rafraîchissez la démo à nouveau, et vous verrez vos balles changer de couleur quand elles entrent en collision !
  6. +
+ +
+

Note : Si vous avez des difficultés à faire fonctionner cet exemple, essayez de comparer votre code JavaScript avec notre version finale (voir également la démo en ligne).

+
+ +

Résumé

+ +

Nous espérons que vous vous êtes amusé à écrire votre propre exemple de balles aléatoires bondissantes comme dans le monde réel, en utilisant diverses techniques orientées objet et divers objets d'un bout à l'autre du module ! Nous espérons vous avoir offert un aperçu utile de l'utilisation des objets.
+
+ C'est tout pour les articles sur les objets
il ne vous reste plus qu'à tester vos compétences dans l'évaluation sur les objets.

+ +

Voir aussi

+ + + +

{{PreviousMenuNext("Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects/Adding_bouncing_balls_features", "Learn/JavaScript/Objects")}}

+ + + +

Dans ce module

+ + diff --git a/files/fr/learn/javascript/objects/object_prototypes/index.html b/files/fr/learn/javascript/objects/object_prototypes/index.html new file mode 100644 index 0000000000..efb3681f18 --- /dev/null +++ b/files/fr/learn/javascript/objects/object_prototypes/index.html @@ -0,0 +1,244 @@ +--- +title: Prototypes Objet +slug: Learn/JavaScript/Objects/Prototypes_Objet +tags: + - Constructeur + - JavaScript + - Prototype +translation_of: Learn/JavaScript/Objects/Object_prototypes +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}
+ +

Les prototypes sont un mécanisme au sein de JavaScript qui permettent aux objets JavaScript d'hériter des propriétés d'autres objets. Les prototypes implémentent un héritage différent de celui rencontré dans les langages de programmation objets habituels. Dans cet article, nous allons aborder ces différences, nous allons aussi voir comment la chaîne de prototypage fonctionne. Nous verrons aussi comment les propriétés prototypes peuvent être utilisées afin d'ajouter des méthodes à des constructeurs existants.

+ + + + + + + + + + + + +
Pré-requis :Une connaissance générale de l'informatique, des notions d'HTML et CSS, une connaissance des bases en JavaScript (voir Premiers pas et Blocs de construction) ainsi que des notions de JavaScript orienté objet (JSOO) (voir Introduction aux objets).
Objectifs :Comprendre le concept de prototype en JavaScript, comprendre comment fonctionne une chaîne de prototypage et comment ajouter de nouvelles méthodes aux propriétés d'un prototype.
+ +

Un langage basé sur des prototypes ?

+ +

JavaScript est souvent décrit comme un langage basé sur les prototypes, chaque objet pouvant avoir un prototype objet d'où il hérite des méthodes et des attributs. Un prototype peut lui aussi avoir son prototype objet duquel il héritera des méthodes et des attributs et ainsi de suite. On parle alors de chaîne de prototypage (ou prototype chain en anglais). Cela permet d'expliquer pourquoi différents objets possèdent des attributs et des méthodes définis à partir d'autres objets.

+ +

En réalité, les méthodes et attributs sont définis dans l'attribut prototype , la fonction constructrice de l'objet et non pas dans les instances des objets elles-mêmes.

+ +

En programmation orientée objet classique, les classes sont définies, puis lorsque des instances sont créées, l'ensemble des attributs et des méthodes sont copiés dans l'instance. En JavaScript en revanche, tout n'est pas copié : on établit un lien entre l'objet instancié et son constructeur (c'est un lien dans la chaîne de prototypage). On détermine alors les méthodes et les attributs en remontant la chaîne.

+ +
+

Note: Il faut bien comprendre qu'il y a une différence entre la notion de prototype d'un objet (qu'on obtient via Object.getPrototypeOf(obj), ou via la propriété dépréciée  __proto__ ) et l' attribut prototyped'une fonction constructrice. La première concerne chaque instance, le dernier existe uniquement sur une fonction constructrice. Cela dit, Object.getPrototypeOf(new Foobar()) renvoie au même object queFoobar.prototype.

+
+ +

Prenons un exemple afin de rendre cela un peu plus clair.

+ +

Comprendre les prototypes objet

+ +

Reprenons notre exemple dans lequel nous avions écrit notre constructeur Personne(). Chargez cet exemple dans votre navigateur, si vous ne l'avez plus, vous pouvez utiliser notre exemple oojs-class-further-exercises.html example (voir aussi le code source).

+ +

Dans cet exemple, nous avons défini un constructeur comme suit :

+ +
function Personne(prenom, nom, age, genre, interets) {
+
+  // property and method definitions
+
+};
+ +

Nous avons ensuite instancié des objets comme ceci :

+ +
var personne1 = new Personne('Bob', 'Smith', 32, 'homme', ['musique', 'ski']);
+ +

Si vous entrez  « personne1 » dans votre console JavaScript, vous devriez voir que le navigateur essaie de faire de l'auto-complétion avec les attributs de cet objet.

+ +

+ +

Dans cette liste vous verrez les membres définis au niveau du constructeur de personne1 qui n'est autre  Personne(). On y trouve les valeurs suivantes : nom, age, genre, interets, bio, et salutation. On peut voir aussi d'autres membres tels que watch, valueOf …  Ces membres particuliers sont définis au niveau du prototype objet du constructeur Personne(), qui est Object. On voit ici une mise en œuvre de la chaine de prototypage.

+ +

+ +

Que peut-il bien se passer lorsque l'on tente d'appeler une méthode définie pour Object en l'appliquant à Personne1 ? Par exemple :

+ +
personne1.valueOf()
+ +

Cette méthode renvoie simplement la valeur de l'objet pour lequel elle est appelée. Vous pouvez essayer dans votre console ! Lorsque l'on effectue cet appel, il se produit les choses suivantes :

+ + + +
+

Note : Encore une fois, il est important d'insister sur le fait que les méthodes et attributs ne sont pas copiés d'un objet à un autre, mais qu'on y accède à chaque fois en remontant la chaine de prototypage.

+
+ +
+

Note : Il n'existe pas de façon officielle d'accéder directement au prototype d'un objet donné. Les « liens » entre les éléments de la chaine sont définis au sein d'une propriété interne appelée [[prototype]] définie dans la spécification de JavaScript. (voir ECMAScript). Néanmoins, la plupart des navigateurs modernes implémentent l'attribut __proto__   (deux tirets soulignés ou underscore de chaque côté) qui contient le prototype objet d'un objet. Vous pouvez tenter personne1.__proto__ et personne1.__proto__.__proto__ pour voir à quoi ressemble une chaine de prototypage dans la console !

+
+ +

L'attribut prototype : là où l'on définit les éléments héritables

+ +

Mais alors, où définissons-nous les attributs et méthodes qui seront hérités au long de la chaîne de prototypage ? En effet, s'il on regarde à la page de documentation Object on peut voir un large éventail d'attributs et de méthodes qui sont définis, une liste bien plus longue que celle disponible pour notre objet Personne1. Pourquoi Personne1 hérite de certains de ces éléments mais pas de tous ?

+ +

Cela vient du fait que les éléments hérités sont ceux définis au niveau de l'attribut prototype d'Object (on peut voir cet attribut comme un sous espace de noms). Ainsi, les éléments listés sont ceux sous Object.prototype. et pas ceux situés juste sous Object. La valeur de l'attribut prototype est un objet qui rassemble les attributs et méthodes que l'on souhaite appliquer aux objets tout au long de la chaine de prototypage.

+ +

Ainsi Object.prototype.watch(), Object.prototype.valueOf() …  sont disponibles pour n'importe quel objet qui hérite de Object.prototype ce qui inclus les nouvelles instances créées à partir du constructeur Personne().

+ +

Object.is(), Object.keys(), ainsi que d'autres membres non définis dans prototype ne sont pas hérités par les instances d'objet ou les objets qui héritent de Object.prototype. Ces méthodes et attributs sont disponibles uniquement pour le constructeur Object().

+ +
+

Note : Ça paraît bizarre, d'avoir une méthode définie au sein d'un constructeur qui est lui même une fonction non ? Et bien, une fonction est aussi un type d'objet — vous pouvez jeter un  œil à la documentation du constructeur Function() si vous ne nous croyez pas.

+
+ +
    +
  1. Vous pouvez vérifier les attributs du prototype en reprenant l'exemple précédent et en entrant le code suivant dans la console JavaScript : +
    Personne.prototype
    +
  2. +
  3. Il n'y a pas grand chose renvoyé par le navigateur. En même temps, nous n'avons rien défini dans l'attribut prototype de notre constructeur, et par défaut l'attribut prototype d'un constructeur est toujours vide. Voyons ce que renvoie le code suivant : +
    Object.prototype
    +
  4. +
+ +

On observe que plusieurs méthodes sont définies au niveau de l'attribut prototype d'Object, qui seront alors disponibles pour les objets qui héritent d'Object, comme nous l'avons vu plus haut.

+ +

Vous verrez qu'il existe plein d'exemples de chaine de prototypage dans JavaScript. Vous pouvez essayer de trouver les méthodes et les attributs définis dans les attributs prototype des objets globeaux comme String,  DateNumber, et  Array. Chacun de ces objets possède des éléments au sein de leur attribut prototype. Dès lors que l'on crée une chaine de caractères, comme celle-ci :

+ +
var maChaine = 'Ceci est ma chaine de caracteres.';
+ +

maChaine possède aussitôt plusieurs méthodes utiles pour manipuler les chaines de caractères telles que split(), indexOf(), replace()

+ +
+

Important : L'attribut prototype est un des éléments JavaScript qui peut le plus prêter à confusion. On pourrait penser qu'il s'agit du prototype objet de l'objet courant mais ça ne l'est pas (on peut y accéder via __proto__). L'attribut prototype est un attribut qui contient un objet où l'on définit les éléments dont on va pouvoir hériter.

+
+ +

Revenons sur create()

+ +

Nous avons vu précedemment que la méthode Object.create() pouvait être utilisée pour instancier des objets.

+ +
    +
  1. Par exemple, vous pouvez essayer le code suivant dans la console JavaScript : +
    var personne2 = Object.create(personne1);
    +
  2. +
  3. En réalité create() se contente de créer un nouvel objet à partir d'un prototype spécifique. Dans cet exemple, personne2 est créé à partir de personne1 qui agit en tant que prototype. Vous pouvez le vérifier via : +
    person2.__proto__
    +
  4. +
+ +

Cela renverra l'objet personne1.

+ +

L'attribut constructor

+ +

Chaque fonction possède un attribut prototype dont la valeur est un objet contenant un attribut constructor. L'attribut constructor renvoie vers la méthode constructrice utilisée. Nous allons le voir dans la section suivante, les attributs définis dans l'attribut Personne.prototype deviennent disponibles pour toutes les instances créées à partir du constructeur Personne(). De cette manière, l'attribut constructor est aussi disponible au sein de personne1 et personne2.

+ +
    +
  1. Par exemple, vous pouvez tester le code suivant : +
    personne1.constructor
    +personne2.constructor
    + +

    Chaque commande devrait renvoyer le constructeur Personne() étant donné qu'il a permis d'instancier ces objets.

    + +

    Une astuce qui peut s'avérer utile est d'ajouter des parenthèses à la fin de l'attribut constructor pour le transformer en méthode. Après tout, le constructeur est une fonction que l'on peut appeler si besoin. Il faut juste utiliser le mot-clé new pour signifier que l'on souhaite construire un objet.

    +
  2. +
  3. Par exemple : +
    var personne3 = new personne1.constructor('Karen', 'Stephenson', 26, 'femme', ['jouer de la batterie', 'escalade']);
    +
  4. +
  5. Vous pouvez désormais essayer d'accéder aux propriétés de personne3 : +
    personne3.prenom
    +personne3.age
    +personne3.bio()
    +
  6. +
+ +

Ça fonctionne bien. A priori, ce n'est pas la manière la plus simple de créer un objet et vous n'aurez pas à l'utiliser souvent. En revanche, ça peut vous débloquer quand vous devez créer une nouvelle instance et que vous ne disposez pas facilement du constructeur d'origine.

+ +

L'attribut constructor possède d'autres intérêts. Par exemple, si vous disposez du nom d'une instance objet vous pouvez utiliser le code suivant pour renvoyer le nom de son constructeur :

+ +
instanceName.constructor.name
+ +

Vous pouvez essayer :

+ +
personne1.constructor.name
+ +

Modifions les prototypes

+ +

Voyons au travers d'un exemple comment modifier l'attribut prototype d'un constructeur (les méthodes ajoutées au prototype seront alors disponibles pour toutes les instances créées à partir du constructeur).

+ +
    +
  1. Revenons à notre exemple oojs-class-further-exercises.html et faisons une copie local du code source. En dessous du JavaScript existant, vous pouvez ajouter le code suivant, ce qui aura pour effet d'ajouter une nouvelle méthode à l'attribut prototype du constructeur : + +
    Personne.prototype.aurevoir = function() {
    +  alert(this.nom.prenom + ' est sorti. Au revoir !');
    +}
    +
  2. +
  3. Enregistrez vos modifications et chargez la page dans votre navigateur. Vous pouvez ensuite entrer le code suivant dans la console : +
    personne1.aurevoir();
    +
  4. +
+ +

Vous devriez voir une fenêtre s'afficher avec un message contenant le nom de la personne. Cette fonctionalité est utile, mais là où ça devient plus intéressant c'est que la chaine de prototypage a été mis à jour dynamiquement, rendant automatiquement cette méthode disponible à l'ensemble des instances existantes.

+ +

Revoyons en détail ce qui s'est passé : tout d'abord, nous avons défini le constructeur. Ensuite, nous avons instancié un objet à partir du constructeur. Enfin, nous avons ajouté une nouvelle méthode au prototype du construceur :

+ +
function Personne(prenom, nom, age, genre, interets) {
+
+  // définition des attrbuts et des méthodes
+
+};
+
+var personne1 = new Personne('Tammi', 'Smith', 32, 'neutre', ['musique', 'ski', 'kickboxing']);
+
+Personne.prototype.aurevoir= function() {
+  alert(this.nom.prenom + ' est sorti. Au revoir !');
+}
+ +

Même si nous l'avons déclaré après, la méthode aurevoir() est disponible pour l'instance personne1. Son existence a mis à jour dynamiquement les méthodes de l'instance. Cela démontre ce que nous expliquions plus haut au sujet de la chaine de prototypage : le navigateur la parcourt de manière ascendante. Ainsi, il est possible de trouver directement les méthodes qui n'ont pas été définies au niveau de l'instance, plutôt que de les recopier au sein de l'instance. Cela nous permet de bénéficier d'un système extensible de manière simple et élégante.

+ +
+

Note : Si vous avez du mal à faire fonctionner cet exemple, vous pouvez jeter un œil au notre (oojs-class-prototype.html, voir la démo)

+
+ +

Vous verrez peu d'attributs définis au sein de l'attribut prototype, pour la simple et bonne raison que c'est assez peu pratique. Vous pourriez avoir :

+ +
Personne.prototype.nomComplet = 'Bob Smith';
+ +

Mais ce n'est pas très pratique, étant donné qu'une personne ne sera peut-être pas appelée de cette manière. Il est plus cohérent de construire le nom entier en combinant le nom et le prénom :

+ +
Personne.prototype.nomComplet = this.nom.prenom + ' ' + this.nom.nom;
+ +

Ça ne fonctionnera toujours pas. En effet, this aura une portée globale et ne sera pas dans le contexte de la fonction. En appelant cet attribut, nous aurions alors undefined undefined. Dans les exemples précédents sur le prototype, nous arrivions à obtenir quelque chose de fonctionnel puisque nous étions au sein d'une méthode, qui sera utilisée par l'instance. Il est donc possible de définir des attributs invariables au niveau du prototype mais de manière générale, il est préférable de les définir au sein du constructeur.

+ +

En fait, on retrouve généralement la chose suivante : les attributs sont définis dans le constructeur, tandis que les méthodes sont définies au niveau du prototype. Cela rend le code plus simple à lire puisque les attributs sont groupés et les méthodes structurées en blocs distincts. Par exempe :

+ +
// Constructeur avec définition des attributs
+
+function Test(a, b, c, d) {
+  // définition des attributs
+};
+
+// Définition de la première méthode
+
+Test.prototype.x = function() { ... }
+
+// Définition de la seconde méthode
+
+Test.prototype.y = function() { ... }
+
+// etc...
+ +

Ce type d'implémentation peut être observée dans l'appli plan d'école de Piotr Zalewa par exemple.

+ +

Résumé

+ +

Cet article a traité des prototypes objet en JavaScript, en incluant la chaine de prototypage qui permet aux objets d'hériter des propriétés d'un autre objet. Nous avons aussi vu l'attribut prototype et comment nous pouvons l'utiliser pour ajouter des méthodes au constructeur.

+ +

Dans le prochain article, nous verrons comment appliquer l'héritage entre deux de nos propres objets.

+ +

{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}

diff --git a/files/fr/learn/javascript/objects/prototypes_objet/index.html b/files/fr/learn/javascript/objects/prototypes_objet/index.html deleted file mode 100644 index efb3681f18..0000000000 --- a/files/fr/learn/javascript/objects/prototypes_objet/index.html +++ /dev/null @@ -1,244 +0,0 @@ ---- -title: Prototypes Objet -slug: Learn/JavaScript/Objects/Prototypes_Objet -tags: - - Constructeur - - JavaScript - - Prototype -translation_of: Learn/JavaScript/Objects/Object_prototypes ---- -
{{LearnSidebar}}
- -
{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}
- -

Les prototypes sont un mécanisme au sein de JavaScript qui permettent aux objets JavaScript d'hériter des propriétés d'autres objets. Les prototypes implémentent un héritage différent de celui rencontré dans les langages de programmation objets habituels. Dans cet article, nous allons aborder ces différences, nous allons aussi voir comment la chaîne de prototypage fonctionne. Nous verrons aussi comment les propriétés prototypes peuvent être utilisées afin d'ajouter des méthodes à des constructeurs existants.

- - - - - - - - - - - - -
Pré-requis :Une connaissance générale de l'informatique, des notions d'HTML et CSS, une connaissance des bases en JavaScript (voir Premiers pas et Blocs de construction) ainsi que des notions de JavaScript orienté objet (JSOO) (voir Introduction aux objets).
Objectifs :Comprendre le concept de prototype en JavaScript, comprendre comment fonctionne une chaîne de prototypage et comment ajouter de nouvelles méthodes aux propriétés d'un prototype.
- -

Un langage basé sur des prototypes ?

- -

JavaScript est souvent décrit comme un langage basé sur les prototypes, chaque objet pouvant avoir un prototype objet d'où il hérite des méthodes et des attributs. Un prototype peut lui aussi avoir son prototype objet duquel il héritera des méthodes et des attributs et ainsi de suite. On parle alors de chaîne de prototypage (ou prototype chain en anglais). Cela permet d'expliquer pourquoi différents objets possèdent des attributs et des méthodes définis à partir d'autres objets.

- -

En réalité, les méthodes et attributs sont définis dans l'attribut prototype , la fonction constructrice de l'objet et non pas dans les instances des objets elles-mêmes.

- -

En programmation orientée objet classique, les classes sont définies, puis lorsque des instances sont créées, l'ensemble des attributs et des méthodes sont copiés dans l'instance. En JavaScript en revanche, tout n'est pas copié : on établit un lien entre l'objet instancié et son constructeur (c'est un lien dans la chaîne de prototypage). On détermine alors les méthodes et les attributs en remontant la chaîne.

- -
-

Note: Il faut bien comprendre qu'il y a une différence entre la notion de prototype d'un objet (qu'on obtient via Object.getPrototypeOf(obj), ou via la propriété dépréciée  __proto__ ) et l' attribut prototyped'une fonction constructrice. La première concerne chaque instance, le dernier existe uniquement sur une fonction constructrice. Cela dit, Object.getPrototypeOf(new Foobar()) renvoie au même object queFoobar.prototype.

-
- -

Prenons un exemple afin de rendre cela un peu plus clair.

- -

Comprendre les prototypes objet

- -

Reprenons notre exemple dans lequel nous avions écrit notre constructeur Personne(). Chargez cet exemple dans votre navigateur, si vous ne l'avez plus, vous pouvez utiliser notre exemple oojs-class-further-exercises.html example (voir aussi le code source).

- -

Dans cet exemple, nous avons défini un constructeur comme suit :

- -
function Personne(prenom, nom, age, genre, interets) {
-
-  // property and method definitions
-
-};
- -

Nous avons ensuite instancié des objets comme ceci :

- -
var personne1 = new Personne('Bob', 'Smith', 32, 'homme', ['musique', 'ski']);
- -

Si vous entrez  « personne1 » dans votre console JavaScript, vous devriez voir que le navigateur essaie de faire de l'auto-complétion avec les attributs de cet objet.

- -

- -

Dans cette liste vous verrez les membres définis au niveau du constructeur de personne1 qui n'est autre  Personne(). On y trouve les valeurs suivantes : nom, age, genre, interets, bio, et salutation. On peut voir aussi d'autres membres tels que watch, valueOf …  Ces membres particuliers sont définis au niveau du prototype objet du constructeur Personne(), qui est Object. On voit ici une mise en œuvre de la chaine de prototypage.

- -

- -

Que peut-il bien se passer lorsque l'on tente d'appeler une méthode définie pour Object en l'appliquant à Personne1 ? Par exemple :

- -
personne1.valueOf()
- -

Cette méthode renvoie simplement la valeur de l'objet pour lequel elle est appelée. Vous pouvez essayer dans votre console ! Lorsque l'on effectue cet appel, il se produit les choses suivantes :

- - - -
-

Note : Encore une fois, il est important d'insister sur le fait que les méthodes et attributs ne sont pas copiés d'un objet à un autre, mais qu'on y accède à chaque fois en remontant la chaine de prototypage.

-
- -
-

Note : Il n'existe pas de façon officielle d'accéder directement au prototype d'un objet donné. Les « liens » entre les éléments de la chaine sont définis au sein d'une propriété interne appelée [[prototype]] définie dans la spécification de JavaScript. (voir ECMAScript). Néanmoins, la plupart des navigateurs modernes implémentent l'attribut __proto__   (deux tirets soulignés ou underscore de chaque côté) qui contient le prototype objet d'un objet. Vous pouvez tenter personne1.__proto__ et personne1.__proto__.__proto__ pour voir à quoi ressemble une chaine de prototypage dans la console !

-
- -

L'attribut prototype : là où l'on définit les éléments héritables

- -

Mais alors, où définissons-nous les attributs et méthodes qui seront hérités au long de la chaîne de prototypage ? En effet, s'il on regarde à la page de documentation Object on peut voir un large éventail d'attributs et de méthodes qui sont définis, une liste bien plus longue que celle disponible pour notre objet Personne1. Pourquoi Personne1 hérite de certains de ces éléments mais pas de tous ?

- -

Cela vient du fait que les éléments hérités sont ceux définis au niveau de l'attribut prototype d'Object (on peut voir cet attribut comme un sous espace de noms). Ainsi, les éléments listés sont ceux sous Object.prototype. et pas ceux situés juste sous Object. La valeur de l'attribut prototype est un objet qui rassemble les attributs et méthodes que l'on souhaite appliquer aux objets tout au long de la chaine de prototypage.

- -

Ainsi Object.prototype.watch(), Object.prototype.valueOf() …  sont disponibles pour n'importe quel objet qui hérite de Object.prototype ce qui inclus les nouvelles instances créées à partir du constructeur Personne().

- -

Object.is(), Object.keys(), ainsi que d'autres membres non définis dans prototype ne sont pas hérités par les instances d'objet ou les objets qui héritent de Object.prototype. Ces méthodes et attributs sont disponibles uniquement pour le constructeur Object().

- -
-

Note : Ça paraît bizarre, d'avoir une méthode définie au sein d'un constructeur qui est lui même une fonction non ? Et bien, une fonction est aussi un type d'objet — vous pouvez jeter un  œil à la documentation du constructeur Function() si vous ne nous croyez pas.

-
- -
    -
  1. Vous pouvez vérifier les attributs du prototype en reprenant l'exemple précédent et en entrant le code suivant dans la console JavaScript : -
    Personne.prototype
    -
  2. -
  3. Il n'y a pas grand chose renvoyé par le navigateur. En même temps, nous n'avons rien défini dans l'attribut prototype de notre constructeur, et par défaut l'attribut prototype d'un constructeur est toujours vide. Voyons ce que renvoie le code suivant : -
    Object.prototype
    -
  4. -
- -

On observe que plusieurs méthodes sont définies au niveau de l'attribut prototype d'Object, qui seront alors disponibles pour les objets qui héritent d'Object, comme nous l'avons vu plus haut.

- -

Vous verrez qu'il existe plein d'exemples de chaine de prototypage dans JavaScript. Vous pouvez essayer de trouver les méthodes et les attributs définis dans les attributs prototype des objets globeaux comme String,  DateNumber, et  Array. Chacun de ces objets possède des éléments au sein de leur attribut prototype. Dès lors que l'on crée une chaine de caractères, comme celle-ci :

- -
var maChaine = 'Ceci est ma chaine de caracteres.';
- -

maChaine possède aussitôt plusieurs méthodes utiles pour manipuler les chaines de caractères telles que split(), indexOf(), replace()

- -
-

Important : L'attribut prototype est un des éléments JavaScript qui peut le plus prêter à confusion. On pourrait penser qu'il s'agit du prototype objet de l'objet courant mais ça ne l'est pas (on peut y accéder via __proto__). L'attribut prototype est un attribut qui contient un objet où l'on définit les éléments dont on va pouvoir hériter.

-
- -

Revenons sur create()

- -

Nous avons vu précedemment que la méthode Object.create() pouvait être utilisée pour instancier des objets.

- -
    -
  1. Par exemple, vous pouvez essayer le code suivant dans la console JavaScript : -
    var personne2 = Object.create(personne1);
    -
  2. -
  3. En réalité create() se contente de créer un nouvel objet à partir d'un prototype spécifique. Dans cet exemple, personne2 est créé à partir de personne1 qui agit en tant que prototype. Vous pouvez le vérifier via : -
    person2.__proto__
    -
  4. -
- -

Cela renverra l'objet personne1.

- -

L'attribut constructor

- -

Chaque fonction possède un attribut prototype dont la valeur est un objet contenant un attribut constructor. L'attribut constructor renvoie vers la méthode constructrice utilisée. Nous allons le voir dans la section suivante, les attributs définis dans l'attribut Personne.prototype deviennent disponibles pour toutes les instances créées à partir du constructeur Personne(). De cette manière, l'attribut constructor est aussi disponible au sein de personne1 et personne2.

- -
    -
  1. Par exemple, vous pouvez tester le code suivant : -
    personne1.constructor
    -personne2.constructor
    - -

    Chaque commande devrait renvoyer le constructeur Personne() étant donné qu'il a permis d'instancier ces objets.

    - -

    Une astuce qui peut s'avérer utile est d'ajouter des parenthèses à la fin de l'attribut constructor pour le transformer en méthode. Après tout, le constructeur est une fonction que l'on peut appeler si besoin. Il faut juste utiliser le mot-clé new pour signifier que l'on souhaite construire un objet.

    -
  2. -
  3. Par exemple : -
    var personne3 = new personne1.constructor('Karen', 'Stephenson', 26, 'femme', ['jouer de la batterie', 'escalade']);
    -
  4. -
  5. Vous pouvez désormais essayer d'accéder aux propriétés de personne3 : -
    personne3.prenom
    -personne3.age
    -personne3.bio()
    -
  6. -
- -

Ça fonctionne bien. A priori, ce n'est pas la manière la plus simple de créer un objet et vous n'aurez pas à l'utiliser souvent. En revanche, ça peut vous débloquer quand vous devez créer une nouvelle instance et que vous ne disposez pas facilement du constructeur d'origine.

- -

L'attribut constructor possède d'autres intérêts. Par exemple, si vous disposez du nom d'une instance objet vous pouvez utiliser le code suivant pour renvoyer le nom de son constructeur :

- -
instanceName.constructor.name
- -

Vous pouvez essayer :

- -
personne1.constructor.name
- -

Modifions les prototypes

- -

Voyons au travers d'un exemple comment modifier l'attribut prototype d'un constructeur (les méthodes ajoutées au prototype seront alors disponibles pour toutes les instances créées à partir du constructeur).

- -
    -
  1. Revenons à notre exemple oojs-class-further-exercises.html et faisons une copie local du code source. En dessous du JavaScript existant, vous pouvez ajouter le code suivant, ce qui aura pour effet d'ajouter une nouvelle méthode à l'attribut prototype du constructeur : - -
    Personne.prototype.aurevoir = function() {
    -  alert(this.nom.prenom + ' est sorti. Au revoir !');
    -}
    -
  2. -
  3. Enregistrez vos modifications et chargez la page dans votre navigateur. Vous pouvez ensuite entrer le code suivant dans la console : -
    personne1.aurevoir();
    -
  4. -
- -

Vous devriez voir une fenêtre s'afficher avec un message contenant le nom de la personne. Cette fonctionalité est utile, mais là où ça devient plus intéressant c'est que la chaine de prototypage a été mis à jour dynamiquement, rendant automatiquement cette méthode disponible à l'ensemble des instances existantes.

- -

Revoyons en détail ce qui s'est passé : tout d'abord, nous avons défini le constructeur. Ensuite, nous avons instancié un objet à partir du constructeur. Enfin, nous avons ajouté une nouvelle méthode au prototype du construceur :

- -
function Personne(prenom, nom, age, genre, interets) {
-
-  // définition des attrbuts et des méthodes
-
-};
-
-var personne1 = new Personne('Tammi', 'Smith', 32, 'neutre', ['musique', 'ski', 'kickboxing']);
-
-Personne.prototype.aurevoir= function() {
-  alert(this.nom.prenom + ' est sorti. Au revoir !');
-}
- -

Même si nous l'avons déclaré après, la méthode aurevoir() est disponible pour l'instance personne1. Son existence a mis à jour dynamiquement les méthodes de l'instance. Cela démontre ce que nous expliquions plus haut au sujet de la chaine de prototypage : le navigateur la parcourt de manière ascendante. Ainsi, il est possible de trouver directement les méthodes qui n'ont pas été définies au niveau de l'instance, plutôt que de les recopier au sein de l'instance. Cela nous permet de bénéficier d'un système extensible de manière simple et élégante.

- -
-

Note : Si vous avez du mal à faire fonctionner cet exemple, vous pouvez jeter un œil au notre (oojs-class-prototype.html, voir la démo)

-
- -

Vous verrez peu d'attributs définis au sein de l'attribut prototype, pour la simple et bonne raison que c'est assez peu pratique. Vous pourriez avoir :

- -
Personne.prototype.nomComplet = 'Bob Smith';
- -

Mais ce n'est pas très pratique, étant donné qu'une personne ne sera peut-être pas appelée de cette manière. Il est plus cohérent de construire le nom entier en combinant le nom et le prénom :

- -
Personne.prototype.nomComplet = this.nom.prenom + ' ' + this.nom.nom;
- -

Ça ne fonctionnera toujours pas. En effet, this aura une portée globale et ne sera pas dans le contexte de la fonction. En appelant cet attribut, nous aurions alors undefined undefined. Dans les exemples précédents sur le prototype, nous arrivions à obtenir quelque chose de fonctionnel puisque nous étions au sein d'une méthode, qui sera utilisée par l'instance. Il est donc possible de définir des attributs invariables au niveau du prototype mais de manière générale, il est préférable de les définir au sein du constructeur.

- -

En fait, on retrouve généralement la chose suivante : les attributs sont définis dans le constructeur, tandis que les méthodes sont définies au niveau du prototype. Cela rend le code plus simple à lire puisque les attributs sont groupés et les méthodes structurées en blocs distincts. Par exempe :

- -
// Constructeur avec définition des attributs
-
-function Test(a, b, c, d) {
-  // définition des attributs
-};
-
-// Définition de la première méthode
-
-Test.prototype.x = function() { ... }
-
-// Définition de la seconde méthode
-
-Test.prototype.y = function() { ... }
-
-// etc...
- -

Ce type d'implémentation peut être observée dans l'appli plan d'école de Piotr Zalewa par exemple.

- -

Résumé

- -

Cet article a traité des prototypes objet en JavaScript, en incluant la chaine de prototypage qui permet aux objets d'hériter des propriétés d'un autre objet. Nous avons aussi vu l'attribut prototype et comment nous pouvons l'utiliser pour ajouter des méthodes au constructeur.

- -

Dans le prochain article, nous verrons comment appliquer l'héritage entre deux de nos propres objets.

- -

{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}

-- cgit v1.2.3-54-g00ecf