Ответы пользователя по тегу 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 - (a[i + 1]?.sick ?? 0),
    }));

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

    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 sortedArr = arr
      .map(n => [ n, n[0].replace(/\D+/, '') ])
      .sort((a, b) => a[1].localeCompare(b[1]))
      .map(n => n[0]);
    Ответ написан
    Комментировать
  • Как добавить или отнять 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
    arr.map((n, i) => n * matrix.reduce((acc, row) => acc + row[i], 0))
    Ответ написан
    Комментировать
  • Как вывести результат "на лету"?

    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 >'
    Ответ написан
    Комментировать
  • Почему в корзине считается только последний 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 colors = [
      [ 'En',   'red' ],
      [ 'Ru', 'green' ],
      [ 'De',  'blue' ],
    ];
    
    document.querySelectorAll('.some-link').forEach(n => {
      n.style.color = colors.find(m => n.innerText.includes(m[0]))?.[1];
    });
    Ответ написан
    Комментировать
  • Как записать рекурсию (функц. глубокого копирования) в виде цикла?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Используйте стек.

    Если, обрабатывая данные, натыкаетесь на объект, надо сохранить в стек текущее состояние - ссылку на копируемые данные, индекс текущего элемента, ссылку на объект, куда копируете; затем установить новое состояние - копируемыми данными будет массив пар ключ-значение встреченного объекта, индекс обнуляется (на самом деле надо выставить -1, нулевое значение будет получено при переходе к следующей итерации; конечно, можно и буквально 0 выставлять, но тогда придётся усложнить работу с индексом - тут увеличиваем, а тут нет), пустой объект в качестве копии.

    Если данные закончились, надо восстановить состояние из стека.

    Условий, при которых возможно продолжение цикла, будет два - кроме наличия необработанных данных ещё и непустой стек.

    function clone(value) {
      const clone = {};
      const stack = [];
    
      for (
        let i = 0, source = [ [ '', value ] ], target = clone;
        i < source.length || stack.length;
        i++
      ) {
        if (i === source.length) {
          [ i, source, target ] = stack.pop();
        } else {
          const [ k, v ] = source[i];
          const isObject = v instanceof Object;
    
          target[k] = isObject ? v.constructor() : v;
    
          if (isObject) {
            stack.push([ i, source, target ]);
            [ i, source, target ] = [ -1, Object.entries(v), target[k] ];
          }
        }
      }
    
      return clone[''];
    }

    как правильнее всего будет это сделать?

    Перестать заниматься ерундой и начать использовать готовые решения. Например.
    Ответ написан
    Комментировать
  • Как написать этот код легче?

    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));
    objects.push(...strings.filter(n => !names.has(n)).map(n => ({ name: n })));
    Ответ написан
    Комментировать