Pas l'temps d'niaiser

Aujourd'hui au programme: ECMAScript 2022. Pas de baratin, pas de blabla, du code, des snippets, des exemples. Comme le disait justement Yogi Berra, "on peut observer beaucoup en regardant".
Pour rappel, ECMAScript, ce sont des gens à la santé mentale branlante qui se retrouvent dans des caves pour décider des nouvelles fonctionnalités à ajouter au langage JavaScript.
Cet article présente les fonctionnalités à venir dans la nouvelle version d'ECMAScript, de son petit nom ES2022.
niaiser

Attendre au plus haut niveau

Sous ce terme tout droit sorti des services marketing les plus cokés se cache simplement la possibilité de pouvoir utiliser le mot clé await directement dans un fichier au niveau le plus haut, en dehors d'une fonction asynchrone.
Auparavent pour exécuter des fonctions asycnrhones au top niveau d'un fichier on devait faire quelque chose comme ça:
(async () => {
    await etape1();
    await etape2();
})();
Avec ES2022, on pourra faire ceci:
await etape1();
await etape2();

La rentrée des classes

Pour ceux qui vivent dans une grotte: oui, on peut faire de l'objet en JS, enfin à peu près. On peut créer des classes, les instancier, c'est chouette. Dans ES2022 plusieurs fonctionnalités viennent améliorer la gestion des classes:
  • La déclaration d'attributs de classe
  • Les propriétés privées et leur opérateur in
  • Les getters / setters
  • Les propriétés statiques et le bloc d'exécution dédié
Voici un condensé de ces nouveautés regroupées dans un gros snippet des familles:
class YogiBerra {
    // on peut définir des attributs ici
    metier = 'Entraineur';
    // cet attribut est privé (grâce au symbole # devant)
    #sport;
    // on peut lui mettre un getter et un setter
    get sport() {
        return this.#sport ?? 'Pas de sport';
    }
    set sport(value) {
        this.#sport = value;
    }
    // on peut tester qu'un attribut privé existe avec l'opérateur in
    static possedeAttributSport(objet) {
        return #sport in objet;
    }
    // ces attributs sont statiques
    static equipe = 'Yankees';
    static ville;
    // cette méthode aussi est statique
    static aphorisme() {
        return 'Allez toujours aux funérailles de vos amis ou ils ne viendront pas aux vôtres';
    }
    // ce bloc statique s'exécute au moment où la classe est définie
    static {
        try {
            this.ville = recupererVille(this.equipe);
        } catch {
            this.ville = 'Inconnue';
        }
    }
}

// créons une instance de Yogi Berra
const yogi = new YogiBerra();
// même si son attribut age est privé on peut y accéder car il y a un getter
console.log(yogi.sport); // 'Pas de sport'
yogi.sport = 'Baseball';
console.log(yogi.sport); // 'Baseball'
// appelons maintenant une méthode statique
console.log(YogiBerra.aphorisme()); // 'Allez toujours aux [...]'

En quête d'indices

On peut maintenant récupérer des indices (ou index) nous indiquant où une expression régulière a été détectée dans une chaîne de caractère. Pour ce faire il faut utiliser le flag /d.
// notez l'utilisation du flag /d
const regex = /vous/d;
const aphorisme = 'Quand vous arrivez à un embranchement, prenez-le';
const match = regex.exec(aphorisme);
console.log(match.indices); // [[6, 10]]

Where you at

Une nouvelle fonction d'Array nous permet de récupérer des éléments d'un tableau à partir de leur index et supporte les index négatifs (partant ainsi de la fin du tableau).
const equipes = ['Yankees', 'Red Sox', 'Mariners', 'Rangers'];
console.log(equipes.at(0)); // Yankees
console.log(equipes.at(1)); // Red Sox
console.log(equipes.at(-1)); // Rangers
console.log(equipes.at(-2)); // Mariners
// pour rappel, avant on devait faire comme ça
console.log(equipes[equipes.length - 2]); // Mariners

Mon petit préféré

Vous allez apprécier cette nouveauté si comme moi vos codes JS sont plein de trucs comme ça:
// je veux juste tester si une clé existe dans un objet bordel laissez-moi tranquille
if (Object.prototype.hasOwnProperty.call(monObjet, 'uneCle')) {
    //
}
Maintenant on peut utiliser la méthode Object.hasOwn qui est quand même un peu plus lisible:
// merci bien
if (Object.hasOwn(monObjet, 'uneCle')) {
    //
}

Just cause

Il est désormais possible de fournir une cause d'erreur lorsqu'on jette une exception dans le code.
// petite tâche asynchrone des familles
const faireUnTruc = async () => {
    try {
        await fetch('https://url.qui.existe.pas/du/tout');
    } catch (err) {
        // on throw notre propre erreur en mettant l'erreur catchée en cause
        throw new Error('Ah bah mince ça marche pas', {
            cause: err,
        });
    }
};

// on lance la tâche
try {
    await faireUnTruc();
} catch (err) {
    // on récupère l'erreur qu'on a throw nous même
    console.log(err.message); // Ah bah mince ça marche pas
    // et on récupère l'erreur cause (pratique pour débugger)
    console.log(err.cause.message); // NetworkError when attempting to fetch resource
}

Bonus track

En bonus, deux fonctionnalités sympathiques qui ne sont cependant pas encore intégrées à ES2022. Elles sont toutes deux au stage 3, c'est à dire proches de la validation.
D'abord, la classe Temporal, qui remplacera la classe toute éclatée Date qui fait rager moult développeuses et développeurs JS (vous-mêmes vous savez).
const uneDate = Temporal.Date.from('2000-01-01');
const uneHoraire = Temporal.Time.from('12:00:00');
const uneTimezone = new Temporal.TimeZone('Europe/Paris');

// toutes ces options c'est beau
const cestNoel = Temporal.ZonedDateTime.from({
    timeZone: 'Europe/Paris',
    year: 2021,
    month: 12, // des mois qui vont de 1 à 12, je chiale putain
    day: 25,
    hour: 23,
    minute: 59,
    second: 59,
    millisecond: 0,
    microsecond: 4,
    nanosecond: 500,
});
console.log(cestNoel); // 2021-12-25T23:59:59.0000045+01:00[Europe/Paris]

// vous êtes pas prêts pour ça
const datePleine = Temporal.PlainDate.from({
    year: 2020,
    month: 6,
    day: 7,
});
console.log(datePleine); // 2020-06-07

// dayjs en sueur
const duration = Temporal.Duration.from({
    hours: 130,
    minutes: 20,
});
const seconds = duration.total({ unit: 'second' });
console.log(seconds); // 469200

// jpp c'est trop
const calendar = Temporal.Calendar.from('iso8601');
const date = calendar.dateFromFields(
    {
        year: 1999,
        month: 12,
        day: 31,
    },
    {}
);
console.log(date.monthsInYear); // 12
console.log(date.daysInYear); // 365
Enfin, on termine tranquille avec, toujours en stage 3, le support de l'import de fichiers JSON.
import mesDonnees from './donnees.json' assert { type: 'json' };

Liens utiles

fin