За межами Console.log, Епізод III: спеціальні форматери в Devtools

Ця стаття є частиною серії статей про консоль Chrome;
Раніше в «Beyond console.log»
Вам набридло бачити, що ваші об’єкти постійно реєструються однаково на консолі? Вам подобаються інструменти розробника Chrome, але вам потрібні назви екземплярів Eleve відображається червоним, оранжевим або зеленим, залежно від його значення? Залишайтеся на цій сторінці, вам не потрібно йти далі.

Обов’язкова умова: увімкнути спеціальні форматувальники

У DevTools перейдіть до налаштувань, а потім поставте прапорець «увімкнути спеціальні форматери» в розділі «Консоль».

Що таке спеціальні форматери?

Les Спеціальні форматери є масивом об’єктів, що зберігаються в object window. Вони дозволяють нам налаштувати відображення певного об’єкта за своїм бажанням. Таким чином, вони можуть значно покращити читабельність наших журналів. Або краще: змусити очі наших колег кровоточити (див. нижче).
знімок екрана, коли ми реєструємо() об’єкт із користувацькими форматами: тут букви горять!
Незважаючи на їхню корисність, я не відчуваю, що це широко відома тема, в мережі є дуже невелика кількість статей на цю тему, всі англійською. Без зайвих розмов, давайте виправимо цю несправедливість, забруднивши руки.

Мета

  • По-перше, ми забезпечимо, щоб екземпляри нашого майбутнього класу Студента відображали своє ім’я у форматі ім’я + ІМ’Я, а цей має бути забарвлений від червоного до зеленого відповідно до середнього значення його оцінок.
  • Тоді ми подбаємо про легко підтримуваний код

давайте кодувати

Спочатку закодуємо клас Student:

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;
    }
}

… Тоді давайте оголосимо наш формататор і додамо його до масиву:

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 ];

Тепер ми можемо зареєструвати масив студентів:

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]);

знімок екрана інструментів розробника під час реєстрації об'єкта за допомогою спеціальних форматів

Короткий аналіз коду

схвильований мох
Ого, це магія, імена студентів пишуться великими літерами і розфарбовуються відповідно до середнього! Як я міг жити без цього так далеко? Моє життя програміста змінилося назавжди!
Кожен об’єкт у масиві користувацького форматування повинен мати три методи: заголовок, який повинен відображати об'єкт JSONML, який буде використовуватися для відображення імені об'єкта, коли його згорнуто, має тіло, що вказує, чи є об’єкт розгортаним і нарешті тіло який повинен відображати шаблон HTML розгорнутого тіла об’єкта у форматі JSONML. Однак єдиними дозволеними елементами HTML є таблиця, тр, ц, ол, лі, див et span
Ось я перевіряю чи x є прикладом Student з instanceof. Зауважте, що це повернеться true для будь-якого підкласу Student. Якби ми хотіли ввімкнути форматувальник, лише якщо об’єкт є точно екземпляром Student, ми могли б написати:
if (x.constructor === Student)

Йти далі

Все це насправді непогано. Але у великому проекті я не бачу, щоб люди додали щойно створений клас до масиву window.devtoolsFormatters вручну. Було б краще, якби Student's CustomFormatter було визначено в самому класі. Але це було б недоліком: це б забруднювало наших студентів, могло б викликати зіткнення. З огляду на такі проблеми ми скористаємося перевагами символів:

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"]

тренажери
Ну, на сьогодні все. До нових пригод із Chromes Dev Tools!