Задать вопрос
Ответы пользователя по тегу JavaScript
  • Как сделать неактивными все 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
    x?.[Symbol.iterator] instanceof Function
    Ответ написан
    Комментировать
  • Как вывести самую длинную строку из массива?

    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);
        if (!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());
    Ответ написан
    Комментировать
  • Как получить каждый последний подряд идущий элемент с нужным классом?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const elements = Array.prototype.filter.call(
      document.querySelectorAll('.green'),
      (n, i, a) => n.nextElementSibling !== a[i + 1]
    );

    Если отдельно стоящие элементы не интересуют, то замените селектор на '.green + .green', или при фильтрации дополнительно проверяйте, что n.previousElementSibling === a[i - 1].
    Ответ написан
    1 комментарий
  • Как получить часть строки после последнего «/»?

    0xD34F
    @0xD34F Куратор тега JavaScript
    str.split('/').pop()
    // или
    str.match(/[^\/]+$/)[0]
    // или
    str.replace(/.*\//, '')
    // или
    str.slice(str.lastIndexOf('/') + 1)
    // или
    Array.from(str).reduce((acc, n) => n === '/' ? '' : acc + n, '')
    // или
    [...str].filter((n, i, a) => !a.includes('/', i)).join('')
    Ответ написан
    1 комментарий
  • Как удалить родительский элемент через дочерний?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Что помешало разобраться с этим вопросом самостоятельно? Всего-то надо было догадаться погуглить пару вещей:

    1. Как получить родительский элемент
    2. Как удалить элемент

    Нет, серьёзно - ЧТО ВАМ ПОМЕШАЛО?

    UPD.

    Кого надо удалить, на кого надо нажимать:

    const itemSelector = '.header';
    const buttonSelector = `${itemSelector} .delete_block`;

    Удаляем:

    document.querySelectorAll(buttonSelector).forEach(function(n) {
      n.addEventListener('click', this);
    }, ({ currentTarget: t }) => {
      while (!(t = t.parentNode).matches(itemSelector)) ;
      t.replaceWith();
    });
    
    // или
    
    document.addEventListener('click', e => e
      .target
      .closest(buttonSelector)
      ?.closest(itemSelector)
      .remove()
    );
    Ответ написан
    2 комментария
  • Как правильно скрестить 3 массива в один?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Почему именно три? Давайте сделаем функцию, которая будет обрабатывать произвольное количество массивов; а в качестве признака, по которому надо объединять их элементы, будет выступать не обязательно id:

    function merge(key, ...arrs) {
      const getKey = key instanceof Function ? key : n => n[key];
      const result = new Map;
    
      arrs.forEach(arr => arr.forEach(n => {
        const k = getKey(n);
        result.set(k, Object.assign(result.get(k) ?? {}, n));
      }));
    
      return [...result.values()];
    }

    Использовать так: const result = merge('id', arr1, arr2, arr3);.
    Ответ написан
    Комментировать
  • Как можно сделать функцию перебора объекта проще/чистой?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Проще - используйте возможности массивов более полно:

    const getTruthyKeys = obj =>
      Object
        .entries(obj)
        .filter(n => n[1])
        .map(n => n[0]);

    Чистой - заведите себе привычку объявлять все используемые переменные. Сейчас ваша функция гадит в глобальную (или какую-то другую внешнюю, если там есть переменные с такими же именами) область видимости (не в строгом режиме и при отсутствии таких переменных во внешних областях видимости конечно, в этом случае ваш код просто упадёт с ошибкой), вот здесь:

    for([key, value] of Object.entries(item)) {


    UPD. А вообще, если подумать, то такая функция чистой быть не может. Уж точно не в js.
    Потому что в js можно сделать так:

    const obj = new Proxy({
      a: 0,
      b: 1,
      c: 2,
    }, {
      get: () => Math.round(Math.random()),
    });

    Ну и соответственно, результаты будут случаться для такого объекта самые разные:

    console.log(Array.from({ length: 10 }, () => getTruthyKeys(obj)));

    Ответ написан
    4 комментария
  • Как переписать значения во вложенных объектах?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const replaceValues = (val, test, replacer) =>
      val instanceof Array
        ? val.map(n => replaceValues(n, test, replacer))
        : val instanceof Object
          ? Object.fromEntries(Object
              .entries(val)
              .map(([ k, v ]) => [
                k,
                test(k, v)
                  ? replacer(v)
                  : replaceValues(v, test, replacer)
              ])
            )
          : val;

    const newData = replaceValues(
      data,
      k => k.includes('Date'),
      v => v.replace(/(\d+)-(\d+)-/, '$2.$1.')
    );
    Ответ написан
    6 комментариев
  • Как в jQuery улучшить функцию для работы с отдельными блоками?

    0xD34F
    @0xD34F Куратор тега JavaScript
    $('.content_toggle').click(function() {
      const $button = $(this);
    
      $(`#box-${this.id.split('-').pop()}`).slideToggle(300, function() {
        const isHidden = $(this).is(':hidden');
        $button
          .text(isHidden ? 'Показать текст' : 'Скрыть текст')
          .toggleClass('open', !isHidden);
      });
    
      return false;
    });

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

    $(this).closest('здесь селектор общего предка').find('.content_block')

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

    $(this).next()

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

    $('.content_block').eq($('.content_toggle').index(this))
    Ответ написан
    Комментировать