Задать вопрос
Ответы пользователя по тегу JavaScript
  • Как можно менять у элемента атрибут приоритета при drag'n'drop?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Добавить в обработчик dragend:

    box.querySelectorAll('.item').forEach((n, i) => n.dataset.priority = -~i);
    
    // или
    
    for (const [ i, n ] of box.querySelectorAll('.item').entries()) {
      n.setAttribute('data-priority', i + 1);
    }
    
    // или
    
    for (let i = box.children.length; i;) {
      const attr = document.createAttribute('data-priority');
      attr.value = i;
      box.children[--i].attributes.setNamedItem(attr);
    }
    
    // или
    
    (function next(i, n) {
      n && next(n.attributes['data-priority'].value = ++i, n.nextElementSibling);
    })(0, box.firstElementChild);
    Ответ написан
    Комментировать
  • Как вывести длину самого большого вложенного массива?

    0xD34F
    @0xD34F Куратор тега JavaScript
    где ошибка?

    Скобки пересчитайте. Фигурные. Сколько закрывающих, сколько открывающих.

    Ну и конечно не надо никаких циклов в явном виде:

    const maxlen = Math.max(...arr.map(n => n.length));
    
    // или
    
    const maxlen = arr.reduce((max, { length: n }) => max > n ? max : n, -Infinity);
    Ответ написан
    Комментировать
  • Как в ссылки добавить значения title?

    0xD34F
    @0xD34F Куратор тега JavaScript
    fetch('https://gorest.co.in/public/v1/posts')
      .then(r => r.json())
      .then(r => {
    
       // собираем разметку
        document.body.insertAdjacentHTML('beforeend', `
          <ul>${r.data.map(n => `
            <li>
              <a>${n.title}</a>
            </li>`).join('')}
          </ul>
        `);
    
        // или, создаём элементы напрямую
        const ul = document.createElement('ul');
        ul.append(...r.data.map(n => {
          const li = document.createElement('li');
          const a = document.createElement('a');
          a.textContent = n.title;
          li.append(a);
          return li;
        }));
        document.body.append(ul);
      });
    Ответ написан
    1 комментарий
  • Как узнать что экземпляр конкретного класса а не его прародителя?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Получаем тип данных (конструктор или само значение, если оно nullish):

    const type = x => x == null ? x : x.constructor;
    
    type() === undefined // true
    type(null) === null // true
    type(/./) === RegExp // true
    type(187) === Number // true
    type(type) === Function // true

    Получаем имя типа:

    const typename = x => x?.constructor.name ?? `${x}`;
    
    typename() // 'undefined'
    typename(null) // 'null'
    typename(false) // 'Boolean'
    typename('hello, world!!') // 'String'
    typename({}) // 'Object'
    typename([]) // 'Array'
    typename(document.body) // 'HTMLBodyElement'
    typename(document.getElementsByClassName('xxx')) // 'HTMLCollection'
    typename(new class XXX {}) // 'XXX'
    typename((c => new class YYY extends c {})(class XXX {})) // 'YYY'
    typename(typename) // 'Function'
    Ответ написан
    Комментировать
  • Как найти элементы, встречающиеся только в одном из двух массивов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Уникализируем массивы; объединяем в один; перебираем, отмечая, встречался ли текущий элемент ранее - если элемент встречен впервые, будет false, повторно (т.е., представлен в более чем одном из исходных массивов) будет true; хватаем элементы, которые false:

    const diff = (...arrs) => Array
      .from(arrs
        .flatMap(arr => [...new Set(arr)])
        .reduce((acc, n) => acc.set(n, acc.has(n)), new Map))
      .reduce((acc, n) => (n[1] || acc.push(n[0]), acc), []);

    Или, собираем Map, где ключами будут элементы вложенных массивов, а значениями множества вложенных массивов, где присутствует данный элемент. Получаем те ключи, где размер множества равен единице:

    const diff = (...arrs) => Array
      .from(arrs.reduce((acc, arr) => (
        arr.forEach(n => acc.set(n, acc.get(n) ?? new Set).get(n).add(arr)),
        acc
      ), new Map))
      .reduce((acc, n) => (n[1].size === 1 && acc.push(n[0]), acc), []);

    Или, никаких Map и Set - проверяем, что элемент вложенного массива отсутствует во всех других вложенных массивах и в результирующем массиве:

    const diff = (...arrs) =>
      arrs.reduce((acc, arr) => (
        arr.forEach(n =>
          arrs.every(m => m === arr || !m.includes(n)) &&
          !acc.includes(n) &&
          acc.push(n)
        ),
        acc
      ), []);
    Ответ написан
    1 комментарий
  • Как заполнить TextArea через JS (калькулятор)?

    0xD34F
    @0xD34F Куратор тега JavaScript
    document.querySelector('.calc_container').addEventListener('input', e => {
      const block = e.target.closest('.calc_block');
      const price = +block.querySelector('.price span').innerText;
      const count = +e.target.value;
      block.querySelector('.summ span').innerText = price * count;
    
      const orderData = Array
        .from(e.currentTarget.querySelectorAll('.calc_block'), n => ({
          name: n.querySelector('label').innerText,
          count: +n.querySelector('.count').value,
          sum: +n.querySelector('.summ span').innerText,
        }))
        .filter(n => n.count);
    
      document.querySelector('.total_block span').innerText = orderData
        .reduce((acc, n) => acc + n.sum, 0);
    
      document.querySelector('textarea').value = orderData
        .map(n => `Название: ${n.name} | Количество: ${n.count}`)
        .join('\n');
    });
    Ответ написан
  • Как двумерный массив порезать на куски и превратить строки в столбцы?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const chunkedAndTransposed = ([ headers, ...arr ], chunkSize) =>
      arr.reduce((acc, n, i) => (
        (i % chunkSize) || acc.push(headers.map(m => [ m ])),
        n.forEach((m, j) => acc.at(-1)[j].push(m)),
        acc
      ), []);
    
    const result = chunkedAndTransposed(arr, 2);

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

    const chunkedAndTransposed = (arr, chunkSize, defautlValue = null) =>
      Array.from({ length: Math.ceil((arr.length - 1) / chunkSize) }, (_, iChunk) =>
        Array.from({ length: arr[0].length }, (_, iCol) =>
          Array.from({ length: chunkSize + 1 }, (_, iRow) =>
            iRow ? arr[iChunk * chunkSize + iRow]?.[iCol] ?? defautlValue : arr[0][iCol]
          )
        )
      );
    
    const result = chunkedAndTransposed(arr, 5);
    Ответ написан
    4 комментария
  • Как сделать неактивными все option, значение которых меньше сегодняшнего числа?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Какое сегодня число, о каком select'е идёт речь и как обновлять состояние его option'ов:

    const today = new Date().getDate();
    const select = document.querySelector('select');
    const toggle = option => option.disabled = option.value < today;

    Обновляем:

    select.querySelectorAll('option').forEach(toggle);
    
    // или
    
    Array.prototype.forEach.call(select, toggle);
    
    // или
    
    for (const n of select.options) {
      toggle(n);
    }
    
    // или
    
    for (let i = 0; i < select.children.length; i++) {
      toggle(select.children[i]);
    }
    
    // или
    
    (function next(i, n = select.item(i)) {
      if (n) {
        toggle(n);
        next(-~i);
      }
    })(0);
    
    // или
    
    const next = n => n && (next(n.nextElementSibling), toggle(n));
    next(select.firstElementChild);
    Ответ написан
    1 комментарий
  • Как продублировать содержимое элемента?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const duplicateContent = el =>
    
      // можно добавить копии вложенных узлов
      el.append(...el.cloneNode(true).childNodes);
    
      // или добавить копию разметки
      // el.insertAdjacentHTML('beforeend', el.innerHTML);
    
      // или перезаписать разметку в удвоенном виде
      // el.innerHTML += el.innerHTML;
      // el.innerHTML = el.innerHTML.repeat(2);
      // el.innerHTML = Array(3).join(el.innerHTML);
      // el.innerHTML = String.prototype.concat.apply('', Array(2).fill(el.innerHTML));
      // el.innerHTML = el.innerHTML.replace(/.+/, '$&$&');
      // el.innerHTML = /(.+)/.exec(el.innerHTML).join``;

    document.querySelectorAll('.btn').forEach(duplicateContent);
    
    // или
    
    for (const n of document.getElementsByClassName('btn')) {
      duplicateContent(n);
    }
    Ответ написан
  • Как можно оптимизировать этот код поиска совпадений в массиве?

    0xD34F
    @0xD34F Куратор тега JavaScript
    "Оптимизировать" - в смысле сократить? Вот так можно:

    const getDuplicatesIndex = (arr, key = n => n) =>
      Object.fromEntries(Object
        .entries(arr.reduce((acc, n, i) => ((acc[key(n)] ??= []).push(i), acc), {}))
        .filter(n => n[1].length > 1)
      );

    Если среди значений массива могут быть такие, которые, будучи различными, имеют одинаковый строковый эквивалент, то обычный объект следует заменить на Map:

    const getDuplicatesIndex = (arr, key = n => n) =>
      new Map(Array
        .from(arr.reduce((acc, n, i) => {
          const k = key(n);
          acc.set(k, acc.get(k) ?? []).get(k).push(i);
          return acc;
        }, new Map))
        .filter(n => ~-n[1].length)
      );
    Ответ написан
    Комментировать
  • Как создать такую функцию обертку?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Функция - это объект, ей можно добавить нужное свойство:

    function wrapper(fn) {
      function wrapped(...args) {
        return fn.apply(this, args);
      }
    
      wrapped.reset = () => console.log('hello, world!!');
    
      return wrapped;
    }
    Ответ написан
    Комментировать
  • Как проверить, что значение является итерируемым?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const isIterable = x =>
      x?.[Symbol.iterator] instanceof Function;

    isIterable([]) // true
    isIterable('') // true
    isIterable(document.scripts) // true
    isIterable(Array().keys()) // true
    isIterable((function*(){})()) // true
    
    isIterable() // false
    isIterable(null) // false
    isIterable(1) // false
    isIterable({}) // false
    isIterable(isIterable) // false
    Ответ написан
    Комментировать
  • Как вывести самую длинную строку из массива?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const longestStr = arr.reduce((max, n) => max.length > n.length ? max : n, '');
    // или
    const longestStr = arr.sort((a, b) => b.length - a.length)[0];
    // или
    const longestStr = arr.reduce((acc, n) => (acc[n.length] = n, acc), []).pop();

    или, в более общем виде:

    function max(data, key = n => n) {
      const getVal = key instanceof Function ? key : n => n[key];
      let result = null;
    
      for (const n of data) {
        const val = getVal(n);
        result = result?.[1] >= val ? result : [ n, val ];
      }
    
      return result?.[0];
    }
    
    const longestStr = max(arr, 'length');
    Ответ написан
    2 комментария
  • Насколько правильно и оптимально написан код?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Сравнивайте, делайте выводы:

    document.querySelector('#check').addEventListener('change', e => {
      document.querySelector('#password-input').type = e.target.checked
        ? 'text'
        : 'password';
    });
    Ответ написан
    Комментировать
  • Как получить значение из массива, которое используется n раз?

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

    const getRepetition = (arr, repeated) => Array
      .from(arr.reduce((acc, n) => acc.set(n, -~acc.get(n)), new Map))
      .reduce((acc, n) => (n[1] === repeated && acc.push(n[0]), acc), []);

    Длинно:

    function getRepetition(arr, repeated) {
      const result = [];
      const count = {};
    
      for (const n of arr) {
        if (!count.hasOwnProperty(n)) {
          count[n] = 0;
        }
    
        count[n]++;
      }
    
      for (const n in count) {
        if (count[n] === repeated) {
          result.push(+n);
        }
      }
    
      return result;
    }
    Ответ написан
    1 комментарий
  • Как начать поиск совпадения с конца строки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    str.replace(/,(?=[^,]*$)/, ' and')
    Ответ написан
    2 комментария
  • При $(document).click(selector) как не обрабатывать вложенные элементы в jQuery?

    0xD34F
    @0xD34F Куратор тега JavaScript
    $(document).click('.e-1', function(event) {
    console.log(event.target)
    });

    Вот бы узнать: первый параметр метода click, он тут по вашему мнению как используется? Мне кажется, вы не до конца понимаете, что написали.

    Устанавливаем делегированный обработчик правильно, смотрим у объекта события свойство currentTarget:

    $(document).on('click', '.e-1', function(e) {
      console.log(e.currentTarget);
    });
    Ответ написан
    2 комментария
  • Как вызвать цепочку ключей в объекте, как функции с возвратом результата в предыдущий ключ?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const Format = (function createFormat(tags) {
      return new Proxy(
        (...content) => tags.reduceRight((acc, n) => `<${n}>${acc}</${n}>`, content.join('')),
        { get: (target, key) => createFormat([ ...tags, key ]) }
      );
    })([]);
    Ответ написан
    Комментировать
  • В чем причина ошибки 'expected "*\\n"' to equal '"*"'?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Ожидается '*' в качестве результата, реально вы выдаёте '*\n'.

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

    Исправлено.
    const christmasTree = length =>
      Array.from({ length }, (n, i) => (
        n = ' '.repeat(length - i - 1),
        n + '*'.repeat(i * 2 + 1) + n
      )).join('\n');
    Ответ написан
  • Как извлечь случайный элемент из вложенных массивов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Извлечение случайного элемента массива выносим в отдельную функцию:

    const random = arr => arr[Math.random() * arr.length | 0];

    Дальше можно получить случайный элемент случайного элемента:

    const item = random(random(Object.values(state.themes)));

    Или вложенный массив превратить в плоский и получить случайный элемент один раз:

    const item = random(Object.values(state.themes).flat());

    Какой из вариантов предпочесть? Зависит от того, как должны распределяться вероятности выпадения элементов - в случае, если выбирать элемент в два приёма, и размеры вложенных массивов различны, вероятности будут разными для разных массивов. Предположим, есть два вложенных массива, в одном два элемента, во втором сто. Получается, у элементов первого массива шанс быть выбранными один к четырём (один из двух массивов, один из двух элементов - 0.5 умножается на 0.5), а у элементов второго - один к двумстам (0.5 * 0.01).

    То есть, если должны быть равны вероятности выпадения элементов - объединяем вложенные массивы в один. Если равными должны быть вероятности принадлежности выбранного элемента к вложенным массивам, то выбираем сначала массив, а потом элемент внутри него.

    Но что если вероятности выпадения элементов должны быть равны, а размеры вложенных массивов велики, и не хотелось бы тратить на их объединение ни время, ни память? Возвращаемся к двум выборам, но выбирать вложенные массивы надо не с равными вероятностями, а учитывая их размеры:

    function weightedRandom(arr, key = () => 1) {
      const val = key instanceof Function ? key : n => n[key];
      const max = arr.reduce((acc, n) => acc + val(n), 0);
    
      return () => {
        let rand = Math.random() * max;
        return arr.find(n => (rand -= val(n)) < 0);
      };
    }

    const randomArr = weightedRandom(Object.values(state.themes), 'length');
    
    // ...
    
    const item = random(randomArr());
    Ответ написан
    Комментировать