Valentin Dupas

💡 If this is the first course you read from me, please read this small thing : about my courses

Plus d'explications

Jusqu'ici tout ce que l'on a vu est soit une variable, soit une valeur, soit une fonction, soit un mot-clef. Pour le moment tout ceci ne vous dis pas grand chose mais expliquer ca est le but de ce chapitre.

Les valeurs

Ça c'est le plus simple, peut être même trop simple. 5 c'est une valeur, false c'est une valeur, "un peu de texte" est aussi une valeur. Le but d'un programme informatique est de manipuler des valeurs (souvent fournies par l'utilisateur) rapidement pour calculer et/ou partager de l'information.

Pour le moment on va se dire qu'il existe 3 type de valeurs différentes. On verra les autres plus tard.

  • Les nombres: 5, -12, 13.37
  • la valeur de vrai true et la valeur de faux false, que l'on appelle "valeurs booléennes" d'après George Boole qui s'est dit "viens on éssaye de faire des maths avec vrai/faux plutôt que des nombres, comme ça on pourra rigouresement calculer si un argumentaire est correct ou non".
  • les textes: "ceci est du texte", "ça aussi", 'on peut aussi mettre ça entre guillemets simples'. Sachez c'est quasiment tout le temps appelé une "string", du terme technique "string of characters" qui veux dire "chaîne de caractères".

Attention au guillemets

J'insiste parceque ça arrive régulièrement que de confondre un nombre 5 avec du texte représentant ce nombre "5". Ce qui n'est pas pareil.

Exécutez le code ci-dessous pour voir le résultat.

console.log(5 + 5);

console.log("5" + "5");

console.log(5 + "5");

Remarquez que l'opération + permet de coller deux bouts de texte ensemble en un plus gros bout de texte, et vu que ça ne fait aucun sense de chercher à additionner un nombre et du texte, javascript prévois dans ce cas de convertir le nombre en texte puis de les coller ensemble. Ce qui fâche beaucoup de programmeurs qui préféreraient qu'on leur refuse et qu'on les avertisse à la place.

Les variables

let mais aussi const

Une variable permet de garder une valeur en memoire, c'est bien pratique si on veux s'en servir plusieurs fois. Que soit parce que sa valeur pourrait changer entre deux utilisations comme on a vu avec la variable count au chapitre précédent, ou juste parce que c'est plus facile de donner un nom explicite a une valeur pour ensuite s'en servir à plusieur endroits du code.

let est le mot-clef qui nous permet de créer une variable à laquelle on pourra réassigner une nouvelle valeur plus tard dans le code comme ceci.

let a = 5;
a = a * 2;
console.log(a); // 10

c'est assez pratique quand il s'agit de données sur lesquelles ont est "en cours de travail".

Pour faciliter la lisibilité d'un programme on pourrait vouloir créer une variable qui n'as pas pour vocation de changer mais juste de mettre un nom sur une valeur.

Si je vous montre ...

console.log(42); // 42

... ainsi que ceci

let userAge = 42;
console.log(userAge); // 42

Le programme nous donne le même résultat, 42 dans la console. Mais dans le deuxième, en tant que développeur, vous comprennez qu'on déclare que l'âge de l'utilisateur est de 42 puis on s'affiche l'âge de l'utilisateur, ce qui communique clairement plus sur le fonctionnement du programme que le premier exemple.


Mais avoir toutes les variables de son programme qui ont la capacité de changer ça n'est pas nécessaire et notre programme s'exécute tellement vite que l'utilisteur n'aura pas le temps de fêter son anniversaire qu'on aura déjà fini. On peut juste remplacer let par const pour s'assurer qu'aucune ligne de code pourra changer la valeur de userAge en cours de routes.

const userAge = 42;
console.log(userAge); // 42

Je sais que cet exemple n'est pas très convaincant, mais imaginez que maintenant on parle d'une variable qui existe au travers de tout le programme et que ce programme fait 400 lignes, tout de suite c'est plus intéressant de se garantir que la variable ne peut pas changer, ça nous débarasse d'un paquet d'ennuis potentiel.

De manière générale, commencez toujours par créer vos variables avec const puis de les changer pour let si vraiment c'est utile.

undefined

Un nouveau type de valeur à ajouter à votre liste.

undefined (non-defini) est une valeur spéciale. Si on créer une variable sans pour autant lui donner de valeur alors sa valeur initiale sera undefined.

let a;
console.log(a); // undefined

En soi, cette valeur ne vous sert à rien mais au moins quand vous verrez l'erreur ci-dessous ça vous parlera un peu plus.

Uncaught ReferenceError: mySuperVariable is not defined

Trouvez le bug:

let a;
let b;
const c;

a = 5;
b = a + 5;
c = a + b;
Solution

Il est trop tard pour donner a + b comme valeur à c car au moment de sa création il a déjà reçu undefined comme valeur et vu que c'est une variable const on ne peut plus lui donner autre chose.

D'ailleurs, je remarque en écrivant ça que les navigateurs sont suffisamment intélligents et ne vous laissent même pas aller jusqu'à la dernière ligne. Effectivement, ne pas donner de valeur lors de la création d'une constante est littéralement inutile et donc ils ont prévu de crasher dans ce scenario.

Une valeur, certes, mais une valeur complexe

Je vous avais dit qu'une variable permet contenir une valeur, et je ne vous ai pas menti. Mais il existe un type de valeur que nous n'avons pas encore vu, qui est utilisé quasiment partout, et qui représente la majeure complexité du chapitre précédent.

Les objets.

Un objet est une valeur qui contient d'autre valeurs et qui se présente comme ceci.

{
    name: "John Oates",
    birth: 1948,
    retired: false,
    occupation: "out of time",
}

C'est toujours délimité par des accolades {} et chaque chose contenue présente d'abord son nom puis deux-points : puis la valeur et une virgule ,, la virgule de la derniere ligne n'étant pas obligatoire.

Les retours à la ligne ne sont pas obligatoires, on pourrait le marquer comme ceci ...

{ name: "John Oates",birth: 1948,	retired: false,	occupation: "out of time" }

... mais c'est généralement une bonne idée de les mettre dès qu'on dépasse 2~3 valeurs.

Un objet est rarement utile en dehors d'une variable, parce que si l'objet contient plusieurs valeurs on va probablement vouloir l'utiliser plusieurs fois dans le reste du code. Et puis le mettre dans une variable c'est aussi lui donner un nom et c'est toujours mieux.

Un truc sympa, est que ça à beau être un paquet de valeurs, on peut quand même le passer dans console.log() comme n'importe quelle autre valeurs plus simple.

const user = {
  name: "John Oates",
  birth: 1948,
  retired: false,
  occupation: "out of time",
};

console.log(user);

Allez-y, essayez.

Si vous voulez lire ou changer une propriété de votre objet vous pouvez y accedez en y acollant un point . que l'on appelle "l'opérateur d'accession" (un opérateur est juste un sybole qui combine des "opérandes". Par exemple + est l'opérateur d'addition et prend 2 nombres en guise d'opérandes).

const user = {
  name: "John Oates",
  birth: 1948,
  retired: false,
  occupation: "out of time",
};

console.log(user.name);

user.name = "Daryl Hall";

console.log(user.name);

Ça fonctionne exactement comme les chemins de dossier et de fichiers. /documents/counter.js veux dire "le fichier counter.js qui est dans le dossier documents sauf qu'on remplace les / par des .. user.name étant donc la propriété name qui est dans l'objet user.

Et si l'analogie avec le rangement de fichiers ne vous parle pas trop, on peut constater aussi que ça se lit assez bien de droite à gauche en règle générale.

(note de traduction: Waldo = Charlie)

Les fonctions

Du code reutilisable

Si une valeur qui porte un nom est une variable alors un ensemble de quelques lignes de code qui portent un nom est une fonction.

function liftoff() {
  console.log("3");
  console.log("2");
  console.log("1");
  console.log("liftoff!!");
}

En soit ça s'écrit comme ceci. D'abord le mot function pour déclarer que le code qui suit est une fonction. Comme let déclare que ce qui suit est une création de variable. Ensuite le nom de la fonction (qui peut être ce que l'on veut, comme avec les variables). Puis une paire de paranthèses () qu'on expliquera juste après, et enfin le "corps" de la fonction (ce qu'elle fait) entre accolades {}.

Executez le code ci-dessus pour voir.

Il ne se passe rien? Pourtant ça fait bien 5~6 lignes de code, et en plus il y à des console.log()!

Effectivement, tout ce que ce code fait est de créer la fonction liftoff() mais on ne s'en sert jamais.

function liftoff() {
  console.log("3");
  console.log("2");
  console.log("1");
  console.log("liftoff!!");
}

liftoff();
liftoff();
liftoff();

Pour s'en servir il suffit de taper son nom et ses parethèses comme ceci.

Exécutez le code ci-dessus.

Remarquez que la séquence de console.log() se voit autant de fois que l'on a appelé la fonction.

Du code qui s'adapte

Donc, ces fameuses paranthèses, elles servent à quoi?

C'est ce que l'on apelle les "paramètres" de la fonction, c'est assez pratique parce que le code qui appelle la fonction peut maintenant donner des valeurs à la fonction pour qu'elle puisse travailler dessus. Sans paramètres une fonction est condamnée à faire la même chose à chaque exécution.

function twoPartLog(a, b) {
  console.log("Du " + a + " et du " + b);
}

twoPartLog("jambon", "beurre");
twoPartLog("beurre", "jambon");

Donc, via ce code on créer une fonction twoPartLog() qui demande 2 valeurs. Valeurs que l'on donne au moment où on apelle la fonction. Ce qui détermine "quelle valeur va dans quel paramètre" est leur position. La première fois qu'on apelle la fonction, elle va s'exécuter avec a valant "jambon" et b valant "beurre" tandis qu'à la deuxième exécution ce sera l'inverse a vaudra "beurre" et b vaudra "jambon".

On peut nommer les paramètres d'une fonction comme on veux, au même titre que les variables. J'aurais très bien pu utiliser first et second au lieux de a et b. C'est juste que cet example est trop petit pour être concret et c'est donc difficile de leur donner un nom pertinent.

Allez-y exécutez ce code et verifiez par vous même.

function twoPartLog(a, b) {
  console.log("Du " + a + " et du " + b);
}

twoPartLog("jambon"); // "Du jambon et du undefined"

Remarquez que si on ne respecte pas une fonction en lui donnant moins que ce qu'elle doit recevoir elle s'exécute quand même en collant la valeur undefined dans les paramètres qui n'on pas reçus de valeurs (autrement dit, ils n'ont pas été definies). Ne comptez pas là dessus c'est degoutant 🤣, considerez qui si vous ne donnez pas au fonction ce qu'elles attendent est un problème. D'ailleurs je le fait tellement jamais que je m'attendais à ce que ça crash en écrivant ce chapitre, ce qui est le cas dans tous les autres langages que je connais.


Il y a une manière plus propre de faire une fonction qui prend entre 0 et N paramètres, mais ça nous sera pas utile dans un futur proche donc on verra ça plus tard (ou pas du tout).

function twoPartLog(a, b) {
  console.log("Du " + a + " et du " + b);
}

twoPartLog("jambon", "beurre", "cornichons"); // "Du jambon et du beurre"

Si vous en mettez trop ça passe aussi. Les valeurs qui sont en excédent seront recupérables avec une manip', mais pareil, evitez, c'est vraiment ouvrir la porte a des tas de bugs. La manière de faire ça proprement n'est pas utile dans l'immédiat donc on repassera.

Du code qui répond

Il est possible que l'on écrive nos fonction de telle sorte qu'elles nous rendent un résultat quand elles ont finie. Pour ca il suffit d'utiliser le terme return et une valeur comme ceci.

function giveMeFive() {
  return 5;
}

console.log(giveMeFive()); // 5

Ce qui va se passer c'est que lorsequ'on appelle une fonction on va d'abord l'exécuter puis remplacer son appel par la valeur qui aura été retournée, ce qui fait que notre exemple ci-dessus est équivalent à console.log(5).

Voici un exemple un peu plus concret.

function square(x) {
  return x * x;
}

console.log("Le carré de 4 est " + square(4)); // Le carré de 4 est 16

Nottez aussi quelque chose d'important, return stope l'exécution de la fonction. Donc si on rend une valeurs on quitte direcetement la fonction.

D'ailleurs on peut aussi utiliser return sans fournir de valeur si tout ce qui nous intéresse c'est d'arreter l'exécution.

function earlyStop() {
  console.log("vous me voyez");
  return;
  console.log("vous ne me verrez pas");
}

earlyStop();

Exécutez ce code pour vérifier que vous ne voyez pas le deuxième message.

Problème

Écrivez une fonction neg() qui prend un nombre en paramètre et qui renvoie son opposé.

exemple d'utilisation:

console.log(neg(5)); // -5;
console.log(neg(-13)); // 13

Faire des essais dans un projet vide est une bonne idée.

Solution
function neg(x) {
  return x * -1;
}

Recoller tous les morceaux

Ok, maintenant on a tout ce qu'il faut pour expliquer les éléments du chapitre précédent.

Déjà, sachez que le navigateur gère beaucoup de choses pour nous (c'est cool) donc il faut les apprendres (mais on peut le faire à notre rythme).

document

document est une variable gérée par le navigateur qui représente notre page web. Je vous invite à exécuter console.log(document) pour y jeter un œil, mais pas la peine d'y trainer trop longtemps parce que vous n'avez pas besoin de tout connaitre. Un petit exemple sympa et parlant c'est sa propriété title qu'on peut donc aller chercher via document.title.

Mais du coup maintenant vous comprennez que document.querySelector() c'est la fonction querySelector() de la page qui me permet de selectionner via un selecteur (CSS) et pour etre honnête c'est la seule fonction (avec document.querySelectorAll() mais on verra plus tard) dont je me sert regulièrement dans document.

exercice

Après avoir loggé et bien regardé document, essayez de changer le titre de la page web via javascript. Pour rappel le titre est ce qui est contenu dans la balise <title> en HTML et qui figure dans l'onglet du navigateur quand on visite la page avec un navigateur.

Solution
document.title = "mon super titre";

problème

En reprennant le code du compteur du chapitre précédent, faites en sorte que le titre du document soit la valeur du compteur et qu'il reste à jour lorsque le compteur change.

Solution
<script>
  let count = 0;
  document.title = count;

  document.querySelector("#minus-button").addEventListener("click", countDown);
  document.querySelector("#plus-button").addEventListener("click", handleClick);

  function handleClick() {
    count = count + 1;

    document.title = count;
    document.querySelector("#count").textContent = count;
  }

  function countDown() {
    count = count - 1;

    document.title = count;
    document.querySelector("#count").textContent = count;
  }
</script>

console

Eh oui, console est aussi un objet géré par le navigateur.

Et on peut aussi y jetter un œil avec console.log(console).

Donc...

... tout ce qu'on fait depuis le départ c'est de grassement utilisé des choses qui sont déjà là.

console.log() c'est juste la fonction log() de console. document.querySelector() c'est juste la fonction querySelector() de la variable document ...

Element

... et d'ailleurs document.querySelector() vous retourne un objet qui représente le premier élément HTML qui correspond. Un truc important à souligner est que tous les objets issus de document.querySelector() ont tous la même forme, autrement dit, ils ont tous les mêmes propriétés (mais pas nécessairement les même valeurs).

Allez-y attrapez en un et loggez-le pour voir ce qu'il contient.

Et c'est tout ce qu'on à fait au chapitre précédent.

  • utiliser la fonction querySelector() du document via document.querySelector() de nous rendre un élément HTML
  • utiliser la fonction addEventListener() de cet élément HTML pour lui donner une fonction à exécuter quand l'event (c'était un event de type "click") sera déclaneché

et à partir de là on à juste gardé la trace de notre progression dans une variable et mis à jour le contenu d'un élément HTML.

"C'est bien beau de regarder ce qu'il y a dans les objets comme le document ou les objets de type Element mais...

... comment je fais pour savoir qu'est-ce qui est utile?"

Quand on console.log() quelque chose qui n'est pas à vous:

  1. Les noms des propriétés sont assez évocateurs ("malgré" le fait qu'ils soient en anglais)
  2. vous pouvez prendre votre moteur de recherche favoris et chercher "MDN <nom de la propriété>". MDN étant un site qui liste tout ce que le navigateur gère à votre place et vous propose.

C'est essentiellement pour ça que j'adore javascript, il suffit de console.log() tout ce qui nous passe sous la main et d'aller faire de la lecture pour s'améliorer.

Mais bon, je vais aussi passer tous les prochains chapitres à vous parler de trucs très utiles qui vont pouvoir se combiner afin de produire des choses vraiment cool. Et qu'on soit clairs, le plus dur c'est le début parce que si le nombre de choses que vous connaissez est N alors le nombre de combinaisons est N*(N-1) qu'on peut simplifier N2 soit...

Les mots-clef

Les mots-clef sont des mots que l'on ne peut pas utiliser pour nommer nos fonction ou nos variables parce que javascript leur a déjà assigné un rôle.

Imaginez que j'éssaye de créer une variable qui s'appellerait let comme ceci:

let let = 5;

En admettant que ce soit accpeté, cette ligne pourrait tenir la route mais le reste du code à partir de là deviendrait un casse-tête catastrophique parce que la machine ne saurais pas si j'éssaye d'utiliser la varibable let ou d'utiliser le mot-clef let pour créer une variable.

Jusqu'ici les mots-clef que nous avons vu sont:

  • let
  • const
  • function
  • return

Donc, pour récapituler:

Si ça fait partie du langage c'est un mot-clef, sinon si il y a des paranthèses c'est une fonction sinon c'est une variable

Nottez aussi que la coloration des mots dans votre éditeur de code devrait donner une couleur différente à chacun de ces éléments.

Là où c'est possiblement difficile, c'est de faire la différence entre les variables/fonctions définies par le navigateur et les mot-clefs. Dites vous que si vous pouvez le passer dans une console.log() ce n'est pas un mot-clef. console.log(document) fonctionne mais console.log(let) ou console.log(return) est du charabia pour la machine.

if

La raison pour laquelle on cherche d'abord à déterminer si il s'agit d'un mot-clef dans le diagramme ci-dessus est d'abord parce que c'est facile vu qu'il y en a un nombre limité et que ça bouge très rarement (2~3 fois par décénnie). Mais aussi parce que certains mots-clefs on aussi des paranthèses comme if.

if ressemble un peu à une fonction sauf que ça s'exécute tout de suite si la condition qui est entre ses paranthèses () est vraie true.

exemple simple

if (6 > 0) {
  console.log("6 est positif"); // ce console.log() s'exécutera
}

if (42 > 50) {
  console.log("42 est plus grand que 50"); // mais pas celui-ci
}

Symboles utiles avec le if:

  • < : plus petit que
  • > : plus grand que
  • <= : plus petit ou égal à
  • >= : plus grand ou égal à
  • == : égal à
  • === : strictement égal à

La différence entre == et === est que == sera vrai si les deux éléments comparés sont équivalents tandis qu'avec === le résultat sera vrai si les deux comparées ont la même valeur et le même type.

exemple

console.log(5 == 5);      // true
console.log(5 == "5");    // true
console.log("5" == "5");  // true

console.log(5 === 5);     // true
console.log(5 === "5");   // false
console.log("5" === "5"); // true

Nottez qu'il faut que la valeur finale entre les paranthèses du if soit vraie, mais il n'est pas nécessaire que ce soit via une comparaison.

if(true){
  console.log("je m'executerais toujours");
}

if(false){
  console.log("je m'executerais jamais");
}

// donc
const maVar = true
if(maVar == true){}
// et
if(maVar){}
// sont entièrement équivalents

Aussi, si la valeur entre paranthèses n'est pas un booléen (true ou false) alors elle sera convertie automatiquement.

if("un peu de texte"){
  console.log("je m'executerais toujours");
}

if(""){
  console.log("je m'executerais jamais");
}

Les valeurs qui sont automatiquement converties en false sont des valeurs que l'on apelle "falsy". Il en existe très peu et ceux qui vont nous intéresser sont:

  • une string vide ""
  • undefined
  • 0

Ce qui est pratique parce que si on veux modifier un élément HTML qui existe peut être alors on peut faire ceci

const myMain = docement.querySelector("main");

if(myMain){
  myMain.textContent = "J'existe!";
}

On sélectionne l'élément <main> et on le met dans une variable. À ce moment, la variable contient soit l'objet javascript qui représente l'élément <main>, soit undefined parce qu'aucun élément de la page correspondait au selecteur main.

Un objet est equivalent a true et undefined est équivalent à false, donc on rentrera dans if(myMain) seulement si l'élément existe.

Problème

Écrivez une fonction max() qui prend deux nombres en paramètres et qui rend le plus grand des deux.

exemple d'utilisation

console.log(max(-1, 1)); // 1
console.log(max(1238, 2)); // 1238
Solution

Vous pourriez écrire ...

function max(a, b) {
  if (a > b) {
    return a;
  }

  if (b > a) {
    return b;
  }
}

... mais si on se rapelle que return arrête la fonction on peu simplifier comme ceci

function max(a, b) {
  if (a > b) {
    // a est plus grand que b?
    return a; // oui? tient prend a
  }

  return b; // on ne t'as pas donné a? donc prend b.
}

Problème

Reprennez le code du compteur au chapitre d'avant et ne laissez pas l'utilisateur descendre en dessous de 0 ni aller au dessus de 10.

indice

Au moment de changer le compteur vous pouver toujours tester la valeur du compteur et si elle dépasse dans un sens ou dans l'autre, vous la ramenez à la bonne valeur.

Solution
<script>
  let count = 0;

  document.querySelector("#minus-button").addEventListener("click", countDown);
  document.querySelector("#plus-button").addEventListener("click", handleClick);

  function handleClick() {
    count = count + 1;

    // ça depasse? oui?
    if (count > 10) {
      count = 10; // ça depasse plus
    }

    document.querySelector("#count").textContent = count;
  }

  function countDown() {
    count = count - 1;

    // ça depasse? oui?
    if (count < 0) {
      count = 0; // ça depasse plus
    }

    document.querySelector("#count").textContent = count;
  }
</script>

Altenativement:

<script>
  let count = 0;

  document.querySelector("#minus-button").addEventListener("click", countDown);
  document.querySelector("#plus-button").addEventListener("click", handleClick);

  function handleClick() {
    // est-ce que je suis encore en dessous du maximum?
    // oui? donc je peux me permettre de mettre à jour
    if (count < 10) {
      count = count + 1;
      document.querySelector("#count").textContent = count;
    }
  }

  function countDown() {
    // est-ce que je suis encore au desssus du minimum?
    // oui? donc je peux me permettre de mettre à jour
    if (count > 0) {
      count = count - 1;
      document.querySelector("#count").textContent = count;
    }
  }
</script>

else

Le mot-clef else permet de mettre un bloc après le bloc du if qui s'exécutera si la condition du if est fausse.

if(true){
  console.log("je m'executerais toujours");
}else{
  console.log("je m'executerais jamais");
}

if(false){
  console.log("je m'executerais jamais");
}else{
  console.log("je m'executerais toujours");
}