Ответы пользователя по тегу JavaScript
  • Как показать определённое количество блоков по клику?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const SHOW_ON_LOAD = 3;
    const SHOW_MORE = 2;
    
    const items = [...document.querySelectorAll('.box-list__item')];
    const button = document.querySelector('.show-more');
    
    showItems(SHOW_ON_LOAD);
    button.addEventListener('click', () => showItems(SHOW_MORE));
    
    function showItems(count) {
      items.splice(0, count).forEach(n => n.classList.add('ui-box-active'));
      button.classList.toggle('ui-button-hidden', !items.length);
    }
    Ответ написан
    1 комментарий
  • Когда применять arr.reduce?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Когда сочтёте нужным. Типа, подумали, и решили - здесь reduce нужен. Или не нужен. Да, подумали. Для этого у вас есть особый инструмент - голова называется.
    Ответ написан
    Комментировать
  • Как сделать кастомный выпадающий список?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Вместо назначения индивидуальных обработчиков клика элементам списка (которых в момент назначения ещё нет, openItems оказывается пуст, так что обработчики никому не назначаются) сделайте один делегированный, надо

    openItems.forEach(function (formItem) {
      formItem.addEventListener('click', function () {
        openBtn.innerText = this.innerText;
        openList.classList.remove('open');
        hiddenInput.value = this.dataset.value;
      });
    });

    заменить на

    openList.addEventListener('click', function(e) {
      const item = e.target.closest('li.form-item');
      if (item) {
        openBtn.innerText = item.innerText;
        openList.classList.remove('open');
        hiddenInput.value = item.dataset.value;
      }
    });
    Ответ написан
    1 комментарий
  • Как получить последовательно разницу значений в массиве?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Собрать новый массив:

    const newData = data.map((n, i, a) => ({
      ...n,
      newSick: n.sick - (i < ~-a.length && a[-~i].sick),
    }));

    Добавить свойство элементам существующего массива:

    data.forEach((n, i, a) => n.newSick = n.sick - (a[i + 1]?.sick ?? 0));
    // или
    data.reduceRight((prev, n) => (n.newSick = n.sick - prev, n.sick), 0);
    Ответ написан
    Комментировать
  • Как отсортировать массив пар [ключ, значение]?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const sorted = (arr, key) => arr
      .map(n => [ key(n), n ])
      .sort(([a], [b]) => a < b ? -1 : +(a > b))
      .map(n => n[1]);

    Так как сортировка сбивается из-за наличия нечисловых символов в начале некоторых строк, просто вырежем их:

    const sortedArr = sorted(arr, n => n[0].replace(/^\D+/, ''));

    Если же значения могут быть не только двухзначными, то сравнивать их как строки уже нельзя. Делаем из них настоящие числа, считаем сумму; если второе слагаемое отсутствует, используем первое повторно:

    const sortedArr = sorted(arr, n => {
      const d = n[0].match(/\d+/g);
      return +d[0] + +d.at(-1);
    });
    Ответ написан
    Комментировать
  • Как добавить или отнять 1 по клику на кнопки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    let count = 0;
    const countEl = document.querySelector('.text');
    const buttons = [...document.querySelectorAll('.click')];
    const onClick = e => updateCount(e.target.classList.toggle('clicked') ? 1 : -1);
    const updateCount = change => countEl.innerText = count += change;
    buttons.forEach(n => n.addEventListener('click', onClick));
    updateCount(buttons.reduce((acc, n) => acc + n.classList.contains('clicked'), 0));
    Ответ написан
    1 комментарий
  • Как найти произведения элементов массива и сумм столбцов матрицы?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const result = arr.map((n, i) => n * matrix.reduce((acc, row) => acc + row[i], 0));

    или

    const result = Array(arr.length).fill(0);
    
    for (const row of matrix) {
      for (const [ i, n ] of row.entries()) {
        result[i] += n * arr[i];
      }
    }
    Ответ написан
    Комментировать
  • Как вывести результат "на лету"?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Вместо click'а у кнопки обрабатывайте input у формы:

    - document.querySelector('.calculate').addEventListener('click', function () {
    + document.querySelector('form').addEventListener('input', function () {
    Ответ написан
    6 комментариев
  • Как, имея строку с ключами, получить массив значений из вложенных объектов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const result = Array
      .from(letter, n => soundParts[Number.isNaN(+n) ? 'letter' : 'number'][n])
      .filter(Boolean);

    или

    const result = Object
      .entries(Object.assign({}, ...Object.values(soundParts)))
      .reduce((acc, n) => (letter.includes(n[0]) && acc.push(n[1]), acc), []);
    Ответ написан
  • Как получить подстроку в данном случае?

    0xD34F
    @0xD34F Куратор тега JavaScript
    str.match(/\]\s*(.+?)\s*#/)?.[1] ?? '< unknown >'
    Ответ написан
    Комментировать
  • Как сгруппировать расположенные последовательно элементы массива с одинаковыми значениями одного из свойств?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const groupAdjacent = (arr, newGroup) =>
      arr.reduce((acc, n, i, a) => (
        (!i || newGroup(n, a[~-i])) && acc.push([]),
        acc.at(-1).push(n),
        acc
      ), []);
    
    
    const result = groupAdjacent(arr, (c, p) => c.name !== p.name);
    Ответ написан
  • Почему в корзине считается только последний discount?

    0xD34F
    @0xD34F Куратор тега JavaScript
    for (let i in goods) {
      if (discounts.length === 0) {
        count = goods[i].value * goods[i].amount;
      }
      for (let j in discounts) {
        if (goods[i].name === discounts[j].name) {
          count =
            (goods[i].value - goods[i].value * discounts[j].discount) *
            goods[i].amount;
        } else {
          count = goods[i].value * goods[i].amount;
        }
      }
      sum += count;
      console.log(count, goods[i].name);
    }

    Зачем на каждой итерации цикла, ищущего скидку, пересчитывать цену? Предположим, нашли скидку для текущего товара, что дальше? Дальше, на следующей итерации, цена будет рассчитана заново, но уже без скидки - ведь объект скидки будет другим, будет соответствовать другому товару. Исключение - если скидка найдена на последней итерации.

    Правильно будет вычислять до цикла сумму без скидки, искать в цикле скидку, если нашли - пересчитывать со скидкой, прерывать цикл:

    for (const n of goods) {
      let s = n.value * n.amount;
      for (const m of discounts) {
        if (n.name === m.name) {
          s *= 1 - m.discount;
          break;
        }
      }
      sum += s;
    }

    Возможно есть лучший способ для решения такой задачи.

    function totalCost(goods, discounts) {
      discounts = Object.fromEntries(discounts.map(n => [ n.name, 1 - parseFloat(n.discount) / 100 ]));
      return goods.reduce((acc, n) => acc + n.value * n.amount * (discounts[n.name] ?? 1), 0);
    }
    Ответ написан
    3 комментария
  • Как узнать индекс гласных в слове?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Array.from(word.matchAll(/[aeiouy]/gi), n => n.index)

    или

    [...word.toLowerCase()].reduce((acc, n, i) => ('aeiouy'.includes(n) && acc.push(i), acc), [])

    или

    Object.entries(word).filter(n => 'AaEeIiOoUuYy'.indexOf(n[1]) !== -1).map(n => +n[0])


    Что до говнокода из вопроса...

    let letters = 'АаЕеIiOoUuYy'  //Создал переменную со строкой с гласными

    Почему символы из разных алфавитов? - первые четыре кириллические.

    if (arg1[i] == letters[j]) {  //Если элемент слова равен элементу строки с согласными
      newArr.push(arg1[i].indexOf())  //То пушу в массив индексы гласных этого слова
    }

    Какой ещё на хрен indexOf (кстати, вы не знаете, что он делает, откройте документацию и разберитесь)? Вот же бред. Что является индексом проверяемого символа? Строчкой выше ещё помнили, а когда до push'а дело дошло, уже забыли? Просто .push(i).

    Не ошибка, но упомянуть косячок стоит - после найденного совпадения продолжать крутить внутренний цикл смысла нет. Гуглите, как прервать цикл.
    Ответ написан
    Комментировать
  • Как изменить цвет ссылки при наличии в ней определённого текста?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Кого будем перекрашивать, и в какие цвета:

    const className = 'some-link';
    const colors = {
      En:   'red',
      Ru: 'green',
      De:  'blue',
    };

    Перекрашиваем текст в случае точного совпадения:

    for (const n of document.getElementsByClassName(className)) {
      n.style.color = colors[n.textContent];
    }

    Или, смотрим наличие подстроки, регистр не важен:

    document.querySelectorAll(`.${className}`).forEach(function(n) {
      n.style.color = this.find(m => m[0].test(n.innerText))?.[1];
    }, Object.entries(colors).map(n => [ RegExp(n[0], 'i'), n[1] ]));

    Можно и без регулярных выражений:

    - RegExp(n[0], 'i')
    + n[0].toLowerCase()

    - m[0].test(n.innerText)
    + n.innerText.toLowerCase().includes(m[0])
    Ответ написан
    Комментировать
  • Как написать этот код легче?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const newData = data.reduce((acc, n) => {
      const k = Object.keys(n)[0];
      (acc.result[acc.keys[k] = (acc.keys[k] ?? -1) + 1] ??= []).push(n);
      return acc;
    }, { result: [], keys: {} }).result.flat();

    или

    const numKeys = new Set(data.flatMap(Object.keys)).size;
    const numObjs = data.length / numKeys;
    const newData = data.map((n, i, a) => a[(i % numKeys) * numObjs + (i / numKeys | 0)]);
    Ответ написан
    2 комментария
  • Если в диве больше 1го элемента то добавить класс к диву?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Кому надо добавить класс, какой класс, сколько вложенных элементов должно быть:

    const selector = 'селектор элементов';
    const className = 'класс';
    const minChildrenCount = 666;

    Добавляем:

    for (const n of document.querySelectorAll(selector)) {
      n.classList.toggle(className, n.children.length >= minChildrenCount);
    }
    
    // или (нет, так делать точно не надо - для 0 результат будет некорректным)
    
    document
      .querySelectorAll(`${selector} > :nth-child(${minChildrenCount})`)
      .forEach(n => n.parentNode.classList.add(className));
    Ответ написан
    Комментировать
  • Одномерный массив в многомерный?

    0xD34F
    @0xD34F Куратор тега JavaScript
    (function toArrays(obj) {
      const arr = Object.values(obj ?? {});
      arr.forEach(n => n.children = toArrays(n.children));
      return arr;
    })(arr.reduce((acc, n) => {
      const path = n.path.replace(/^\/|\/$/g, '').split('/');
      const obj = path.reduce((p, c) => ((p.children ??= {})[c] ??= {}), acc);
      Object.assign(obj, n);
      return acc;
    }, {}).children)
    Ответ написан
    2 комментария
  • Как переписать функцию со scrollIntoView?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Задать связь между кнопками и блоками с помощью data-атрибутов:

    <div class="mainMenu">
      <button data-scroll-to="calendar">Раз</button>
      <button data-scroll-to="rooms">Два</button>
      <button data-scroll-to="maps">Три</button>
      <button data-scroll-to="contact">Четыре</button>
    </div>
    ...
    <div data-block="calendar">...</div>
    <div data-block="rooms">...</div>
    <div data-block="maps">...</div>
    <div data-block="contact">...</div>

    Сделать функцию, которая получает значение атрибута, находит соответствующий блок и выполняет прокрутку:

    function scrollTo(block) {
      document.querySelector(`[data-block="${block}"]`).scrollIntoView({
        block: 'center',
        behavior: 'smooth',
      });
    }

    Воспользоваться этой функцией при обработке кликов по кнопкам:

    document.querySelector('.mainMenu').addEventListener('click', e => {
      const block = e.target.dataset.scrollTo;
      if (block) {
        scrollTo(block);
      }
    });
    
    // или
    
    document.querySelectorAll('[data-scroll-to]').forEach(function(n) {
      n.addEventListener('click', this);
    }, e => scrollTo(e.target.dataset.scrollTo));
    Ответ написан
    1 комментарий
  • Как сделать алгоритм добавления елементов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Значения в массиве строк уникальны? Если нет, сколько надо добавлять объектов?

    Сколько раз строка повторилась - столько новых объектов будет добавлено:

    const names = new Set(objects.map(n => n.name));
    strings.forEach(n => (names.has(n) || objects.push({ name: n })));

    Два раза одно и то же не добавляем:

    new Set(strings).forEach(function(n) {
      if (!this.has(n)) {
        objects.push({ name: n });
      }
    }, new Set(objects.map(n => n.name)));
    
    // или
    
    for (const name of strings) {
      if (objects.every(n => n.name !== name)) {
        objects[objects.length] = { name };
      }
    }
    
    // или
    
    objects.splice(0, objects.length, ...strings.reduce(
      (acc, n) => acc.set(n, acc.get(n) ?? { name: n }),
      new Map(objects.map(n => [ n.name, n ]))
    ).values());
    Ответ написан
    Комментировать