Задать вопрос
Ответы пользователя по тегу JavaScript
  • Мне нужно объединить два массива подкатегории вставить в категории.?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const result = [...subcategory.reduce(
      (acc, n) => (acc.get(n.category)?.children.push(n), acc),
      new Map(category.map(n => [ n.id, { ...n, children: [] } ]))
    ).values()];

    или

    const result = category.map(n => ({
      ...n,
      children: subcategory.filter(m => m.category === n.id),
    }));

    или

    const result = category.map(function(n) {
      return {
        ...n,
        children: this[n.id] ?? [],
      };
    }, subcategory.reduce((acc, n) => ((acc[n.category] ??= []).push(n), acc), {}));
    Ответ написан
    1 комментарий
  • Как передать data-attr только в один блок, куда наведен курсор?

    0xD34F
    @0xD34F Куратор тега JavaScript
    $('.item').on('mouseover', '.dot', function({ delegateTarget: t }) {
      $('.thumb-target', t).attr('src', $(this).data('img'));
      $('.dot', t).removeClass('select').filter(this).addClass('select');
    });

    или

    document.querySelectorAll('.item').forEach(n => {
      n.addEventListener('mouseover', onMouseOver);
    });
    
    function onMouseOver({ target: t, currentTarget: ct }) {
      const dot = t.closest('.dot');
      if (dot) {
        ct.querySelector('.thumb-target').src = dot.dataset.img;
        ct.querySelectorAll('.dot').forEach(n => {
          n.classList.toggle('select', n === dot);
        });
      }
    }
    Ответ написан
    Комментировать
  • Как из нескольких объектов сделать один, сложив значения свойств с одинаковыми именами?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Коротко:

    const sum = (...arr) => arr
      .flatMap(Object.entries)
      .reduce((acc, [ k, v ]) => (
        acc[k] = (acc[k] ?? 0) + v,
        acc
      ), {});

    Длинно:

    function sum() {
      const result = {};
    
      for (const n of arguments) {
        for (const k in n) {
          if (n.hasOwnProperty(k)) {
            if (!result.hasOwnProperty(k)) {
              result[k] = 0;
            }
    
            result[k] += n[k];
          }
        }
      }
    
      return result;
    }

    Использовать, понятное дело, так: const obj = sum(obj1, obj2);.
    Ответ написан
    Комментировать
  • Почему не получается добавить ещё одно событие?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Во-первых, события не добавляют - так говорить безграмотно. Добавляют обработчики событий.

    Во-вторых:

    Если зарегистрировано несколько одинаковых EventListener на одном EventTarget с одинаковыми параметрами, дублирующиеся обработчики игнорируются.
    Ответ написан
    Комментировать
  • Как правильно обработать клик на любой дочерний элемент?

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

    const container = document.querySelector('#element');
    const itemSelector = '.someclass';
    const key = 'id';
    const attr = `data-${key}`;
    const attrSelector = `[${attr}]`;

    Слушаем клики непосредственно на элементах:

    container.querySelectorAll(itemSelector).forEach(function(n) {
      n.addEventListener('click', this);
    }, function(e) {
      e.preventDefault();
      let el = this;
      while (!(el = el.parentNode).hasAttribute(attr)) ;
      console.log(el.getAttribute(attr));
    });

    Или, на обладателях data-атрибута:

    container.querySelectorAll(attrSelector).forEach(n => {
      n.addEventListener('click', onClick);
    });
    
    function onClick(e) {
      if (e.target.matches(itemSelector)) {
        e.preventDefault();
        console.log(e.currentTarget.attributes[attr].value);
      }
    }

    Или, на контейнере:

    container.addEventListener('click', e => {
      const item = e.target.closest(itemSelector);
      if (item) {
        e.preventDefault();
        console.log(item.closest(attrSelector).dataset[key]);
      }
    });
    Ответ написан
    Комментировать
  • Как сортировать массив объектов по их паренту?

    0xD34F
    @0xD34F Куратор тега JavaScript
    function sort(arr) {
      const obj = Object.fromEntries(arr.map(n => [ n.parent, n ]));
      const sorted = [];
    
      for (let item = obj['null']; item; item = obj[item.id]) {
        sorted.push(item);
      }
    
      return sorted;
    }

    или

    function sort(arr, parent = null) {
      const item = arr.find(n => n.parent === parent);
      return item
        ? [ item, ...sort(arr, item.id) ]
        : [];
    }
    Ответ написан
    Комментировать
  • Как конвертировать формат времени?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const formatDateStr = str =>
      new Date(str.split(' GMT', 1)[0])
        .toLocaleDateString('ru-RU')
        .split('.')
        .reverse()
        .join(', ');

    или

    const formatDateStr = function(str) {
      const [ , month, day, year ] = str.match(/(\S+) (\d+) (\d+)/);
      return [ year, this[month], day.padStart(2, 0) ].join(', ');
    }.bind(Object.fromEntries(Array.from({ length: 12 }, (_, i) => [
      new Date(0, i).toLocaleString('en', { month: 'short' }),
      `${i + 1}`.padStart(2, 0)
    ])));
    Ответ написан
    Комментировать
  • Как проверить содержит ли в массив массивов нужный мне массив?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Коротко:

    const includes = (arrs, search) =>
      arrs.some(arr => arr.length === search.length && arr.every((n, i) => n === search[i]));

    Длинно:

    function includes(arrs, search) {
    COMPARE_ARRAYS:
      for (const arr of arrs) {
        if (arr.length === search.length) {
          for (const [ i, n ] of arr.entries()) {
            if (!Object.is(n, search[i])) {
              continue COMPARE_ARRAYS;
            }
          }
    
          return true;
        }
      }
    
      return false;
    }
    Ответ написан
    4 комментария
  • Как вывести массив объектов в виде таблицы?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Собираем массив столбцов:

    const columns = [ '#', ...new Set(persons.flatMap(Object.keys)) ];
    
    // или
    
    const columns = [ '#' ].concat(Object.keys(Object.assign({}, ...persons)));

    Собираем разметку таблицы:

    document.body.insertAdjacentHTML('beforeend', `
      <table>
        <thead>
          <tr>${columns.map(col => `
            <th>${col}</th>`).join('')}
          </tr>
        </thead>
        <tbody>${persons.map((person, i) => `
          <tr>${columns.map((col, j) => `
            <td>${j ? person[col] ?? '-' : i}</td>`).join('')}
          </tr>`).join('')}
        </tbody>
      </table>
    `);

    Или, создаём элементы напрямую:

    const table = document.createElement('table');
    
    table.createTHead().insertRow().append(...columns.reduce((acc, col) => (
      (acc[acc.length] = document.createElement('th')).textContent = col,
      acc
    ), []));
    
    persons.forEach(function(person, i) {
      columns.forEach(function(col, j) {
        this.insertCell().textContent = j ? person[col] ?? '-' : i;
      }, this.insertRow());
    }, table.createTBody());
    
    document.body.append(table);
    Ответ написан
    2 комментария
  • Как заставить функцию ждать выполнения события click?

    0xD34F
    @0xD34F Куратор тега JavaScript
    async function Func() {
      console.log('START');
    
      await new Promise(r => {
        $('div').one('click', () => (console.log('CLICK'), r()));
      });
    
      console.log('END');
    }
    Ответ написан
    Комментировать
  • Как найти значение по ключу в объекте с неизвестной глубиной вложенности?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Рекурсия есть:

    const find = (data, key) => Object
      .entries(data instanceof Object ? data : {})
      .reduce((found, [ k, v ]) => found ?? (k === key ? v : find(v, key)), null);

    Рекурсии нет:

    function find(data, key) {
      for (const stack = [ data ]; stack.length;) {
        const n = stack.pop();
        if (n?.hasOwnProperty(key)) {
          return n[key];
        }
    
        if (n instanceof Object) {
          stack.push(...Object.values(n));
        }
      }
    
      return null;
    }
    Ответ написан
    Комментировать
  • Почему не срабатывает функция при нажатии?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Брехня, всё срабатывает.

    Бегом гуглить, что такое всплытие событий.

    Надо его останавливать:

    const $section = $('.section').on('click', () => $section.addClass('opened'));
    $section.find('.close').on('click', e => {
      e.stopPropagation();
      $section.removeClass('opened');
    });
    
    // или
    
    const section = document.querySelector('.section');
    
    section.addEventListener('click', () => section.classList.add('opened'));
    section.querySelector('.close').addEventListener('click', e => (
      e.stopPropagation(),
      section.classList.remove('opened')
    ));

    Или есть вариант ограничиться одним обработчиком, в котором проверять, откуда событие пришло:

    const $section = $('section').click(e => {
      $section.toggleClass('opened', !$(e.target).is('.close'));
    });
    
    // или
    
    document.querySelector('.section').addEventListener('click', e => {
      e.currentTarget.classList.toggle('opened', !e.target.matches('.close'));
    });
    Ответ написан
    1 комментарий
  • Как сгруппировать массив объектов по двум свойствам?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Object.values(orders.reduce((acc, n) => {
      const date = n.date.split(' ')[0];
    
      ((acc[date] ??= {
        date,
        documents: {},
      }).documents[n.docTypesName] ??= {
        date: n.date,
        docId: n.docId,
        docTypesName: n.docTypesName,
        products: [],
      }).products.push({
        name: n.name,
        price: n.price,
        image: n.image,
        qunatity: n.quantity,
      });
    
      return acc;
    }, {})).map(n => (n.documents = Object.values(n.documents), n))
    Ответ написан
  • Как избавиться от утечек памяти при самовызове промисов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    С каждым "неудачным" вызовом функции camel у вас добавляется ещё один промис, ждущий разрешения. 10 "неудачных" вызовов - 10 промисов в режиме ожидания. 1000 попыток - 1000 промисов. И т.д. Каждый съедает немного памяти.

    Не нужно вам тут никакого "самовызова". Вместо рекурсии сделайте цикл:

    async function test() {
      let result = null;
    
      do {
        result = await camel() || await new Promise(r => setTimeout(r, 1000));
      } while (!result);
    
      return result;
    }
    Ответ написан
    3 комментария
  • Как определить дату, отстоящую от другой даты на определённое количество дней?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const days = 46330;
    const date = new Date();
    date.setDate(date.getDate() + days);
    const dateStr = date.toLocaleDateString('ru-RU', {
      day: 'numeric',
      month: 'short',
      year: 'numeric',
    });
    
    console.log(dateStr);
    Ответ написан
    Комментировать
  • Как превратить вложенный массив в плоский?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Рекурсия есть:

    const flatten = arr => [].concat(...arr.map(n => Array.isArray(n) ? flatten(n) : n));
    
    // или
    
    function flatten(arr) {
      const result = [];
    
      for (const n of arr) {
        if (n?.constructor === Array) {
          [].push.apply(result, flatten(n));
        } else {
          result.push(n);
        }
      }
    
      return result;
    }

    Рекурсии нет:

    function flatten(arr) {
      const result = [];
      const stack = [];
    
      for (let i = 0; i < arr.length || stack.length; i++) {
        if (i === arr.length) {
          [ i, arr ] = stack.pop();
        } else if (arr[i] instanceof Array) {
          stack.push([ i, arr ]);
          [ i, arr ] = [ -1, arr[i] ];
        } else {
          result.push(arr[i]);
        }
      }
      
      return result;
    }
    
    // или
    
    function flatten([...arr]) {
      for (let i = 0; i < arr.length; i++) {
        const n = arr[i];
        if (n?.[Symbol.iterator] && typeof n !== 'string') {
          arr.splice(i--, 1, ...n);
        }
      }
    
      return arr;
    }
    Ответ написан
    Комментировать
  • Как при вызове return из функции в функции остановить функцию?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Никак, forEach прервать нельзя. Да и не надо тут никаких forEach'ей, больше подойдёт some. И функция не нужна, код совсем короткий получается:

    words.some(n => str.includes(n))
    Ответ написан
    1 комментарий
  • Как по клику на кнопку окрывать нужный попап ( класс в дата атрибуте)?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const openSelector = '.block__item';
    const closeSelector = '.close';
    const itemSelector = '.popup';
    const activeClass = 'popup--active';
    
    
    // делегирование, общий обработчик клика - для открытия и закрытия сразу,
    // назначается один раз для всех элементов;
    // связь кнопок открытия попапов с попапами через data-атрибут
    document.addEventListener('click', ({ target: t }) => {
      let item = t.closest(closeSelector)?.closest(itemSelector);
      if (!item) {
        const open = t.closest(openSelector);
        if (open) {
          item = document.querySelector(`${itemSelector}.${open.dataset.popup}`);
        }
      }
    
      item?.classList.toggle(activeClass);
    });
    
    // или, отдельные обработчики клика для открытия и закрытия,
    // назначаются каждому элементу индивидуально;
    // связь кнопок открытия попапов с попапами через индексы
    const open = [...document.querySelectorAll(openSelector)];
    const close = document.querySelectorAll(closeSelector);
    const items = document.querySelectorAll(itemSelector);
    
    const onOpenClick = e => items[open.indexOf(e.currentTarget)].classList.add(activeClass);
    open.forEach(n => n.addEventListener('click', onOpenClick));
    
    const onCloseClick = e => e.currentTarget.closest(itemSelector).classList.remove(activeClass);
    close.forEach(n => n.addEventListener('click', onCloseClick));
    Ответ написан
    Комментировать
  • Почему не работает код?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Вопрос бессмысленный - код работает. Между "не работает" и "работает не так, как задумано" есть существенная разница. Попытайтесь её осознать.

    params = format({

    Зачем здесь вызов format? Не нужен.

    params_list = Object.values(params)
    console.log(params_list)
    for (var v in params_list) {s=s+v+'='+params[v]+'&'}

    Вот это конечно дичь дикая. Чтобы такое написать, надо не знать, как работает цикл for-in. Разберитесь. Не нужен тут массив значений, перебирать надо было сразу params.

    А вообще, всё это делается гораздо проще:

    function format(params, method) {
      return `https://api.vk.com/method/${method}?${new URLSearchParams(params)}`;
    }
    
    console.log(format({ access_token, version }, method));
    Ответ написан
    4 комментария
  • Как просуммировать элементы массива, расположенные до нуля?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const sum = arr.reduceRight((acc, n) => n && acc + n, 0);

    или

    let sum = 0;
    for (let i = 0; arr[i]; sum += arr[i++]) ;

    или

    let sum = 0;
    for (const n of arr) {
      if (!n) {
        break;
      }
      sum += n;
    }

    или

    const sum = (function sum(i, n = arr[i]) {
      return n ? n + sum(i + 1) : 0;
    })(0);
    Ответ написан
    1 комментарий