Javascript

Quelle différence entre le Node et les Elements dans le DOM?

lorsque vous faites des requêtes sur les éléments d’une page HTML et en faisant un affichage des éléments que vous avez obtenus, parfois vous avez des nodelist et parfois vous avez des Element, cela peut prêter à confusion parce que à première vue ce sont deux choses qui sont similaires, mais alors si elles sont similaires pourquoi elle portent deux types différents?

Node (Nœuds) dans le DOM

Dans le DOM, tout est un nœud. Un nœud peut être un élément, un attribut, un texte, un commentaire, un document, ou tout autre type d’objet DOM. Les nœuds sont organisés dans une structure arborescente, avec le nœud de document en haut et tous les autres nœuds en découlant.

Les nœuds ont des propriétés et des méthodes qui vous permettent de les manipuler ainsi que leurs nœuds enfants. Par exemple, vous pouvez utiliser la méthode appendChild() pour ajouter un nœud enfant à un nœud existant.

Éléments dans le DOM

Les éléments sont un type spécifique de nœud qui représente un élément HTML ou XML. Les éléments ont toutes les propriétés et méthodes d’un nœud, mais ils ont également des propriétés et des méthodes supplémentaires qui leur sont propres.

Par exemple, les éléments ont une propriété tagName qui spécifie le nom de l’élément, tel que « div » ou « span ». Les éléments ont également des attributs, qui peuvent être accédés en utilisant la méthode getAttribute() ou simplement en accédant à l’attribut comme une propriété de l’élément.

Il existe 12 types de noeuds

Source StackOverflow

Element est un type de noeud, il y a aussi les noeuds TEXT, COMMENT, etc. Mais le plus familier pour nous est le type Element, les éléments de la page HTML.

Quand obtient l’un ou l’autre?

Lorsque vous faite une requêtes qui peut retourner plusieurs item, vous obtenex un NodeList (ce n’est pas un tableau !)

    <div class="container">
        <ul id="liste">
            <li id="un">Un</li>
            <li id="deux">Deux</li>
            <li id="trois">Trois</li>
        </ul>
    </div>


let el = document.getElementById('un')   
console.log(el)  // retourne un Element

let nodelist = document.querySelectorAll('li')
console.log(nodelist)   // retourne un nodeList

Dans l’exemple ci-dessus, même si le second exemple retourne un NodeList, les items de cette nodelist sont des Elements ! Vous pouvez le vérifier avec instanceof

console.log(nodelist[0] instanceof Element)  // true
console.log(nodelist[0] instanceof Node)  // true
console.log(el instanceof Node)  // true

Mais alors pourquoi dans ce cas on ne fait pas un objet ElementList? c’est un choix des ingéieurs qui ont fait Javascript.

Par contre HTML5 définit un objet HTMLCollection, qui est un objet qui ne contient que des Element, qui exclut tous les autres types de noeuds. Vous pouvez voir HTMLCollection à l’oeuvre avec l’exemple suivant:

let el = document.getElementById('liste') 

En pratique vous n’avez pas à vous soucier de ces subtiles différences.

Quand utiliser Redux

Quand ne pas utiliser Redux

  • budget peu élevé
  • application de taille petite à moyenne
  • UI simple, flux de données simple
  • données statiques

Pours et contres de Redux:

Pour :

  • débug facilité
  • test
  • faire et défaire
  • persistence de state
  • préserve le state d’une page

Contre:

  • complexité
  • verbosité

Débuter avec Greasemonkey

C’est un plugin navigateur qui vous permet d’exécuter du code Javascript sur la page où vous vous trouvez. Vous connaissez les extensions de navigateur? Greasemonkey vous permet facilement de retrouver les mêmes capacités sans avoir à coder toute l’extension.

Installez Greasemonkey version 4 (sur Chrome c’est TamperMonkey).

Pour aller au plus simple, cliquez sur l’icône du singe, vérifiez qu’il est bien activé puis cliquez sur Nouveau Script

// ==UserScript==
// @name     Anonyme Script 813510
// @version  1
// @grant    none
// ==/UserScript==


Sion on veut de l'ajax (cross domain en plus !)
//@grant GM.xmlHttpRequest

Vous pouvez personnaliser les annotations, @name pour le nom du script, @version qui n’aura pas d’influence sur votre scripts, et surtout @grant est très important, si vous voulez par exemple faire une requêtes Ajax, par défaut vous ne pouvez pas. Je vous joins la page de documentation du plugin:

Comment déployer votre propre package sur NPM?

Nous allons voir comment créer et déployer soi-même son package NPM, plutôt cool comme idée non? Voici les étapes :

  • Créer un compte sur le site de NPM
  • écrire notre package
  • tester localement
  • publier notre package sur NPM
  • test grandeur nature de notre package

Créer un compte sur le registre NPM

Voici un fichier par default de package.json, personnalisez le :

{
  "name": "npmpackage",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

packge.json est le fichier important sans lui vous ne pouvez pas publier de package.

Le fichier index.js est le point d’entrée de votre package.

Le nom du package doit être unique dans tout le repository NPM, cela a donné à l’affaire du npmgate

Dans la barre de recherche de NPM vous pouvez chercher par nom de package.

Créez le fichier index.js

On va faire simple un seul fichier:

let uniqueArr = [];

function removeArrayDuplicates(arr) {
    // Accepts an array from which the duplicates
    // will be removed

    if (!Array.isArray(arr)) {
        arr = [];
    }

    let theSet = new Set(arr);

    arr.filter((num) => {
        if (!uniqueArr.includes(num)) {
            uniqueArr.push(num)
        }
    })

    return uniqueArr;
}

/* code de test */
let myNums = [1, 2, 3, 1, 4, 1, 2, 5, 3, 4];
let uniqueNums = removeArrayDuplicates(myNums)
console.log(uniqueNums);

Mettez à jour le package.json

{
  "name": "remove-dup-arr",
  "version": "0.1.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "remove",
    "array",
    "duplicate"
  ],
  "author": "refschool <[referencementschool@gmail.com](mailto:referencementschool@gmail.com)>",
  "license": "ISC"
}

Publication de votre package NPM

Pour cela inutile d’aller sur le site web de NPM ! vous pouvez tout faire en ligne dans votre terminal. Enlevez le code inutile d’application qui vient après la fonction.

npm login
// entrez vos identifiants

npm publish

j’ai eu un problème car le nom du paquet existe déjà, donc ce qu’on peut faire c’est de changer vers un nom qui n’existe pas encore

{
  "name": "openweather-wrapper",
  "version": "0.1.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "openweather",
    "meteo",
    "demo"
  ],
  "author": "refschool <[referencementschool@gmail.com](mailto:referencementschool@gmail.com)>",
  "license": "ISC"
}

PS E:\npmpackage> npm publish 
Debugger attached.
npm notice 
npm notice �📦  openweather-wrapper@0.1.0
npm notice === Tarball Contents ===
npm notice 521B index.js    
npm notice 359B package.json
npm notice === Tarball Details ===
npm notice name:          openweather-wrapper
npm notice version:       0.1.0
npm notice filename:      openweather-wrapper-0.1.0.tgz
npm notice package size:  586 B
npm notice unpacked size: 880 B
npm notice shasum:        ca698456c2b3c8691534f370f7539d0c42662724
npm notice integrity:     sha512-oCm4uzyLUsJC3[...]b1V0cR834Cchg==
npm notice total files:   2
npm notice
npm notice Publishing to https://registry.npmjs.org/
+ openweather-wrapper@0.1.0
Waiting for the debugger to disconnect...

Vérifions sur le site NPM la présence de notre package qui est visible pour le monde entier :

Test grandeur nature de notre package NPM

Maintenant que notre package est déployé je me suis rendu compte que quelque chose n’allait pas, il n’est pas utilisable car pas de directive export !

Remédions à cela à la fin du fichier index.js

module.exports = removeArrayDuplicates;

et republions.

Maintenant créons un autre répertoire (qui n’a rien à voir avec notre précédent répertoire) dans lequel nous allons tester notre package

npm install openweather-wrapper

Un répertoire node_modules va être créé.

Créez un fichier test.js avec le code suivant :

const tab = [8, 4, 2, 65, 2, 33, 33, 33, 22, 8, 8];
const removeArrayDup = require('openweather-wrapper');
let unik = removeArrayDup(tab)

console.log(unik)

Félicitation vous avez réussi !

javascript

Mémento de Fetch

Faire une requête GET avec fetch

L’expression la plus simple pour une requête GET avec fetch est :

fetch("https://google.fr")
.then(function(response){
    return response.json
})
.then()

Pour une requête GET pas la peine d’indiquer à la fonction car c’est celui par défaut

Faire une requête POST avec fetch

Le body

let apiUrl = "http://localhost/api/"
            fetch(apiUrl, {
                method: "POST",
                body: {
                    name : 'toto'
                   }
            })

La requête ci-dessus va envoyer un objet JSON contenat l’attribut « name », via la méthode POST (comme si c’était un formulaire)

javascript

Ecouter un événement de réponse AJAX

C’est quoi un événement en Javascript?

Un événement est par exemple un click de souris, une touche de clavier enfoncée, mais ça peut être purement logiciel, par exemple lorsque la page HTML a fini de se charger, il se produit un événement de type onload.

Un événement de requête AJAX

Ce type d’événement permet de détecter lorsqu’une requête AJAX est émise.

(function() {
    var origOpen = XMLHttpRequest.prototype.open;
    XMLHttpRequest.prototype.open = function() {
        console.log('request started!');
        this.addEventListener('load', function() {
            console.log('request completed!');
            console.log(this.readyState); //will always be 4 (ajax is completed successfully)
            var text = this.responseText
            toto = document.querySelector('#toto')
            toto.innerHTML = toto.innerHTML + text

        });
        origOpen.apply(this, arguments);
    };
})();
javascript

Javascript import et symbole @

Vous avez sans doute souvent vu dans un script javascript moderne ceci:

import Component from '@/components/component'

Normalement si on veut importer un module Javascript, il faut utiliser les / et les .. soit pour remonter d’un niveau soit pour descendre d’un niveau, comme on le ferait dans n’importe quel langage de programmation.

Cette notation n’est pas du Javascript natif, elle est rendue possible par l’utilisation d’un plugin de type module loader ou module bundler.

Un plugin comme babel plugin root import, quel root? le root du projet javascript en question. Ainsi quelquesoit l’emplacement du plugin et de la page qui demande le plugin, on utilisera l’arobase pour atteindre un plugin comme si on le demandait depuis la racine du projet.

Cela permet d’éviter que la syntaxe suivante :

import Component from 'components/component'

Dans ce cas ça va chercher dans /node_modules.

javascript

L’Event Loop dans Javascript

setTimeout n’appartient pas à V8

Javascript est single threaded

Blocking

Async callback and call stack @ 11:25

console.log('hi'); // A

setTimeout(function(){  // B
    console.log('there');
},5000);

console.log('Hello');  // C

Ordre d’appel dans le callstack A, B, C mais le ‘there’ est affiché 5 secondes après. Javascript ne fait qu’une seule chose à la fois

Event Loop

L’event loop regarde s’il reste encore des opérations à faire dans le stack, si le stack est vide, l’Event loop va regarder dans le task queue.

Liens :

JS Async

Latentflip Loupe

Javascript engine talk

javascript

Test de nullité en Javascrip : Cas où l’ordre a une importance

    const handleAccountCreation = async () => {
        const exist = await userExistCheck(result.email)
        console.warn('social login', exist)

        if (exist.exist !== null) {
            socialLogin(result.email)
            console.warn('social login')
        }
        else {
            createAccount(result.email)
            console.warn('social create account')
        }
    }

La condition dans le if échoue si exist est null, car exist.exist reverra une erreur undefined.

Il faut mettre une condition autrement

    const handleAccountCreation = async () => {
        const exist = await userExistCheck(result.email)
        console.warn('social login', exist)

        if (exist == null) {
             createAccount(result.email)
             console.warn('social login')
        }
        else {
            socialLogin(result.email)
            console.warn('social create account')
        }
    }

javascript

Opérateur point d’interrogation ?. en Javascript (Null propagation operator)

A ne pas confondre avec le null coalesce operator en Javascript ?? . Cet opérateur est encore appelé optional chaining operator.

        if (data.error?.message) {
          Alert.alert('Erreur carte',
            `Votre transaction ne s\'est pas terminée correctement Message de Stripe.com : ${data.error.message}`)
        } else {
          return data.id
        }

Si error n’existe pas alors data.error?.message évaluera en undefined

https://ponyfoo.com/articles/null-propagation-operator

react native

Boucler dans un JSX

La syntaxe JSX n’est pas forcément facile à appréhender, imaginez du HTML dans un return…

Pour faire une boucle sur un tableau afin d’afficher une liste par exemple d’élément JSX, il existe plusieurs façons, mais la plus répandue (99% semble-t-il) est d’utiliser map qui est une méthode de l’objet Array, qui retourne un tableau avec le même nombre d’éléments que le tableau d’entrée)

Façon ES6, la plus compacte avec fonction flèche

<div>
    {montableau.map((item, i) => <ObjectRow obj={item} key={i} />)}
</div>

Méthode avec le mot clé function

<div>
    {montableau.map(function(object, i){
        return <ObjectRow obj={item} key={i} />;
    })}
</div>

Avec la boucle for

Cette méthode est rarement vue mais elle marche

<div>
    for (var i=0; i < objects.length; i++) {
        <ObjectRow obj={objects[i]} key={i}>
    } 
</div>

https://stackoverflow.com/questions/22876978/loop-inside-react-jsx

javascript

Ecouter les événements du clavier avec Javascript

Cette thématique est rarement abordée, mais je trouve qu’il est intéressant d’ajouter des raccourcis clavier à votre application. Il existe des plugin qui le font déjà, mais back to basics, regardons comment on le fait avec du Javascript pur

Ecouter les touches alpha numérique de base

document.addEventListener('keydown', function (event) {
  if (event.key === 'a') {
    //votre code javascript ici
  }
  if (event.key === 'd') {
    //votre code javascript ici
  }
});

Il est assez simple d’ajouter un listener, mais l’astuce est de le faire sur l’élément document, comme ça, ça concernera toute votre page et on utilisera la délégation d’événement.

Ecouter les touches spéciales

document.addEventListener('keydown', function (event) {
  // CTRL + D combo
  if (event.ctrlKey && event.key === 'd') {
    //votre code
  }
  // CTRL + L combo 
  if (event.ctrlKey && event.key === 'l') {
    //votre code
  }
});

Eviter les conflits avec les autres raccourcis clavier de votre navigateur, par exemple sur Windows ou Linux, CTRL + D sert à bookmarker une page, pour éviter cela on va utiliser le célèbre preventDefault !!

document.addEventListener('keydown', function (event) {
event.preventDefault()
  // CTRL + D combo
  if (event.ctrlKey && event.key === 'd') {
    //votre code
  }
  // CTRL + L combo 
  if (event.ctrlKey && event.key === 'l') {
    //votre code
  }
});

Les autres touches péciales Alt, Shift etc

alt :  event.altKey
shift : event.shiftKey

Les modules en Javascript (import/export)

Tout d’abord sachez que les modules existent aussi bien ôté serveur que client. Les modules on été inventé pour permettre d’inclure ds fichier de script javascript comme on purrait le faire en PHP avec include.

Il existait plusieur type de module

  • AMD (Asynchronous Module Definition) un des plus ancien cf la librairie require.js
  • CommonJS, le systyme de mdule de NodeJS
  • UMD (universal Module Definition) Universal comme rassemblant AMD et CommonJS.

C’est quoi un module?

Un module est un fichier JS. Pour charger les uns des autres, il y a les mots clé import et export.

Exemple :

// sayHi.js
export function saluer(user) {
  alert(`Bonjour, ${user}!`);
}

Dans un autre fichier qui veut utiliser cette fonction

// main.js
import {sayHi} from './sayHi.js';
saluer('Jean'); // Bonjour Jean

ES2015 et ses apports

Grâce à ES2015, nous avons nativement les instructions import et export côté client. Si nous voulons importer un module dans une page HTML, nous devons utiliser le type module. Pour accéder au fichier HTML ci-dessous, vous devez avoir un serveur local, car ouvrir le fichier directement dans le navigateur avec le protocole file:// ne va pas marcher.

<!doctype html>
<script type="module">
  import { saluer} from './sayHi.js;
 document.body.innerHTML = sayHi('John');
</script>

Les particularités des modules

  • utiliser use strict
  • chaque module a son scope, les varaibles de deux modules sont invisible mutuellement
  • un module est exécutéune seule fois même s’il est importé de multiples fois

Export et import

Nous avons vu que à la base du système de module, ce sont ces deux mot clé qui sont incontournables.

Nous pouvons exporte une constante, un tableau , un objet, ou un fonction, ou encore une classe.

export const Pi = 3.14
export let nom = "Dupont"
expot class User{
   constructor(name){
      this.name = name
   }
} // pas de ; à la fin

function sayHi(user) {
  alert(`Hello, ${user}!`);
}

function sayBye(user) {
  alert(`Bye, ${user}!`);
}

export {sayHi, sayBye}; // a list of exported variables

Export default

On rencontre très couramment cette syntaxe. Un seul export défault par fichier JS. Et l’import se fait sans accolade.

export default class User { // just add "default"
  constructor(name) {
    this.name = name;
  }
}
// main.js
import User from './user.js'; // et non {User}

donc import utiliser les accolades pour les exports nommés, et pas d’accolade pour les export defaults.

https://javascript.info/modules-intro

https://javascript.info/import-export

Réaliser une application web avec Firebase, Firestore

Firebase d’avoir une base de données NoSQL principalement dans le cloud. Mais ça ne se limite pas à ça, il y a aussi du stockage d fichier, de code, de l’analytics, mais le principal usage à ma connaissance est la base temps réel NoSQL, son avantage est de permettre de mettre sur pied rapidement une application, pour peu qu’on soit familier avec lui.

Création d’un compte Firebase

Pour créer un compte Firebase, vous devez disposer d’un compte Google, et ensuite activer votre compte Firebase.

Contexte du tutoriel

Le contexte de l’application est une application dans une page html, donc pas besoin d’avoir NodeJs, nous verrons qu’il est possible de créer un projet de cette façon et de faire appel aux librairies, mais pour des raisons de simplicité, nous allons au plus simple.

Ensuite vous devez créer un projet et remplir des informations sur votre projet. Vous disposez d’niformation de configuration pour votre application.

Inclusion des scripts

Il y a plusieurs scripts à inclure en fonction de ce que vous voulez faire (analytics ou non) mais le principal fichier à inclure est le firebase-app.js

    <!-- The core Firebase JS SDK is always required and must be listed first -->
    <script src="https://www.gstatic.com/firebasejs/7.15.0/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/7.17.1/firebase-auth.js"></script>

    <script src="https://www.gstatic.com/firebasejs/7.15.0/firebase-firestore.js"></script>
    <!-- TODO: Add SDKs for Firebase products that you want to use
     https://firebase.google.com/docs/web/setup#available-libraries -->
    <script src="https://www.gstatic.com/firebasejs/7.15.0/firebase-analytics.js"></script>
#exemple de configuration Firebase
        // Your web app's Firebase configuration
        var firebaseConfig = {
            apiKey: "DCZ28p7gilP15WoymVHn-A",
            authDomain: "myapp-bull3503.firebaseapp.com",
            databaseURL: "https://myapp-bull3503.firebaseio.com",
            projectId: "myapp-bull3503",
            storageBucket: "myapp-bull3503.appspot.com",
            messagingSenderId: "2017024",
            appId: "1:2017024:web:e282485405d09",
            measurementId: "G-J4XXXQPHT9"
        };

// initialisation de l'app
firebase.initializeApp(firebaseConfig);

Créer une base de données orientée documents Cloud Firestore

Cette base est en accès public pour une durée de 30 jours, vous pourrez vous y connecter sans mot de passe, passé ce délai, vous recevrez une alerte comme quoi la base ne sera plus accessible en public. Dans la cnsole, vous verrez Realtime Database et Cloud Firestore, quelle est la différence? C’est expliqué sur cet article.

#paramétrage de la base de données
à l'origine le paramétrage est permissif pour vous permettre de tester la base

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.time  < timestampe.date(2020,7,6);
    }
  }
}

Mais au bout de 30 jours vous recevez un mail pour modifier l'accès à la base avec des règles plus strictes.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null;
    }
  }
}

Mais au bout de 30 jours vous recevez un mail pour modifier l'accès à la base avec des règles plus strictes.

Créer un utilisateur

Pour créer un utilisateur, chargez d’abord la librairie auth, qui vous permet de créer un utilisateur et de gérer les connexion.

#création d'un utilisateur via un formulaire
        firebase.auth().createUserWithEmailAndPassword(email, password).catch(function (error) {
            // Handle Errors here.
            var errorCode = error.code;
            var errorMessage = error.message;
            console.log(errorCode, ':', errorMessage)
        });

Si la création d’un utilisateur s’est faite avec succès, vous êtes automatiquement loggé. Si vous n’arrivez pas à créer un utilisateur de cette façon (probablement parce que vous avez oublié d charger la librairie auth) et que vous désirez rapidement en créer un, vous pouvez aller directement sur la console, dans la sidebar de gauche Authentification puis Ajouterun utilisateur

Connexion d’un utilisateur

        firebase.auth().signInWithEmailAndPassword(email, password).catch(function (error) {
            // Handle Errors here.
            var errorCode = error.code;
            var errorMessage = error.message;
            console.log(errorCode, ':', errorMessage)
        });

Pour maintenir la connexion de l’utilisateur entre différentes pages, il vous faudra utiliser le localStorage.

Lire une table

Je suppose que vous incluiez à chaque page les librairie correspondantes.

        var firebaseConfig = {
            ...
        };
        // Initialize Firebase
        firebase.initializeApp(firebaseConfig);
        firebase.auth().signInWithEmailAndPassword(email, password).catch(function (error) {
          ...
        });
#instanciation de la connexion à Firestore
var db = firebase.firestore();

Découvrez comment administrer la base de données depuis le site de Firebase.

Passage de paramètre à une fonction callback

vous connaissez tous la requête Ajax avec JQuery

$.ajax({
url:url,
method:'GET',
success:function(data){
  console.log(data)
}
})

En passant en callback une fonction anonyme, on définit la fonction à la volée, donc pas de problème pour passer des paramètres.

Mais qu’en est-il si on utilise une fonction nommée à la place?

function callback(data) {
console.log(data)
}

On serait tenté d’écrire :

$.ajax({
url:url,
method:'GET',
success:callback(data)
})

ça ne marche pas en effet, vous devez passer la fonction par référence, autrement dit vous devez passer le handler, en ajoutant des parenthèses vous exécutez la fonction. Donc on doit avoir la syntaxe suivante, mais qui amène à poser la question : mais comment on passe le paramètre data?

$.ajax({
url:url,
method:'GET',
success:callback
})

Il existe en Javascript la variable argument, qui fait référence aux paramètres qui sont passés, c’est un tableau commençant à l’index 0 pour le premier paramètre (donc data dans notre cas)

function callback() {
console.log(argument[0])
}

#marche quelquesoit le nombre de paramètres

Développer une application web en ReactJS

ReactJS à la différence de Angular et de VueJS, est une librairie qui s’occupe uniquement de la vue, très véloce, grâce à l’utilisation d’un virtual DOM. Le principe es de ne mettre à jours que ce qui est nécessaire.

Mise en place du projet

$ npx create-react-app myApp
# npx fourni depuis la version npm@5.2.0 est sensé vous faciliter la vie, si npx <command>, et que la <command> n'est pas dans le PATH, iil est capable d'installer la commande depuis NPM et l'invoquer.
# sortie de la commande npx create-react-app
Initialized a git repository.

Success! Created jeu at /Users/poste5hookipa/sites/reactapplication/jeu
Inside that directory, you can run several commands:

  yarn start
    Starts the development server.

  yarn build
    Bundles the app into static files for production.

  yarn test
    Starts the test runner.

  yarn eject
    Removes this tool and copies build dependencies, configuration files
    and scripts into the app directory. If you do this, you can’t go back!

We suggest that you begin by typing:

  cd jeu
  yarn start
react native

Les Hooks en React

Les hook sont apparus avec la version de React 16.8.

Le Hook UseState en ReactJS

Le hook UseState se charge du state dans les composants fonctionnels. Dans le composant de classe on avait :

this.setState(nouveauState)
#avec useState
const [state,setState] = useState(initialState)

Le hook useEffect

Il est l’équivalent de plusieurs fonction de cycle dans les composant de classe. Il remplace ComponentDidMount, ComponentDidUpdate.

#invocation au premier rendu
useEffect( () => {

},[])

#invocation au premier rendu et à chaque update du state
useEffect( () => {

},[variable])


#invocation uniquement à chaque update (et pas au premier chargement)

const isInitialMount = useRef(true);

useEffect(() => {
  if (isInitialMount.current) {
     isInitialMount.current = false; //grâce à cette astuce on bypasse l'exécution du code d'update au premier rendu
  } else {
      // le code pour chaque update
  }
});
javascript

Installer NPM sans avoir les problèmes de droit d’accès à des répertoire

Une des choses qui m’énervent le plus (et les développeur) est que dans certains processus de build avec NodeJs, on est confronté à des erreurs qui résultent de droits d’accès à des répertoires parce qu’on n’est pas utilisateur root. Ce problème se produit surtout en environnement MacOS et Linux. sous Windows vous travaillez en Administrateur en général.

Sur le site de NPM, il vous est expliquée ue procédure d’installation de NodeJS qui vous évite cet écueil. Le principe consiste à changer le répertoire par défaut de NPM.

https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally

Qu’est ce que le temporal dead zone TDZ en ES6?

Cette feature a été introduite depuis ES6 et concerne let et const, deux façons alternatives de déclarer des variables. En bref, si vous vouez accéder à des variables déclarées par let et const avant qu’elle ne soient initialisée va déclencher un ReferenceError là où l’utilisation de var va déclencher un undefined.

#utilisation nominale
var a = "bonjour"
console.log(a)
> "Bonjour"

#utilisation avant initialisation
console.log(b)
var b = "bonsoir" // undefined

#avec const
console.log(c)
const c = "hello" // ReferenceError: can't access lexical declaration `b' before initialization

Le variable hoisting

Pour comprendre le TDZ, il faut d’abord comprendre ce qu’est le hoiosting (hissage en anglais). Dans le langage de programmation JS, les variables sont les premières choses processées lors d’une compilation. déclarer une variable n’importe où équivaut à les déclarer en début de script. (source MDN).

Lorsque vous écrivez var a = « bonjour » en fait il y a deux choses qui se passent (et il faut avoir le réflexe de voir la chose de cette façon)

1/la déclaration de la variable : var a

2/l’initialisation de la variable, on lui donne une valeur : a = "bonjour"

Le hoisting (hissage) ne concerne que la déclaration et pas l’initialisation (important à savoir).

#donc écrire 
a = "bonjour"
var a
#est équivalent à
var a
a = "bonjour"

Pour cette raison, il est conseillé de déclarer les variable au début de leur scope (global ou dans la fonction). Donc ci-dessous un exemple :

function  dire(){
    console.log(a)
    var a = "bonjour"
}
#équivalent à
function dire(){
    var a
    console.log(a)
    a = "bonjour"
}

#autre exemple avec deux variables
var a = "bonjour"
var b = "bonsoir"

#équivalent à 
var a
var b
a = "bonjour"
b = "bonsoir"


#autre exemple
var x = y, y = 'A';
console.log(x + y); // undefinedA

#équivalent à
var x
var y
x = y // y n'est pas initialisé mais il existe et vaut undefined
y = 'A' // y est initialisé, mais x est toujours undefined
console.log(x + y) // undefinedA

La TDZ Temporal Dead Zone

Le petit exemple ci-dessous illustre les effets du TDZ pour let :

console.log(x) //ReferenceError: can't access lexical declaration `x' before initialization
let x = "bonjour" 

# équivalent
let x
console.log(x)
x = "bonjour"

let fait intervenir le hoisting, mais à la différence de var, si on essai d’y accéder, il renvoie ReferenceError. La TDZ est la propriété qui renvoie une ReferenceError lorsqu’on essai d’accéder à une variable non initialisée. La TDZ est cet espace entre la déclaration et l’initialisation d’une variable.

La TDZ a été créé pour avoir plus de feedback lorsque l’on code en Javascript.

Pour aller plus loin : la TDZ concerne aussi les argument d’une fonction. Je ne traiterais pas de ce sujet pour l’instant.

Pour plus d’information : la source d’inspiration

javascript

Améliorer son code par des cas réels

Lorsque l’on code et que l’on est débutant ou intermédiaire, il y a des bonnes chances de faire du code touffu ou en spaghetti, illisible, et souvent buggé. Nous allons voir avec des exemples concrets comment à partir d’un code issu du monde réel, on peut améliorer la lisibilité du code, la concision, et l’efficacité tout en évitant des bugs.

Lecture d’un tableau d’objet en Javascript

L’exemple ci-dessous est tiré d’une application Handlebars, le snippet lit un tableau d’objet en deux dimensions.

if(enfantsObject.EnfantsComm != null || enfantsObject.EnfantsP1 != null || enfantsObject.EnfantsP2 != null){
            if(Object.keys(enfantsObject).length){
                $.each(enfantsObject, function(index,value){
                    if(value != null && value != "{}" && jQuery.isNumeric( value )){
                        $.each(value, function(index2, value2){
                            if(value2.pension !== undefined){
                                montPens += Number(value2.pension);
                            }
                        })
                    }
                })
            }
        }

Le model à lire était un tableau d’objets avec les propriétés suivantes, un seul niveau d’imbriquement. Il y a plusieurs choses qui me surprennent, le fait d’utiliser la fonction de Jquery each, qui sert à itérer dans les éléments du DOM (les tags HTML), elle est ici utilisée alors qu’elle ne devrait pas l’être, inapproprié.

Le problème c’est que les propriétés sont changeante, elles peuvent ne pas être présentessuivant la façon dont l’objet a été initialisé. Voir l’exemple ci-dessous :

Dans l’exemple ci-dessus, les propriétés pension et pensionDate ne sont pas présentes ! Mauvaise pratique qui va nous compliquer le code, soit on retravaille l’initialisation, soit on checke les objets quand ils sont utilisés.

Ensuite il y a le Object.keys, elle est utilisée ici pour détecter que l’objet possède des clés (enfantCommuns, enfantP1, etc). Ceci n’est pas du tout stable, c’est en amont que les choses devraient être faites, notamment en initialisant proprement les différents propriétés de l’objet enfantsObject, y mettre un objet vide nous assure de la présence de la propriété et ne pas à avoir faire ce check inutile.

Première étape on simplifie le code

Si vous voulez améliorer votre code, mais que vous ne savez pas par où commencer, choisissez la lisibilité, qui doit être l’ultime but recherché, pas de code intelligent qui marche mais difficile à lire pour les autres développeur. Quitte à faire une simple boucle for au lieu de faire un map comme en programmation déclarative.

Ci-dessous, j’ai scindé en trois parties (attention il ya duplication de code similaire), ce qui n’est pas bon, mais cette étape intermédiaire nous permettra de refactorer en une fonction réutilisable.

J’ai du faire varier les différents cas sur l’interface pour voir les cas limites, et vous verrez un check pour s’assurer que c’est un tableau, en effet, quand il n’y a pas d’enfant présent, on n’a pas un tableau vide mais un objet ! (pourquoi ne pas revoir l’initialisation vous me direz? pour des impératifs de budget tout simplement)

Preuve que répéter du code n’est pas bon, parfois j’oublie de renommer à certains endroits et le programme plante.

        var pensionEnfantscommun = 0;
        var pensionEnfantPers1 = 0;
        var pensionEnfantPers2 = 0;

        if(enfantsObject.EnfantsComm != null && Array.isArray(enfantsObject.EnfantsComm)){
            for(i=0;i<enfantsObject.EnfantsComm.length;i++){
                if(enfantsObject.EnfantsComm[i].pension != undefined && enfantsObject.EnfantsComm[i].pension != ""){
                    pensionEnfantscommun += parseInt(enfantsObject.EnfantsComm[i].pension);
                }
            }    
        }

        if(enfantsObject.EnfantsP1 != null && Array.isArray(enfantsObject.EnfantsP1)){
            for(i=0;i<enfantsObject.EnfantsP1.length;i++){
                if(enfantsObject.EnfantsP1[i].pension != undefined && enfantsObject.EnfantsP1[i].pension != ""){
                    pensionEnfantPers1 += parseInt(enfantsObject.EnfantsP1[i].pension);
                }
            }    
        }

        if(enfantsObject.EnfantsP2 != null && Array.isArray(enfantsObject.EnfantsP2)){
            for(i=0;i<enfantsObject.EnfantsP2.length;i++){
                if(enfantsObject.EnfantsP2[i].pension != undefined && enfantsObject.EnfantsP2[i].pension != ""){
                    pensionEnfantPers2 += parseInt(enfantsObject.EnfantsP2[i].pension);
                }
            }    
        }

On vérifie que tout fonctionne (en tant que développeur il faut toujours bien tester ce que l’on fait). Maintenant nous pouvons faire une fonction réutilisable.

Seconde étape on refactore avec des fonctions

        // sous fonction 
        const majorationPension = function(enfant){
            if(enfant.pensionDate != undefined && enfant.pensionDate != ""){
                return Math.min(parseInt(enfant.pension) * 1.25,PARAM.SEUIL_JUGEMENT) 
            } else {
                return parseInt(enfant.pension)
            }
        }

        // fonction locale de calcul de fonction
        const sumPension = function(arrayEnfants){
                            const pensionEnfants = 0
                                if(arrayEnfants != null && Array.isArray(arrayEnfants)){
                                            for(i=0;i< arrayEnfants.length;i++){
                                                if(arrayEnfants[i].pension != undefined && arrayEnfants[i].pension != ""){
                                                    pensionEnfants += majorationPension(arrayEnfants[i]);
                                                }
                                            }    
                                        }
                                        return pensionEnfants
                                    }
        var montPens = 0;
        var pensionEnfantscommun = 0;
        var pensionEnfantPers1 = 0;
        var pensionEnfantPers2 = 0;

        pensionEnfantscommun = sumPension(enfantsObject.EnfantsComm)
        pensionEnfantPers1 = sumPension(enfantsObject.EnfantsP1)
        pensionEnfantPers2 = sumPension(enfantsObject.EnfantsP2)

J’ai ajouté une sous fonction majorationPension parce qu’il était nécessaire de faire un filtrage, et on n’oublie pas le parseInt, qui permet de convertir en véritable entier, sinon on aurait des erreurs de type NaN (not a number)

Notez l’utilisation de const pour des variable locales, une bonne pratique à prendre.

Conclusion

Maintenant on a sauvé quelques lignes, et surtout obtenu un code plus lisible pour la maintenance ou les évolutions plus tard.

javascript

Faire des tabulations en Javascript et Jquery

Voici le code minimal pour faire une tabulation (des onglets que l’on peut cliquer pour changer de contenu)

Comment faire des onglets cliquable en javascript?

Le principe :

On a en fait une rangée d’éléments cliquables, que l’on va mettre dans des <li>, mais ce n’est pas obligatoire, et ensuite les différentes <div> que l’on va révéler ou cacher suivant les <lI> cliquer.

<html>
<head>
<title>Tutorial theme</title>
</head>

<body>
    <style>
        .tab-menu {
            padding: 0;
        }
        .tab-menu li {
            display: inline-block;
        }
        .tab-menu .active {
            background: yellow;
        }
    </style>

        <ul class="tab-menu">
            <li><a href="#tab-1">Tab 1</a></li>
            <li><a href="#tab-2">Tab 2</a></li>
            <li><a href="#tab-3">Tab 3</a></li>

        </ul>

<div id="tab-1" class="tab-content" >
Contenu du tab 1
</div>
<div id="tab-2" class="tab-content" >
Contenu du tab 2
</div>
<div id="tab-3" class="tab-content" >
Contenu du tab 3
</div>


</body>
    <script type="text/javascript">
        $(document).ready(function() {
          $('.tab-content').slice(1).hide();
            $('.tab-menu li').eq(0).addClass('active');
            $('.tab-menu li a').click(function(e) {
                e.preventDefault();
                var content = $(this).attr('href');
                $(this).parent().addClass('active');
                $(this).parent().siblings().removeClass('active');
                $(content).show();
                $(content).siblings('.tab-content').hide();
            });
        });
    </script>
</html>

Donc pour résumer en cliquant un lien, ce lien a sa classe css à active, les autres qui sont à côté sont inactifs, content est égal à ce qu’il y a dans l’attribut href, $(content) va en réalité sélectionner l’élément ayant l’id (unique cela va de soi), et le montre, tous ses voisins sont cachés.

 

 

 

Checklist pour développer une PWA (Progressive Web App)

J’essais de créer une PWA depuis quelques temps, et je m’aperçois qu’il y a pas mal de choses à connaitre (vraiment), les connaissances que j’ai acquises en deux ans de JS et d’Angular, ne sont pas suffisantes. Je me fais une liste des pré-requis pour développer une PWA afin d’avoir une feuille de route pour avoir le parcours optimal. Les informations ci-dessous sont tirées du site Google Developer.

Introduction aux Progressives Web App (PWA)

Les PWA sont des pages web dynamiques, offrant des fonctions équivalentes aux applications natives, c’est récent à la date du 2017. Pourquoi a-t-on inventé ça? Pour répondre à plusieurs problématiques inhérentes aux applications natives.

Pourquoi parier sur les PWA?

1/Réduire le travail de développement.

Souvenez vous il n’y a pas si longtemps, on avait Ios, Android et Windows Phone (ce dernier est enterré). Il nous reste donc IOS et Android. Donc si vous voulez développer une application pour ces deux plateformes, vous devez faire deux fois le travail.

2/Les utilisateurs n’installent plus les applications natives

, et seulement une poignée est utilisée régulièrement.

3/Réduire la taille des applications (ou la friction d’installation)

C’est le côté progressif. On ne vous oblige pas à installer une application, mais à tester en douceur le site web, et aller plus loin si vous êtes intéressé.

Ce sont les trois avantages majeurs des PWA. Nous allons voir qu’elles n’ont pratiquement rien à envier aux applications natives. Donc plutôt que d’apprendre à programmer en Java ou Swift, voire en C# si vous voulez utiliser Xamarin (la solution la plus aboutie actuellement), vous allez pouvoir programmer pour toutes les plateformes en Javascript seulement! Donc gros avantage pour les développeurs front-end qui connaissent déjà le Javascript !

Les notions à connaître en PWA

1/Web Push Notification

Les notifications sont les messages que vous voyez apparaitre en haut de l’écran de votre smartphone. Push veut dire qu’il n’est pas besoin (après que vous ayez opté pour les recevoir) pour vous de faire quoique ce soit pour les recevoir. C’est intéressant car pour les marketeurs et pour les développeurs, vous pouvez entrer dans l’intimité d’une personne.

2/Service Worker

C’est l’élément essentiel de la PWA et c’est un gros morceau. Le Service Worker est un thread du processus du navigateur qui tourne en parallèle à côté de la page web proprement dite (le DOM) qui est un autre thread, c’est du code javascript, qui rend les choses hors connexion possibles entre autre (et aussi les Push Notification), le stockage des informations même quand vous êtes hors ligne. Le service worker peut accéder au thread de la page web, donc à l’objet window. Mais il n’y accède pas avec l’objet window qui n’est pas disponible dans le thread, mais via self qui est l’équivalent de window.

Dans le cadre de la programmation d’un service worker, il faut connaitre les Promise, une façon moderne de programmer le JS asynchrone sans faire appel aux callback.

3/Accès aux fonctions natives du smartphone

Ce point est bien sûr très important, à quoi bon si vous ne pouvez pas prendre des photos, enregistrer des vidéos et sons, vous localiser avec le GPS, connaitre l’orientation de l’écran, chatter en vidéoconférence? La réalité virtuelle est aussi disponible quoique encore expérimentale. Donc en résumé voici ce que permet de faire une en 2020 une progressive Web App.

  • géolocalisation GPS
  • Caméra
  • Sensors
  • Payment Request pour les paiements
  • auto update

4/Add to Home screen

C’est pour avoir l’équivalen et de l’installation des application natives depuis le store des applications.

5/ Le fonctionnement hors ligne

C’est une des proposition de valeur majeure des PWA, grâce au Service Worker, votre application web va pouvoir fonctionner hors ligne, et dès que la connexion au web sera restaurée, les données peuvent être synchronisée (moyennant un code bien sûr).

6/Le fichier manifest.json

Un fichier manifest en général décrit le contexte ou le paramétrage de l’application. La première fois que j’ai vu ce concept c’est dans les applications mobiles Android, où il y a un fichier manifest, sur IOS il porte un autre nom info.plist.

Maintenant que vous avez une idée plus claire commençons à développer un PWA ! Le plus didactique est de convertir un site web traditionnel en PWA, plutôt que de faire un PWA de zéro.

node JS

Générer un projet Javascript avec NPM

Imaginez que vous ayez un projet front end, par exemple personnalisation d’un thème d’une boutique Magento, cela ne concerne que le CSS et HTML (voire du javascript), les fichiers sont gros, pouvant faire dix milles lignes en CSS, hors de question de le faire directement en CSS, il y a beaucoup mieux le Sass. Le Sass est un « langage » qui va se compiler en CSS, l’avantage est qu’il est facilement  compréhensible, car sa syntaxe est structurée.

/* Sass */
div > p {
  color:blue;
  a {
    color : red;
  }
}

/* converti en CSS */

div > p {
  color: blue;
}
div > p a {
  color: red;
}

L’exemple ci-dessus illustre la lisibilité de la notation en Sass, hiérachisée mais pas forcément plus concise, en revanche très lisible, la syntaxe Sass est beaucoup plus riche et plus puissante que ne le montre l’exemple ci-dessus. En comparaison, la notation CSS est plus plate et répétitive, et bien sûr moins lisible.

NPM va nous permettre d’installer les dépendances, et dans le cas du Sass, on va installer node-sass pour compiler le Sass en CSS à chaque fois qu’on enregistre le fichier Sass (extension .scss).

Initialisation d’un projet NPM

npm init

Après cette commande vous devez répondre à un tas de questions comme le nom du projet, le propriétaire, la licence, pas mal de champs sont optionnels rassurez-vous etc.

Un fichier package.json est généré.

Ensuite installons le paquet node-sass. Ce dernier permet de surveiller les modifications d’un fichier Sass et de compiler en CSS automatiquement.

$ npm install -D node-sass nodemon
#le D signifie une dev dependency

Dans votre package.json, ajoutez ces lignes

“scripts”: {
  “build-css”: “node-sass --include-path scss scss/main.scss   public/css/main.css”
}

#Pour lancer la compilation
$ npm run build-css

Mieux encore watcher pour automatiquement compiler au moindre changement puis sauvegarde du fichier sass.

“scripts”: {
 “build-css”: “node-sass --include-path scss scss/main.scss public/css/main.css”,
 “watch-css”: “nodemon -e scss -x \”npm run build-css\””
},

lien : https://medium.com/@brianhan/watch-compile-your-sass-with-npm-9ba2b878415b

javascript

Sélectionner des éléments HTML en Javascript pur

Sur ce blog, quand je parle de Javascript, je parle de Javascript pur, et non de JQuery, cette extension étant trop célèbre, sur les forums les gens ont même tendance à proposer une solution en JQuery alors que c’est en Javascript pur (Vanilla Javascript) que la question était posée.

Sélectionner des tags HTML en Vanilla Javascript

Supposons que vous avez une page HTML, vous agrémentez d’un script Javascript en fin de page, on va utiliser la méthode querySelectorAll, qui est une fonction très importante, car elle permet de sélectionner des tags HTML selon divers critères. Par exemple, si on veut les liens hypertextes présents sur la page courante :

var links = querySelectorAll("a")

Pour comprendre comme ça marche, le sélecteur est « a » comme ancre, c’est comme en CSS, si je veux que des div, je mets « div », si je veux les div et ancres :

var elem = document.querySelectorAll("a","div")

Maintenant on va faire un peu plus compliqué :). Supposons que nous voulions seulement les liens nofollow, sur une page HTML un lien nofollow est spécifié avec l’attribut « rel » :

<a href="https://www.google.fr" rel="nofollow" />Lien</a>

Pour sélectionner ce lien, on fera :

var links = document.querySelectorAll("a[rel=nofollow]")

querySelectorAll pour sélectionner dans un sous ensemble de HTML

Parfois on a besoin de faire une sélection sur un ensemble plus petit, parce que la page est complexe, on veut dégrossir le travail. On peut dans ce cas sélectionner un élément HTML d’ordre supérieur, et faire un querySelectorAll sur ce sous ensemble.

var contenu = document.querySelectorAll("div[id=main]")
var links = contenu.querySelectorAll("a")

Ceci est rendu possible par le mécanisme d’héritage de type prototypal (pas un héritage classique au sens classe).

querySelector pour ne sélectionner que le premier

Il peut arrive qu’on n’a besoin que d’un élément (quand on est sûr), et cela pour éviter d’avoir à itérer sur un tableau, on utiliser alors QuerySelector, qui nous retourne alors un seul élément. Dans le jargon, on parle d’un node retourné, là où querySelectorAll retourne un nodeList.

javascript

Comment créer un bookmarklet?

Créer le bookmarklet le plus simple du monde en 10 secondes

<a href="javascript: alert('Un bookmarklet !');">Fav moi</a>

Cela va créer lien Fav moi, que vous allez glisser déposer sur la barre des favoris.

En fait ce n’est rien de plus qu’une ligne de javascript que vous auriez fait de façon classique, sauf que c’est mis dans un lien, et que vous avez mis en favori ce lien, astucieux comme concept non?

Pour c’est super intéressant de savoir faire un bookmarklet? C’est plus simple que de faire faire un addon pour Firefox ou Chrome, par exemple, et c’est presque croos browser de nos jours aux différences d’implémentation de Javascript près.

Parce que ça augmente les fonctionnalité du browser, donc de faire des trucs super intéressant sur les pages web, comme par exemple surligner les liens hypertexte, ou remplacer le logo de Google par celui de Bing ! et vice versa.

Pour les SEO cela peut être intéressant, faites travailler votre imagination.

Les différents degrés de sophistication de conception des bookmarklet

Nous avons vu que la première et plus simple manière de faire un bookmarklet est de mettre directement le Javascript dans un lien hypertexte. Ok c’est cool mais si le code Javascript est plus conséquent?

Un bookmarklet est un code qui va s’exécuter sur la page courante. Vous pouvez définir une fonction anonyme dans la section script et l’appeler dans le lien hypertexte.

  1. Le javascript dans le lien directement (voir ci-dessus)
  2. Le javascript dans une fonction anonyme quand le code est plus conséquent
  3. Le javascript dans un fichier externe (on fait une inclusion avec <link>)
  4. Plus badass, incluez AngularJS ou VueJS ou toute autre librairie
javascript:(function(){// code javascript })();

Voici un exemple de bookmarklet que j’ai fait pour remplir le champ « Legende », »Alt » et « Description » dans l’interface d’ajout d’image.

<a href="javascript:(function(){var t=document.querySelectorAll('div.media-sidebar label input');var a=t[2];var u=document.querySelectorAll('div.media-sidebar textarea');var b=u[0];var v=document.querySelectorAll('div.media-sidebar label input');var c=u[1];b.innerHTML=c.innerHTML=a.value;this.stop;})()">copy</a>

Inclure une feuille de Javascript externe quand vraiment le code est trop volumineux. Dans ce cas il vous placer le script dans une url accessible sur le web.

javascript: (function () { 
   var jsCode = document.createElement('script'); 
   jsCode.setAttribute('src', 'http://domaine.com/file.js');                  
 document.body.appendChild(jsCode); 
}());

Souvenez vous que votre bookmarklet ne doit pas avoir de collission avec le JS de la page sur laquelle elle sera utilisée. Dans l’exemple ci-dessus c’est une fonction à invocation immédiate qui est utilisée, évitant justement la collision de variable.

Si vous chargez un script et que vous voulez être sûr  qu’il soit chargé, voici un tuto sur un site https://idiallo.com/javascript/async-jquery

Element de langage en javascript utile pour les bookmarklets

Les bookmarklets font beaucoup de traversing de DOM ou de sélection de DOM, vous devez en général le faire en Javascript pure voici quelques commandes pour vous simplifier le travail

querySelectorAll

Cette fonction est très utilisée pour matcher des éléments du DOM, elle va vous retourner un objet de type NodeList. NodeList n’est pas un tableau, vous ne pouvez pas le traverser avec une boucle for traditionnelle, ni map(), filter() ou slice(), il faut le convertir en tableau avant.

#sélection des liens 
var a=document.querySelectorAll('a') // NodeList
#sélection des div avec la classe 'primary'
var a = document.querySelectorAll('div.primary')

Convertir un NodeList en tableau

# Array.from()
var array = Array.from(a)

#spread operator
var array = [...a] // rendu possible car a est iterable
Retour en haut