Jenseits von Console.log, Episode III: Benutzerdefinierte Formatierer in Devtools

Dieser Artikel ist Teil einer Reihe von Artikeln zur Chrome Console.
Bisher bei „Beyond console.log“
Sind Sie es leid, dass Ihre Objekte in der Konsole immer auf die gleiche Weise protokolliert werden? Ihnen gefallen die Chrome Dev Tools, aber Sie möchten den Namen der Instanzen von Eleve wird je nach Wert rot, orange oder grün angezeigt? Bleiben Sie auf dieser Seite, Sie müssen nicht weiter gehen.

Voraussetzung: Benutzerdefinierte Formatierer aktivieren

Gehen Sie in DevTools zu den Einstellungen und aktivieren Sie das Kontrollkästchen „Benutzerdefinierte Formatierer aktivieren“ im Abschnitt „Konsole“.

Was sind benutzerdefinierte Formatierer?

Die angebotene Benutzerdefinierte Formatierer sind ein Array von Objekten, die in Objekt gespeichert sind window. Sie ermöglichen es uns, die Anzeige eines bestimmten Objekts nach unseren Wünschen anzupassen. Daher können sie die Lesbarkeit unserer Protokolle erheblich verbessern. Oder besser : unseren Kollegen Tränen in die Augen treiben (siehe unten).
Screenshot, wenn wir ein Objekt mit den benutzerdefinierten Formatierern loggen: Hier erscheinen die Buchstaben in Flammen!
Trotz ihrer Nützlichkeit habe ich nicht das Gefühl, dass dies ein weithin bekanntes Thema ist, es gibt eine sehr kleine Anzahl von Artikeln zu diesem Thema im Internet, alle auf Englisch. Lassen Sie uns diese Ungerechtigkeit kurzerhand beheben, indem wir uns die Hände schmutzig machen.

Ziel

  • Zunächst werden wir dafür sorgen, dass die Instanzen unserer zukünftigen Student-Klasse ihren Namen im Format Vorname + NAME anzeigen, und diese muss entsprechend dem Durchschnitt ihrer Noten rot bis grün eingefärbt werden.
  • Dann stellen wir sicher, dass wir einen leicht wartbaren Code haben

Lass uns codieren

Lassen Sie uns zuerst die Student-Klasse codieren:

class Student {
    constructor(firstname, lastname, notations) {
        this.firstname = firstname;
        this.lastname = lastname;
        this.notations = notations;
    }
    getAverageNotation() {
        return this.notations.reduce((total, notation) => total += notation, 0) / this.notations.length;
    }
}

… Dann deklarieren wir unseren Formatierer und fügen ihn dem Array hinzu:

const studentFormatter = {
    header: (x) => {
        if (x instanceof Student) {
            const moyenne = x.getAverageNotation();
            const color = (moyenne > 15) ? 'limegreen' : (moyenne > 5) ? 'orangered' : 'firebrick';
            return [
                'span',
                {
                    style: 'color: ' + color
                },
                x.lastname.toUpperCase() + ' ' + x.firstname
            ];
        }
    },
    hasBody: x => x instanceof Student,
    body: (x) => {
        return [
            'table',
            {},
            ['tr', {},
                ['td', {style: 'color: burlywood'}, 'Prénom: '],
                ['td', {}, `${x.firstname}`],
            ],
            ['tr', {},
                ['td', {style: 'color: burlywood'}, 'Nom: '],
                ['td', {}, `${x.lastname}`],
            ],
            ['tr', {},
                ['td', {style: 'color: burlywood'}, 'Notes: '],
                ['object', {object: x.notes}],
            ],
        ];
    }
};
window.devtoolsFormatters = [ studentFormatter ];

Jetzt können wir eine Reihe von Schülern protokollieren:

const ducobu = new Student('Élève', 'Ducobu', [2, 5, 3]);
const willHunting = new Student('William', 'Hunt', [18, 20, 19]);
const nicolasLePetit = new Student('Nicolas', 'Le Petit', [10, 10, 10]);
console.info([ducobu, willHunting, nicolasLePetit]);

Screenshot von devtools beim Protokollieren eines Objekts mit benutzerdefinierten Formatierern

Kurze Codeanalyse

Moos aufgeregt
Wow, es ist magisch, die Namen der Schüler erscheinen in Großbuchstaben und es ist nach dem Durchschnitt gefärbt! Wie konnte ich bisher ohne leben? Mein Leben als Programmierer hat sich für immer verändert!
Jedes Objekt im benutzerdefinierten Formatierer-Array muss drei Methoden haben: Kopfzeile, das ein JSONML-Objekt rendern muss, das verwendet wird, um den Namen des Objekts anzuzeigen, wenn es reduziert ist, hatBody, die angibt, ob das Objekt entfaltbar ist und schließlich Körper die die HTML-Vorlage des entfalteten Hauptteils des Objekts im JSONML-Format rendern muss. Die einzigen zulässigen HTML-Elemente sind jedoch Tabelle, tr, ts, ol, li, div et Spannweite
Hier überprüfe ich, ob x ist eine Instanz von Student mit instanceof. Beachten Sie, dass dies zurückkehrt true für jede Unterklasse von Student. Wenn wir den Formatierer nur aktivieren wollten, wenn das Objekt genau eine Instanz von ist Student, hätten wir schreiben können:
if (x.constructor === Student)

Weiter gehen

Das ist alles wirklich nicht schlimm. Aber in einem großen Projekt sehe ich keine Leute, die die Klasse, die sie gerade erstellt haben, manuell zum Array window.devtoolsFormatters hinzufügen. Es wäre besser, wenn der CustomFormatter von Student in der Klasse selbst definiert wäre. Aber das hätte einen Nachteil: Es würde unsere Schüler verschmutzen, es könnte zu Kollisionen kommen. Mit dieser Art von Problemen im Hinterkopf werden wir die Vorteile von Symbolen nutzen:

const CustomFormatterToken = Symbol('CustomFormatter');
// en ajoutant cette propriété à Symbol, ça permet à notre
// fonctionnalité d'être accessible partout :
Symbol.customFormatter = CustomFormatterToken;
// Voici la nouvelle version de la classe Eleve :
class Student {
    constructor(firstname, lastname, notations) {
        this.firstname = firstname;
        this.lastname = lastname;
        this.notations = notations;
    }
    get [CustomFormatterToken]() {
        return {
            header: () => {
                const averageNotation = this.getAverageNotation();
                const color = (moyenne > 15) ? 'limegreen' : (moyenne > 5) ? 'orangered' : 'firebrick';
                return [
                    'span',
                    {
                        style: 'color: '+ color + '}'
                    },
                    this.lastname.toUpperCase() + 'this.firstname'
                ];
            },
            hasBody: () => true,
            body: () => [
                'table',
                {},
                ['tr', {},
                    ['td', {style: 'color: burlywood'}, 'prenom: '],
                    ['td', {}, `${this.firstname}`],
                ],
                ['tr', {},
                    ['td', {style: 'color: burlywood'}, 'nom: '],
                    ['td', {}, `${this.lastname}`],
                ],
                ['tr', {},
                    ['td', {style: 'color: burlywood'}, 'notes: '],
                    ['object', {object: this.notations}],
                ],
            ]
        };
    }
    getAverageNotation() {
        return this.notations.reduce((total, notation) => total += notation, 0) / this.notations.length;
    }
}
// Dorénavant, devtoolsFormatters n'aura qu'une seule valeur : AllPurposeFormatter
const AllPurposeFormatter = {
    header: x => {
        const formatter = x[Symbol.customFormatter];
        if (formatter) {
            return formatter.header();
        }
    },
    hasBody: x => {
        const formatter = x[Symbol.customFormatter];
        if (formatter) {
            return formatter.hasBody();
        }
    },
    body: x => {
        const formatter = x[Symbol.customFormatter];
        if (formatter) {
            return formatter.body();
        }
    },
};
window.devtoolsFormatters = [ AllPurposeFormatter ];
const ducobu = new Student('Élève', 'Ducobu', [2, 5, 3]);
const willHunting = new Student('William', 'Hunt', [18, 20, 19]);
const nicolasLePetit = new Student('Nicolas', 'Le Petit', [10, 10, 10]);
console.info([ducobu, willHunting, nicolasLePetit]);
// les propriétés qui ont pour clé un symbole n'apparaissent pas...
// Notre objet n'est pas pollué \o/
console.log(Object.keys(ducobu)); // => ["firstname", "lastname", "notations"]

Sportschuhe
Nun, das ist alles für heute. Bis bald für neue Abenteuer mit Chromes Dev Tools!