Задать вопрос
Ответы пользователя по тегу JavaScript
  • Как передать в дата-атрибут ту часть строки, которая была заменена при помощи регулярного выражения?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const phoneRegExp = здесь ваше регулярное выражение;
    const phoneButtonTemplate = '<span data-phone="$&">показать телефон</span>';
    
    document.querySelectorAll('.js-phone-replace').forEach(n => {
      n.innerHTML = n.textContent.replace(phoneRegExp, phoneButtonTemplate);
    });
    Ответ написан
    Комментировать
  • Как вывести максимальное и минимальное значение объекта?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const values = Object.values(obj);
    const min = Math.min(...values);
    const max = Math.max(...values);

    или

    const [ min, max ] = Object
      .values(obj)
      .reduce(([ min, max ], n) => [
        n < min ? n : min,
        n > max ? n : max,
      ], [ Infinity, -Infinity ]);

    или

    let min = Infinity;
    let max = -Infinity;
    
    for (const k in obj) {
      if (obj.hasOwnProperty(k)) {
        const v = obj[k];
        (min > v) && (min = v);
        (max < v) && (max = v);
      }
    }
    Ответ написан
    Комментировать
  • Как отфильтровать массив в массиве?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Как будем определять, должен ли элемент остаться: const mustStay = n => n !== null;.

    Собираем новый массив:

    const newArr = arr.map(n => ({
      ...n,
      array2: n.array2.filter(mustStay),
    }));

    Обновляем существующий:

    for (let i = 0; i < arr.length; i++) {
      const a = arr[i].array2;
      for (let j = 0; j < a.length; j++) {
        if (!mustStay(a[j])) {
          for (let k = j--; ++k < a.length; a[k - 1] = a[k]) ;
          a.pop();
        }
      }
    }
    
    // или
    
    arr.forEach(n => {
      n.array2.reduceRight((_, n, i, a) => mustStay(n) || a.splice(i, 1), 0);
    });
    
    // или
    
    (function next(i, { array2: a } = arr[i] ?? {}) {
      if (a) {
        a.splice(0, a.length, ...a.filter(mustStay));
        next(-~i);
      }
    })(0);
    
    // или
    
    for (const { array2: a } of arr) {
      a.length -= a.reduce((acc, n, i) => (
        a[i - acc] = n,
        acc + !mustStay(n)
      ), 0);
    }
    Ответ написан
    Комментировать
  • Как починить фильтр таблиц?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Укажите нормальные атрибуты name для чекбоксов - соответствующие столбцам, по которым будет осуществляться фильтрация с использованием их значений. Т.е., color для первой группы, fruit для второй.

    const table = document.querySelector('table');
    
    const columnIndex = Object.fromEntries(Array.from(
      table.tHead.rows[0].cells,
      n => [ n.innerText.toLowerCase(), n.cellIndex ]
    ));
    
    function onChange() {
      const filters = Object.entries(Array.prototype.reduce.call(
        document.querySelectorAll('.list-group :checked'),
        (acc, n) => ((acc[columnIndex[n.name]] ??= []).push(n.value), acc),
        {}
      ));
    
      for (const { rows } of table.tBodies) {
        for (const tr of rows) {
          tr.hidden = filters.some(n => !n[1].includes(tr.cells[n[0]].innerText));
        }
      }
    }
    
    document.querySelectorAll('.list-group').forEach(n => {
      n.addEventListener('change', onChange);
    });
    Ответ написан
    Комментировать
  • Как получить все вложенные элементы JS?

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

    const getElementsWithDepth = (el, depth = 0) =>
      [...el.children].reduce((acc, n) => (
        acc.push(...getElementsWithDepth(n, depth + 1)),
        acc
      ), [ { el, depth } ]);

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

    function getElementsWithDepth(root) {
      const result = [];
    
      for (const stack = [ [ root, 0 ] ]; stack.length;) {
        const [ el, depth ] = stack.pop();
        result.push({ el, depth });
        stack.push(...Array.from(el.children, n => [ n, -~depth ]).reverse());
      }
    
      return result;
    }
    
    // или
    
    const getElementsWithDepth = root =>
      Array.prototype.reduce.call(
        root.querySelectorAll('*'),
        (acc, n) => {
          acc.push({ el: n, depth: 1 });
          for (; (n = n.parentNode) !== root; acc[acc.length - 1].depth++) ;
          return acc;
        },
        [ { el: root, depth: 0 } ]
      );
    Ответ написан
    Комментировать
  • Как получить все дни в месяце и подписать номер недели?

    0xD34F
    @0xD34F Куратор тега JavaScript
    function getDays(year, month) {
      const days = [];
      const d = new Date(year, month, 1);
      let week = 1;
    
      while (d.getMonth() === month) {
        const date = d.getDate();
        const day = d.getDay();
    
        days.push({
          day: date,
          weeknumber: (day === 1 || date === 1) ? week : false,
          weekday: d.toLocaleString('en-US', { weekday: 'short' }),
        });
    
        d.setDate(date + 1);
        week += !day;
      }
    
      return days;
    }
    Ответ написан
    Комментировать
  • Как посчитать количество совпадений в тексте?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const count = text.match(RegExp(str, 'g'))?.length ?? 0;
    
    // или
    
    const count = text.split(str).length - 1;
    
    // или
    
    const count = (function get(pos) {
      const i = text.indexOf(str, pos);
      return +(i !== -1) && -~get(i + str.length);
    })(0);
    Ответ написан
    2 комментария
  • Как преобразовать объект со вложенными объектами в простой объект?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const flatObj = obj =>
      Object.entries(obj).reduce((acc, [ k, v ]) => (
        v instanceof Object && !Array.isArray(v)
          ? Object.assign(acc, flatObj(v))
          : acc[k] = v,
        acc
      ), {});
    Ответ написан
    2 комментария
  • Как задать элементам ID с условием первого не повторяющегося далее символа?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Такие варианты есть:

    document.querySelectorAll('h2').forEach(n => {
      const [ season, , episode ] = n.innerText.split(' ');
      if (+episode === 1) {
        n.id = `season-${season}`;
      }
    });

    [...document.querySelectorAll('h2')]
      .filter(n => n.innerText.endsWith(', 1 серия'))
      .forEach((n, i) => n.id = `season-${i + 1}`);

    document.querySelectorAll('h2').forEach((n, i, a) => {
      const prev = i && a[i - 1].innerText.match(/\d+/)[0];
      const curr = n.innerText.match(/\d+/)[0];
      if (curr !== prev) {
        n.id = `season-${curr}`;
      }
    });

    Array
      .from(document.querySelectorAll('h2'))
      .reduce((acc, n) => (acc[parseInt(n.innerText)] ??= n, acc), [])
      .forEach((n, i) => n.id = `season-${i}`);
    Ответ написан
    Комментировать
  • Как транспонировать матрицу?

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

    const transpose = matrix => Array.from(
      { length: matrix[0]?.length ?? 0 },
      (_, i) => matrix.map(n => n[i])
    );

    Длинно:

    function transpose(matrix) {
      const result = Array(matrix.length && matrix[0].length);
    
      for (let i = 0; i < result.length; i++) {
        result[i] = [];
    
        for (let j = 0; j < matrix.length; j++) {
          result[i][j] = matrix[j][i];
        }
      }
    
      return result;
    }
    Ответ написан
    Комментировать
  • Как последовательные числа сложить в отдельные массивы?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const groupAdjacent = (arr, newGroup) =>
      arr.reduce((acc, n, i, a) => (
        (!i || newGroup(n, a[~-i])) && acc.push([]),
        acc[~-acc.length].push(n),
        acc
      ), []);
    
    
    const result = groupAdjacent(arr, (c, p) => c !== -~p);

    или (если гарантируется, что элементы массива образуют возрастающую последовательность)

    function group(data, key) {
      const grouped = new Map;
      let i = -1;
    
      for (const n of data) {
        const k = key(n, ++i);
        grouped.set(k, grouped.get(k) ?? []).get(k).push(n);
      }
    
      return grouped;
    }
    
    
    const result = [...group(arr, (n, i) => n - i).values()];
    Ответ написан
    Комментировать
  • Как обрезать строку после длинного слова?

    0xD34F
    @0xD34F Куратор тега JavaScript
    $('.js-cropped-word').text((i, text) => text.replace(/(?<=\S{19,}).+/, '...'));

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

    В Сафари не работает

    Это из-за lookbehind. Делайте тогда так:

    document.querySelectorAll('.js-cropped-word').forEach(n => {
      n.textContent = n.textContent.replace(/(\S{19}).+/, '$1...');
    });

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

    const max = 19;
    
    for (const n of document.getElementsByClassName('js-cropped-word')) {
      const words = n.innerText.split(' ');
      const i = words.findIndex(n => n.length > max);
      if (i !== -1) {
        words.length = i + 1;
        words[i] = words[i].slice(0, max) + '...';
        n.innerText = words.join(' ');
      }
    }
    Ответ написан
    6 комментариев
  • Как добавить элементам обёртки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Кого и во что надо обернуть:

    const elements = document.querySelectorAll('input[type="button"]');
    const tag = 'div';
    const className = 'block';

    Оборачиваем:

    elements.forEach(n => {
      n.after(document.createElement(tag));
      n.nextSibling.className = className;
      n.nextSibling.append(n);
    });

    или

    for (const n of elements) {
      const wrapper = document.createElement(tag);
      wrapper.classList.add(className);
      wrapper.appendChild(n.parentNode.replaceChild(wrapper, n));
    }

    или

    for (let i = 0; i < elements.length; i++) {
      const wrapper = document.createElement(tag);
      elements[i].replaceWith(wrapper);
      wrapper.classList.value = className;
      wrapper.insertAdjacentElement('afterbegin', elements[i]);
    }

    или

    (function wrap(i, n = elements.item(i)) {
      if (n) {
        n.outerHTML = `<${tag} class="${className}">${n.outerHTML}</${tag}>`;
        wrap(-~i);
      }
    })(0);
    Ответ написан
  • Как удалить option'ы с определёнными значениями?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Откуда и кого надо удалить:

    const select = document.querySelector('вам виднее, что тут должно быть');
    const values = [ '1', '2', '3' ];

    Удаляем:

    [...select].forEach(n => values.includes(n.value) && n.remove());

    или

    for (const n of select.querySelectorAll(values.map(n => `[value="${n}"]`))) {
      select.removeChild(n);
    }

    или

    select.replaceChildren(...Array.prototype.filter.call(
      select,
      ((values, n) => !values.has(n.value)).bind(null, new Set(values))
    ));

    или

    Array.prototype.reduceRight.call(
      select.options,
      (_, n) => ~values.indexOf(n.value) && n.replaceWith(),
      null
    );

    или

    select.innerHTML = Array
      .from(select.children)
      .filter(function(n) {
        return n.matches(this);
      }, `:not(${values.map(n => `[value="${n}"]`)})`)
      .map(n => n.outerHTML)
      .join('');

    или

    (function next(i, n = select.item(--i)) {
      if (n) {
        for (const v of values) {
          if (v === n.value) {
            n.outerHTML = '';
            break;
          }
        }
        next(i);
      }
    })(select.length);
    Ответ написан
    Комментировать
  • Как совместить вставить цикл в constructor?

    0xD34F
    @0xD34F Куратор тега JavaScript
    constructor(el) {
      if (typeof el === 'string') {
        el = document.querySelectorAll(el);
      }
    
      if (typeof el[Symbol.iterator] === 'function') {
        return Array.from(el, n => new Select(n));
      }
    
      this.$select = el;
    
      // дальше всё по-старому
    Ответ написан
    Комментировать
  • Как синхронизировать работу нескольких range slider?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Классы calc__price и calc__payment заменить на общий calc.

    const $price = $('#price');
    const $firstPayment = $('#first-payment');
    
    function update($elem) {
      $elem.closest('.calc').find('output').text($elem.val());
      $('.payment-percent').html(Math.round($firstPayment.val() * 100 / $price.val()) + '%');
    }
    
    
    $price.closest('.calc').on('input', function() {
      const val = $price.val();
    
      $firstPayment
        .val((i, v) => Math.min(v, val))
        .attr('max', val)
        .rangeslider('update', true);
    
      update($firstPayment);
    });
    
    $price.add($firstPayment)
      .rangeslider({ polyfill: false })
      .closest('.calc')
      .on('input', e => update($(e.target)))
      .end()
      .trigger('input');
    Ответ написан
    1 комментарий
  • Как заменить все определенные значения в объекте с неизвестной структурой на другие?

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

    function walkNested(val, callback) {
      callback(val);
    
      if (val instanceof Object) {
        Object.values(val).forEach(n => walkNested(n, callback));
      }
    }

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

    function walkNested(val, callback) {
      for (const stack = [ val ]; stack.length;) {
        const n = stack.pop();
        callback(n);
        if (n instanceof Object) {
          stack.push(...Object.values(n));
        }
      }
    }

    Заменяем:

    walkNested(obj, n => n?.touched === true && (n.touched = false));
    Ответ написан
    Комментировать
  • Можно ли переименовать ключи в объектах находящихся в массиве?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Какие ключи хотелось бы иметь: const keys = [ 'city', 'country' ];.

    Собираем новый массив:

    const newArr = arr.map(n => Object.fromEntries(Object.values(n).map((v, i) => [ keys[i], v ])));

    Обновляем существующий:

    arr.forEach(n => Object.entries(n).forEach(([ k, v ], i) => (delete n[k], n[keys[i]] = v)));
    Ответ написан
    Комментировать
  • Как правильно обрезать уродливые строки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    str.replace(/\t.*/s, '')
    // или
    str.match(/^[^\t]*/)[0]
    // или
    str.slice(0, str.search(/\t|$/))
    // или
    str.split('\t', 1).pop()
    // или
    [...str].reduceRight((acc, n) => n === '\t' ? '' : n + acc, '')
    Ответ написан
    2 комментария
  • Как решить ошибку при преобразовании Json в Map?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Никаких ошибок нет, всё правильно, как и должно быть. Сколько есть уникальных ключей - столько записей в map'е и создаётся. Как по одному ключу может быть доступно несколько значений? Никак, это абсурд. Очевидно, вы плохо понимаете, чего хотите сделать.
    Ответ написан