JavaScript débutant - noelno/dovelei GitHub Wiki

Notes de la playlist de Grafikart : https://www.youtube.com/playlist?list=PLjwdMgw5TTLVzD9Jq_WBd1crqDwXRn4cw

Variables

Le mot-clé let est fortement recommandé à l'initialisation d'une nouvelle variable mais pas obligatoire

Caractères autorisés : a-zA-Z0-9_

Conversions implicites : "6" + 2 = 62 (concaténation) mais "6" * 2 = 12 et "6" * 2 = 3.
D'où l'habitude de certains développeurs de multiplier par 1 un chiffre sous forme de chaîne pour le convertir en entier ou en float.
Par contre multiplier une chaîne qui n'est pas un chiffre retourne la valeur NaN

En cas de comparaison (< > >= <=) : les chaînes se comparent par-rapport à l'ordre alphabétique. "B" > "A" retournera true car B est après A dans l'ordre alphabétique.

Mais du coup "7" > "27" renverra aussi true car 7 arrive après 2 dans l'ordre alphabétique.

L'opérateur == réalise une conversion implicite si l'un des opérandes est un booléen : le deuxième sera converti en booléen. En false s'il s'agit d'une valeurs suivantes : 0, -0, "", NaN, null, undefined et false, ou en true par défaut. Un tableau ou un objet vide valent donc true !

Objets : A noter que contrairement au PHP, les deux syntaxes objet.cle et objet['cle'] fonctionnent pour accéder aux propriétés de l'objet. Une nouvelle propriété peut facilement être ajoutée dans à un objet littéral même si la clé n'était pas déclarée au départ.

Commentaires : comme en PHP /* */ ou //

Portée des variables

Les variables déclarées dans une fonction ne sont pas accessibles en dehors. Par contre les fonctions peuvent accéder aux variables déclarées avant leur appel (closure), et peuvent les modifier si on ne les redéclare pas avec le mot-clé var dans la fonction.
Par contre les variables déclarées dans des boucles (par exemple i) sont accessibles en dehors.

Constantes (ES6)

Depuis la version ES6, il est possible de déclarer des constantes avec le mot-clé const.

Structures

Ternaire : condition ? valeur si true : valeur si false
Priorité de l'opérateur & sur | dans une comparaison
break : quitte la boucle; continue : fait un nouveau tour de boucle sans terminer le tour actuel

Fonctions

Une fonction JS est un objet Function. En JS tout objet est passé par référence.
Il est possible de mémoriser la référence d'une fonction dans une variable et de l'appeler en ajoutant () au nom de la variable ( nomVariable() ).
Il est aussi possible d'envoyer la référence d'une fonction B en paramètre d'une autre fonction A, et d'appeler cette fonction B au sein de la fonction A.
On peut attribuer à une propriété dans un objet littéral une référence à une fonction, ce qui permet un comportement similaire à un namespace en PHP, en stockant un ensemble de méthodes dans un seul objet littéral.
Une fonction stockée dans une variable ne peut pas être appelée avant l'affectation à la variable, ce qui n'est pas le cas pour les fonctions déclarées "normalement" (cf. Hoisting)
Les fonctions qui ne retournent aucune valeur (pas de mot-clé return) retournent par défaut undefined, ce qui explique que l'on voit parfois undefined dans la console après un appel de fonction.

Fonction anonyme : fonction déclarée sans nom/référence. function(){ // }.

IIFE : Immediately Invoked Function Expression, fonction qui est appelée immédiatement après sa déclaration. Syntaxe ( function(){ // }() )

Les parenthèses qui encadrent la déclaration en font une expression de fonction au lieu d'une simple définition.
La paire de parenthèses suivant le mot-clé 'function' correspond à la signature de la fonction, et contient la liste de paramètres. La deuxième paire de parenthèses (après le }) correspond aux parenthèses d'appel de la fonction, et contient la liste d'arguments.

Hors d'une boucle on peut simuler le comportement du mot-clé continue en faisant un return false dans une fonction.

Hoisting

L'exécution du JS ne se fait pas exactement de haut en bas. L'interpréteur exécute d'abord les déclarations de fonctions et de variables, puis exécute le reste.
Ce qui explique comment une fonction déclarée hors d'une variable peut être appelée au-dessus du bloc de déclaration sans planter.
Ce qui explique aussi que i ait une valeur à la sortie de la boucle : la déclaration de i est en fait placée au tout début de l'exécution du script mais n'a pas encore de valeur, l'affectation ne se faisant que dans la boucle.
Si je déclare deux fonctions dans un même bloc, et que je place un appel à la fonction entre ces deux fonctions, c'est la dernière déclaration qui comptera bien que celle-ci soit placée après l'appel
Par contre si ces deux fonctions sont assignées à des variables, c'est bien la déclaration précédant l'appel qui sera prise en compte.
Source : https://www.youtube.com/watch?v=rMSqsMFAcKI

This

Par défaut fait référence à l'objet global window. Même chose en appelant une fonction dans une variable.
Par contre dans une méthode (une fonction dans un objet littéral), vaut l'objet en cours.
Un objet contenu dans un autre objet n'a pas accès au contexte de l'objet parent, mais on peut lui en donner l'accès en affectant le contexte actuel à une variable.
On peut appeler une méthode en changeant la valeur de this gràce à la méthode call()
Dans un eventListener, this vaut l'élément sur lequel est greffé l'événement.

Prototype

__proto__ : objet contenant des propriétés et méthodes selon le type de l'objet parent. Quand une méthode est appelée, l'interpréteur la cherche dans les méthodes de l'objet, puis dans les méthodes de son prototype. Attribuer à un objet B le prototype d'un objet A lui permet d'"hériter" des méthodes et propriétés de l'objet A. Pour initialiser une instance d'objet littéral, on peut faire un let instance = Object.create('nomObjet'), mais on utilisera le plus souvent un constructeur :

let Eleve = function(nom){
     this.nom = nom;
}
let jean = new Eleve('Jean');

Cet objet jean a une propriété __proto__, qui a elle-même sa propriété __proto__. Cet objet a aussi une propriété prototype.
Pour ajouter des méthodes au prototype : Eleve.prototype.nomMethode function(prop1){ // }
Le prototype peut donc évoluer dynamiquement : on peut y ajouter des propriétés et des méthodes n'importe quand, les instances seront directement impactées même si elles ont été initialisées avant la déclaration de ces nouvelles propriétés.
Les instances peuvent elles aussi recevoir leurs propres propriétés, qui sont prioritaires sur celles du prototype.
On peut créer l'équivalent des méthodes statiques en ajoutant une méthode directement à l'objet. Celui-ci ne sera pas hérité.

Eleve.moyenne = function(){
 //...
 return moyenne;
}

Try catch

La capture d'erreur permet de ne pas interrompre l'exécution de l'application en cas d'erreur.

try { //code sensible } catch(e) { // alternative } finally { //code s'exécutant quoi qu'il arrive }

catch prend en paramètre l'erreur. finally est surtout utile quand on ne veut pas capturer l'erreur mais que l'on veut quand même pouvoir exécuter quelque chose après l'erreur

On peut aussi créer ses propres objets erreur et les renvoyer quand la valeur d'une saisie n'est pas conforme à une condition avec la syntaxe throw new Error(String) ou dérivés de l'objet Error (TypeError...)

Les try...catch...finally sont imbriquables. Si une erreur n'est pas capturée dans un try enfant, l'erreur remonte au try...catch parent, et donc le catch du parent est exécuté.

Utile pour :

  • donner des indications précises aux utilisateurs de votre librairie.
  • proposer des alternatives à des risques précis.

Window

Les variables initialisées sont des propriétés de l'objet window.
En déclarant deux variables de même nom dans des fichiers .js différents, on prend le risque que l'une écrase l'autre. Pour contourner ce problème on peut écrire des IIFE, qui créent un contexte isolé de window.
window.alert() bloque l'exécution de la suite du script tant que l'utilisateur n'a pas cliqué sur Ok
window.prompt() affiche un message et récupère la saisie utilisateur
window.confirm() affiche un message et récupère true ou false selon la réponse de l'utilisateur
window.setInterval(fonction : callback ou variable, duree)
window.setTimeout(fonction : callback ou variable, duree)
window.clearInterval(id du setInterval à annuler)
window.clearTimeout(id du setTimeout à annuler)

Evénements

element.addEventListener(string event, function(e))
e.preventDefault() // annule l'événement
e.stopPropagation() // annule la propagation des événements vers les éléments parents

currentTarget : fait toujours référence à l’élément recevant l’événement (comme le this) target : fait référence à l’élément enfant cliqué Note sur la console : * celle-ci renvoie les valeurs des propriétés au moment où vous dépliez les données, pas au moment où l’action est déclenchée. Pour voir ces valeurs directement, afficher directement la propriété en question OU faire un breakpoint dans l’onglet Sources (Clic-droit sur l’objet > Créer une variable globale). * dans Elements, cliquer sur un élément puis sur le sous-onglet Event Listener pour suivre les éléments avec un Event Listener. Clic-droit > Show function definition : mène vers la définition de l’EventListener dans l’onglet Sources.

Element.removeEventListener(string, fonctionASupprimer) //supprime l’événement

Utiliser des id plutôt que des classes pour sélectionner des éléments en JS : plus performants, moins de risques que l’intégrateur renomme / supprime la classe et casse le JS

AJAX

AJAX : méthode, technique d'appel d'une page en JS, récupération de données, affichage des données
Cf. Réseau dans l'inspecteur pour voir les données transmises par le navigateur
Objet XMLHttpRequest
Cf. "Ajax Premiers pas" sur MDN

Console : filtre XHR dans l'onglet "Réseaux" => n'affiche que les requêtes AJAX Code prêt à l'usage pour créer un objet XMLHttpRequest compatible avec les anciens navigateurs : https://jsfiddle.net/wqamqoj2/

httpRequest.open(GET ou POST, page, async ?) //ouvre une requête
httpRequest.send(//paramètres POST si nécessaire) //envoie la requête httpRequest.readyState //retourne un chiffre allant de 0 à 4 selon le statut de la requête (4 étant la fin de la requête)
httpRequest.onreadystatechange //propriété à laquelle on assigne une fonction qui se lancera à chaque changement de readyState. httpRequest.responseText //retourne le texte du fichier appelé

Throttling : simule une connexion internet à bas débit

Interdiction d'appels d'AJAX de domaines externes sauf pour les serveurs embarquant un CORS

Fonctionne avec d'autres formats que le texte brut : HTML, JSON...
Il existe un objet JSON qui permet de parser du JSON brut en tableau d'objets : JSON.parse(httpRequest.responseText)
Dans la fonction affectée à httpRequest.onreadystatechange, on peut vérifier avant traitement des données reçues que ces données ont justement bien été reçues en regardant le statut : httpRequest.status (200 = réussi)

En AJAX, on récupère des données en provenance d'une page web en lui envoyant une requête sous forme de requête GET ou POST. On peut accessoirement envoyer des données :

  • en méthode GET, il suffit de communiquer les paramètres dans l'url de la page demandée, dans .open()
  • en méthode POST, les paramètres sont envoyés via la méthode .send(), associée à .setRequestHeader() pour que la page cible comprenne quel type de données lui sont envoyés.

Exemple :

httpRequest.open('POST', '/demo.php', true);
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
httpRequest.send("city=Montpellier&nom=Henry");

La méthode encodeURIComponent() permet d'échapper les caractères spéciaux d'une chaîne (&, =...) avant qu'ils ne soient injectés dans l'url.

Exemple : je dois envoyer un paramètre qui contient un &

let marque = "Ben & Jerry's";
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
httpRequest.send("marque=" + encodeURIComponent(marque) );

Pour les navigateurs récents, l'objet FormData permet de faire la même chose plus simplement :

let data = new FormData();
data.append('marque', 'Ben & Jerry');//je peux faire autant de append que de valeurs à passer
httpRequest.send(data);

Cette dernière méthode est particulièrement pratique avec les soumissions de formulaires ( monFormulaire.submit() ) : il suffit de passer le formulaire en paramètre du constructeur de FormData pour que celui-ci récupère en une seule fois toutes les données postées via le formulaire.

Si je souhaite réaliser une requête AJAX en synchrone, toutes les instructions après le .send() ne s'exécutent que si des données ont été reçues, il est donc inutile d'écrire des conditions httpRequest.readyState === 4 ou httpRequest.status === 200

Côté PHP :
$_SERVER['HTTP_X_REQUESTED_WITH'] == 'xmlhttprequest' //est vrai si une requête Ajax a été envoyée. Nécessite d'envoyer le header X-Requested-With dans la requête Ajax via la méthode .setRequestHeader('X-Requested-With', 'xmlhttprequest')
echo json_encode($content); //formate une variable en JSON. Côté navigateur penser à utiliser JSON.parse(httpRequest.responseText) pour convertir le résultat header('Content-type: application/json'); //le serveur PHP renvoie un header définissant que le contenu envoyé est du json
http_response_code(400); //le serveur PHP renvoie un header status de type 400
sleep(1); //le serveur attend 1 seconde avant d'exécuter la suite

Côté JS :
Object.keys($tableau); //récupère les clés d'un objet dans un tableau. Utile pour itérer sur toutes les propriétés d'un objet :

let objetKeys = Object.keys(objet);
for(let i; i < objetKeys.length; i++){
    let key = objetKeys[i];
    echo objet[key];
}

ElementInput.value //le contenu du champ, que l'on peut changer en lui attribuant une nouvelle valeur
ElementBoutonSubmit.disabled //lui affecter true pour le désactiver, le temps du traitement AJAX.
Astuce en sus : changer la valeur du texte du bouton (bouton.innerText ou .textContent) par 'Chargement...' pour que l'utilisateur ait un retour visuel du processus de chargement

⚠️ **GitHub.com Fallback** ⚠️