Задать вопрос
  • Как получить массив чисел месяца вместе с днями недели?

    0xD34F
    @0xD34F Куратор тега JavaScript
    function getWeekdaysOfMonth(year, month) {
      const date = new Date(year, --month, 1);
      const result = [];
    
      while (date.getMonth() === month) {
        result.push(date.toLocaleString('ru-RU', {
          month: 'long',
          day: 'numeric',
          weekday: 'long',
        }));
        date.setDate(date.getDate() + 1);
      }
    
      return result;
    }
    
    
    const weekdaysOfDecember2020 = getWeekdaysOfMonth(2020, 12);

    UPD. Вынесено из комментариев:

    но как поступить если я не хочу забирать дни недели из стандартного объекта. а взять из их своего массива?

    const weekdays = [
      'воскресенье',
      'это понедельник',
      'а это вторник',
      'конечно же среда',
      'четверг',
      'пятница - прямо после четверга',
      'суббота, рабочая неделя окончена',
    ];
    
    const getWeekdaysOfMonth = (year, month) => Array.from(
      { length: new Date(year, month--, 0).getDate() },
      (n, i) => {
        const d = new Date(year, month, i + 1);
        return d.toLocaleString('ru-RU', {
          month: 'long',
          day: 'numeric',
        }) + ', ' + weekdays[d.getDay()];
      });
    
    
    const weekdaysOfFebruary2021 = getWeekdaysOfMonth(2021, 2);
    Ответ написан
  • Как из массива сделать вложенный объект?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const result = arr.reduceRight((acc, n) => ({ [n]: acc }), {});

    или

    let result = {};
    for (let i = arr.length; i--;) {
      result = { [arr[i]]: result };
    }

    или

    const result = (function createObj(arr, i) {
      return i < arr.length
        ? { [arr[i]]: createObj(arr, -~i) }
        : {};
    })(arr, 0);
    Ответ написан
    Комментировать
  • Как получить src из тега picture?

    0xD34F
    @0xD34F Куратор тега JavaScript
    document.querySelector('.products__body').addEventListener('click', e => {
      const item = e.target.closest('.card-preview__item');
      if (item) {
        e.preventDefault();
        const { srcset } = item.querySelector('source');
        item.closest('.card').querySelector('.card-head__image source').srcset = srcset;
      }
    });
    Ответ написан
    1 комментарий
  • Как сложить значения массивов по ключам?

    0xD34F
    @0xD34F
    function merge(...$arrays) {
      $result = [];
    
      foreach ($arrays as $arr) {
        foreach ($arr as $key => $values) {
          if (!isset($result[$key])) {
            $result[$key] = [];
          }
    
          for ($i = 0; $i < count($values); $i++) {
            $result[$key][$i] = ($result[$key][$i] ?? 0) + $values[$i];
          }
        }
      }
    
      return $result;
    }
    
    
    $arr = merge($arr1, $arr2);
    Ответ написан
    1 комментарий
  • Как создать тег на хабр Q & A?

    0xD34F
    @0xD34F
    Открываете форму обратной связи. В выпадающем списке "тема" выбираете пункт "гениальная идея". В текстовом поле "текст сообщения" излагаете суть - что за тэг, и почему его следует добавить. Подсказка: "почему следует добавить" - это, как минимум, наличие уже существующих вопросов, к которым новый тэг можно будет прицепить, и, наверное, не в количестве 3-5-10 штук, а побольше. Так что прежде чем предлагать добавление тэга, стоит воспользоваться поиском - убедитесь, что оно того стоит.
    Ответ написан
    Комментировать
  • Как правильно доработать логику слайдера?

    0xD34F
    @0xD34F
    нужно отлавливать дата атрибуты и если эти дата атрибуты совпадают с дата атрибутами других блоков то вешать класс на блоки

    Может, не надо никакие атрибуты трогать - учитывая, что порядок значений атрибутов идентичен для слайдов и блоков? Смотрите на индекс:

    on: {
      slideChange() {
        const index = this.realIndex;
        document.querySelectorAll('.lol').forEach((n, i) => n.classList.toggle('active', i === index));
      },
    },

    А вообще, всё это похоже на попытку соорудить собственную пагинацию. Для этого у swiper'а предусмотрены отдельные настройки. Вырезаете из .clients__picture все .lol, вырезаете обработчик slideChange, добавляете

    pagination: {
      el: '.clients__picture',
      bulletClass: 'lol',
      bulletActiveClass: 'active',
      renderBullet: (index, className) => `<div class="${className}">${index + 1}</div>`,
    },
    Ответ написан
    1 комментарий
  • Почему не отрабатывает событие?

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

      For DOM trees which represent HTML documents, the returned tag name is always in the canonical upper-case form.

      А теперь посмотрите, что вы у себя написали:

      if(str.tagName == 'ul') {

      } else if (str.tagName == 'li') {

      Кстати, а почему str, что за странный выбор имени? Там же элемент, а не строка.

    • Вместо элемента добавляется строка:

      elem.append('li');

    • Крайне странное назначение обработчика клика:

      for (let el of strLi) {
          el.addEventListener('click',func);
      };

      Во-первых - зачем каждый раз добавлять всем? Хорошо, что хоть объявление func вынесено за пределы текущей функции, иначе бы при каждом клике всем существующим li добавлялся новый обработчик.

      Во-вторых - пока не кликните по li, на свежесозданных li клик обрабатываться не будет (касается и тех, что изначально существуют).

      В-третьих - а на хрена оно надо? Вы же уже обрабатываете клик по li - так зачем назначать отдельный обработчик клика? То, что делаете в func, вполне можно делать прямо тут.


    А вообще, исправлять существующий код я бы не стал. Лучше его вырезать полностью и написать другой, получится гораздо проще и короче:

    document.querySelector('ul').addEventListener('click', e => {
      const t = e.target;
      const ct = e.currentTarget;
      t.insertAdjacentHTML('beforeend', ct === t ? '<li>text</li>' : '!');
    });
    Ответ написан
    Комментировать
  • Как из списка строк удалить элементы, кроме заданных?

    0xD34F
    @0xD34F
    [ ''.join(m for m in n if m in punct) for n in arr ]
    Ответ написан
    Комментировать
  • JS Promise Memoize как правильно описать функцию?

    0xD34F
    @0xD34F Куратор тега JavaScript
    function memoize(f, timeout) {
      const memo = {};
    
      return () => (new Date() < memo.time + timeout)
        ? Promise.resolve(memo.result)
        : f().then(r => (memo.time = +new Date(), memo.result = r));
    }
    Ответ написан
    Комментировать
  • Как отсортировать DOM элементы в обратную сторону на чистом js?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Где надо развернуть элементы: const parent = document.querySelector('ul');.

    Разворачиваем:

    parent.querySelectorAll(':scope > *').forEach(n => parent.prepend(n));
    
    // или
    
    Element.prototype.append.apply(parent, [...parent.children].reverse());
    
    // или
    
    const [ first, ...rest ] = parent.children;
    first?.before(...rest.reverse());
    
    // или
    
    for (const n of parent.children) {
      parent.insertBefore(n, parent.firstElementChild);
    }
    
    // или
    
    for (let i = parent.children.length; i--;) {
      parent.insertAdjacentElement('beforeend', parent.children[i]);
    }
    
    // или
    
    const elems = Array.from(parent.children);
    while (elems.length) {
      parent.appendChild(elems.pop());
    }
    Ответ написан
    7 комментариев
  • Как определить первые цифры чисел массива?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const first = '125';
    const startWithFirst = arr.filter(n => first.includes(`${n}`[0]));
    
    console.log(startWithFirst);

    или

    const first = [ 1, 2, 5 ];
    const startWithFirst = arr.filter(n => first.includes(n / (10 ** (Math.log10(n) | 0)) | 0));

    или

    const first = /^[125]/;
    const startWithFirst = arr.filter(n => first.test(n));
    Ответ написан
    Комментировать
  • Как ограничить выход элемента за другой?

    0xD34F
    @0xD34F Куратор тега JavaScript
    новая_координата = Math.max(
      минимальное_допустимое_значение,
      Math.min(
        максимальное_допустимое_значение,
        текущая_координата + изменение_координаты
      )
    );

    https://jsfiddle.net/03mh1q78/
    Ответ написан
    Комментировать
  • Регулярное выражение для замены img на picture?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Как получить src:

    const getSrc = img => img.getAttribute('src');
    // или
    const getSrc = img => img.attributes.src.value;

    Чтобы дальше два раза одно и то же не писать, небольшой декоратор:

    const relativeOnly = f => img => {
      const src = getSrc(img);
      if (!/^https?:\/\//.test(src)) {
        f(img, src);
      }
    };

    Можно перезаписывать разметку:

    document.querySelectorAll('img').forEach(relativeOnly((img, src) =>
      img.outerHTML = `
        <picture>
          <source srcset="${src}" type="image/svg+xml">
          ${img.outerHTML}
        </picture>`
    ));

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

    const wrapImages = relativeOnly((img, src) => {
      const picture = document.createElement('picture');
      const source = document.createElement('source');
      source.srcset = src;
      source.type = 'image/svg+xml';
      img.replaceWith(picture);
      picture.append(source, img);
    });

    for (const n of document.getElementsByTagName('img')) {
      wrapImages(n);
    }
    
    // или
    
    Array.prototype.forEach.call(document.images, wrapImages);
    Ответ написан
  • Как разделить значения массива через запятую и обернуть их в кавычки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    О каком количестве значений идёт речь: const count = 10;.

    const result = Array
      .from({ length: count }, (n, i) => `"${-~i}"`)
      .join(', ');
    
    // или
    
    const result = [...Array(count).keys()].reduce((acc, n) => {
      return acc.concat(acc && ', ', '"', ++n, '"');
    }, '');
    
    // или
    
    const result = (function xxx(n) {
      return n > 0 ? xxx(n - 1) + (n === 1 ? '' : ', ') + '"' + n + '"' : '';
    })(count);
    
    // или
    
    const result = Array(count)
      .fill()
      .map((n, i) => JSON.stringify((i + 1).toString()))
      .toString()
      .replace(/,/g, '$& ');
    Ответ написан
    Комментировать
  • Как повесить события на динамический дочерний класс?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Куда надо нажимать и какие классы переключать:

    const buttonSelector = '.class2';
    const classesToToggle = [ 'class3', 'class4' ];

    Переключаем:

    $(buttonSelector).click(e => {
      $(e.currentTarget).next().toggleClass(classesToToggle.join(' '));
    });

    или

    document.querySelectorAll(buttonSelector).forEach(n => {
      n.addEventListener('click', onClick);
    });
    
    function onClick() {
      classesToToggle.forEach(n => this.nextElementSibling.classList.toggle(n));
    }

    или

    document.addEventListener('click', e => {
      const button = e.target.closest(buttonSelector);
      if (button) {
        for (const n of classesToToggle) {
          button.parentNode.lastElementChild.classList.toggle(n);
        }
      }
    });
    Ответ написан
    2 комментария
  • Как сделать циклическую смену 3х цветов фона div при наведении и отведении мыши?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const el = document.querySelector('#box');
    const colors = [ 'red', 'green', 'blue' ];
    let index = -1;
    
    el.addEventListener('mouseenter', function() {
      index = (index + 1) % colors.length;
      this.style.backgroundColor = colors[index];
    });
    el.addEventListener('mouseleave', function() {
      this.style.backgroundColor = '';
    });
    Ответ написан
    Комментировать
  • Как ограничить количество одновременных запросов на сервер?

    0xD34F
    @0xD34F Куратор тега JavaScript
    подскажите, что мне нужно подправить

    Всё нужно подправить. А ещё больше - сделать.

    Ваша функция никак не извещает вызывающий код о том, что запросы выполнены и с какими результатами; результаты запросов - вместо того, чтобы сохранять все, сохраняете только последний полученный; вместо того, чтобы ограничить количество одновременно выполняемых запросов вы пропускаете один (кажется, вы просто не понимаете, как работает forEach).

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

    Под хранение результатов запросов создадим массив.

    Так как url'ы могут повторяться, а запросы не должны, выполним группировку массива url'ов в объект: ключи - url'ы, значения - массивы индексов, под которыми данный url встречается в исходном массиве. Выдернем из этого объекта ключи - это будет массив уникальных url'ов.

    Также создадим два счётчика - количество отправленных запросов и количество полученных ответов.

    Собственно запрос. Первым делом проверяем, сколько ответов получено - если все, резолвим промис массивом результатов. В противном случае проверяем, сколько запросов отправлено - если не все, увеличиваем соответствующий счётчик, отправляем запрос; по получении ответа достаём массив индексов url'а, сохраняем результат, увеличиваем счётчик полученных ответов и пытаемся отправить следующий запрос.

    Ну и запускаем всё это дело в работу - обычный цикл for, в котором на каждой итерации выполняется запрос. Минимум одна итерация (это на тот случай, если массив url'ов пустой), максимум - количество уникальных url'ов или ограничение на количество одновременных запросов, меньшее из этих значений.

    Всё:

    function makeRequests(urls, max) {
      return new Promise(resolve => {
        const results = Array(urls.length).fill(null);
        const groupedUrls = urls.reduce((acc, n, i) => ((acc[n] ??= []).push(i), acc), {});
        const uniqueUrls = Object.keys(groupedUrls);
        let countRequests = 0;
        let countResponses = 0;
    
        for (let i = 0; i < Math.max(1, Math.min(max, uniqueUrls.length)); i++) {
          request();
        }
    
        function request() {
          if (countResponses === uniqueUrls.length) {
            resolve(results);
          } else if (countRequests < uniqueUrls.length) {
            const url = uniqueUrls[countRequests++];
            fetch(url)
              .then(result => result.json())
              .catch(error => error)
              .then(result => {
                groupedUrls[url].forEach(n => results[n] = result);
                countResponses++;
                request();
              });
          }
        }
      });
    }

    Ответ написан
    Комментировать
  • Почему не срабатывает это регулярное выражение?

    0xD34F
    @0xD34F Куратор тега Регулярные выражения
    Регулярному выражению .?a.? соответствует подстрока aab. Дальше вы её проверяете на соответствие выражению ab - успешно, замена не производится.

    В целом, ерундой какой-то пытаетесь заниматься. Делайте так:

    preg_replace('~(?<!b)a(?!b)~', '[совпадение]', $str)
    Ответ написан
    Комментировать
  • Как закрыть попап по клику вне его в классовом компоненте?

    0xD34F
    @0xD34F Куратор тега React
    В родителе:

    state = {
      modal: false,
    }
    
    hideModal = () => {
      this.setState({ modal: false })
    }
    
    render() {
      return (
        ...
          {this.state.modal ? <Modal close={this.hideModal} /> : null}
        ...
      );
    }

    В компоненте окна:

    return (
      <div
        className="modal-overlay"
        onClick={e => (e.currentTarget === e.target) && props.close()}
      >
        <div className="modal-content">
          ...
        </div>
      </div>
    );

    https://jsfiddle.net/5d0t9feh/
    Ответ написан
    Комментировать