Вопрос №7617 от пользователя Константин Бочинин в уроке «Проект HTML Builder», курс «JS: Прототипы»

Константин Бочинин

Мне не хватило глубины погружения. Должен быть где-то рекурсивный процесс погружения и дальше подъем.

const typeOfTopTag = ([tag, inner, content]) => {
    if (Array.isArray(inner) || Array.isArray(content)) {
        return "wrapper";
    }
    if (typeof tag  === "string" && typeof inner === "string") {
        return "simple";
    }
    if (typeof tag  === "string" && typeof inner === "object" && typeof content === "string") {
        return "styled";
    }
};

const buildHtml = arr => {
  return arr.reduce((acc, node, i, [tag, inner, content]) => {
    if (typeOfTopTag(arr) === "simple") {
        return `<${tag}>${inner}</${tag}>`;
    }
    if (typeOfTopTag(arr) === "styled") {
        return `<${tag} class = "${inner.class}">${content}</${tag}>`;
    }
    if (typeOfTopTag(arr) === "wrapper" && Array.isArray(tag)) {
        return acc + buildHtml(node);
    }
    //**ТУТ ПРОВАЛИВАЮСЬ***
    if (typeof tag === "string") {
        return `<${tag}>` + '\n' + buildHtml(...inner) + '\n' + `</${tag}>`;
    }
  }, "");
};

На последнем if проваливаюсь html>meta>title и вылезти не могу. Как-то не так сделано :\ Вывод такой:

<html>
<meta>
<title>hello, hexlet!</title>
</meta>
</html>

В циклах был break (ну или что-то вроде) и дальше всплываешь на уровень выше, а тут как всплыть?

С вводом ниже все работает:

const Tag  = ['meta',      [    ['title', 'hello, hexlet!'], ]  ];
const Tag0 = ['h1', { class: 'header' }, 'html builder example'];
const Tag1 = ['title', 'hello, hexlet!'];
const Tag2 = [['title', 'hello, hexlet!'], ['title', 'hello, hexlet!']];
const Tag3 = [['title', 'hello, hexlet!'], ['title', 'hello, hexlet!'], ['title', 'hello, hexlet!']];
const Tag4 = ['div',[['span', 'span text2'], ['span', 'span text3'],]];
const Tag5 = ['h1', { class: 'header' }, 'html builder example'];
1 0

Александр О.

Давайте по порядку:

  1. [tag, inner, content] - правильно понимаю, что в разные моменты времени под одним и тем же именем могут находиться совершенно разные сущности? Ведь состав конкретного тега и позиции составляющих его частей не зафиксированы. Что такое inner? Почему вы ушли от терминологии предметной области: children, attributes, body? В целом именование в вашем коде резко ухудшает его читабельность.
  2. typeof tag === "string" - что такое tag и зачем нужна проверка его типа? Имя тега есть абсолютно в каждом теге, и оно всегда является строкой.
  3. class = "${inner.class}" - строку атрибутов надо формировать отдельно (выделить функцию для этого). Такое ручное формирование не пройдёт. Атрибуты - это объект, в котором может быть множество (более одного) атрибутов (причём разных видов: не только class, но и id и многих других).
  4. typeOfTopTag(arr) === "simple" - с помощью reduce вы делаете перебор элементов входного массива (они не являются нодами (node)), при этом внутри идёт проверка самого arr: если это условие является истинным, то оно будет истинным на каждом новом перебираемом элементе, ведь значение arr не меняется. Вообще, неясно, зачем это делать, похоже, вы некорректно используете функцию reduce.
  5. return<${tag}>${inner}</${tag}>; - в нескольких операторах return отсутствует аккумулятор acc, таким образом по логике работы функции reduce весь предыдущий накопленный результат теряется.
  6. <${tag}> + '\n' + buildHtml(...inner) + '\n' + </${tag}> - переносы строки не нужны, просто строчка html-кода
  7. Попробуйте определять не "тип тега", а "тип элемента тега" (тело, атрибуты, вложенный тег) и отталкиваться от этого.

Почитайте весь раздел (Вопросы и ответы) с комментариями, процитирую то, что уже неоднократно здесь писал: "Попробуйте для начала реализовать функцию для простого (и базового!) случая, когда на вход подаётся тег без вложенных в него других тегов. Т.е. этот тег может содержать attributes, body, но_без_children. Сделайте так, чтобы функция, приняв его, просто вернула строковое представление (как в html).

Сделав это, далее уже легче масштабироваться до обработки сложных тегов, имеющих children (другие теги). Делается это с помощью рекурсии."

1

Используйте Хекслет по максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»

Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Фронтенд-разработчик
Профессия
Разработка фронтенд-компонентов веб-приложений
7 июля 10 месяцев
Иконка программы Python-разработчик
Профессия
Разработка веб-приложений на Django
7 июля 10 месяцев
Иконка программы PHP-разработчик
Профессия
Разработка веб-приложений на Laravel
7 июля 10 месяцев
Иконка программы Node.js-разработчик
Профессия
Разработка бэкенд-компонентов веб-приложений
7 июля 10 месяцев
Иконка программы Fullstack-разработчик
Профессия
Новый
Разработка фронтенд и бэкенд компонентов веб-приложений
7 июля 16 месяцев
Иконка программы Верстальщик
Профессия
Вёрстка с использованием последних стандартов CSS
в любое время 5 месяцев
Иконка программы Java-разработчик
Профессия
Разработка приложений на языке Java
7 июля 10 месяцев
Иконка программы Разработчик на Ruby on Rails
Профессия
Создает веб-приложения со скоростью света
7 июля 5 месяцев