Задать вопрос
Ответы пользователя по тегу JavaScript
  • Есть ли разница между унарным плюсом и parseInt?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Понятно, что читать спецификацию (+, parseInt) вы вряд ли будете, раз не смогли отличия хотя бы погуглить, так что вот вам несколько примеров разницы, а дальше думайте сами, где что использовать:

    parseInt('1!!!') // 1
    +'1!!!' // NaN
    
    
    parseInt('') // NaN
    +'' // 0
    
    
    parseInt('3.14159') // 3
    +'3.14159' // 3.14159
    
    
    parseInt('0b1000101') // 0
    +'0b1000101' // 69
    
    
    parseInt('0o273') // 0
    +'0o273' // 187
    
    
    parseInt({ valueOf: () => 666 }) // NaN
    +({ valueOf: () => 666 }) // 666
    
    
    parseInt('1000000000', 2) // 512
    +'1000000000' // 1000000000
    
    
    parseInt('99', 8) // NaN
    +'99' // 99
    
    
    parseInt('DEAD', 16) // 57005
    +'DEAD' // NaN
    Ответ написан
    1 комментарий
  • Поменять значение в массиве объектов по заданному id?

    0xD34F
    @0xD34F Куратор тега JavaScript
    function update(target, source, key, props) {
      source.forEach(function(n) {
        const item = this[n[key]];
        item && props.forEach(m => item[m] = n[m]);
      }, Object.fromEntries(target.map(n => [ n[key], n ])));
    }
    
    
    update(directions, [ { раз объект }, { два объект }, ... ], 'id', [ 'color' ]);
    Ответ написан
    Комментировать
  • Можно ли добавить в данной реализации закрытие кнопки типа (toggle)?

    0xD34F
    @0xD34F Куратор тега JavaScript
    document.addEventListener('click', e => {
      const btn = e.target.closest('.more-btn');
      for (const n of document.querySelectorAll('.more-btn')) {
        n.classList.toggle('active', n === btn && !n.classList.contains('active'));
      }
    
      // или
    
      document.querySelectorAll('.more-btn').forEach(function(n) {
        n.classList[n === this ? 'toggle' : 'remove']('active');
      }, e.target.closest('.more-btn'));
    });
    Ответ написан
    2 комментария
  • Как сделать процентную вероятность выведения той или иной картинки из 2 массивов?

    0xD34F
    @0xD34F Куратор тега JavaScript
    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 getRandomPhotosArray = weightedRandom([
      [ 9,  truePhotos ],
      [ 1, funnyPhotos ],
    ], 0);
    
    function getPhoto() {
      const photos = getRandomPhotosArray()[1];
      return photos[Math.random() * photos.length | 0];
    }
    Ответ написан
    Комментировать
  • Как добавить текст в ApexCharts?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Свойства formatter в настройках tooltip'ов:

    new ApexCharts(..., {
      ...
      tooltip: {
        ...
        y: {
          title: {
            formatter: (seriesName, seriesData) => ...,
          },
          formatter: (value, seriesData) => ...,
        },
      },
    });

    Например.
    Ответ написан
    Комментировать
  • Как собрать все элементы объекта?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const getNestedData = arr =>
      Array.isArray(arr)
        ? arr.flatMap(n => [ n, ...getNestedData(n.children) ])
        : [];

    for (const n of getNestedData(DATA)) {
      console.log(n);
    }
    Ответ написан
    Комментировать
  • Как сделать дерево объектов из массива?

    0xD34F
    @0xD34F Куратор тега JavaScript
    function createTreeFromArray(arr, key, parentKey) {
      const tree = Object.fromEntries(arr.map(n => [ n[key], { ...n } ]));
    
      return Object.fromEntries(Object.entries(tree).filter(([ , n ]) => {
        return !(tree[n[parentKey]] && ((tree[n[parentKey]].children ??= {})[n[key]] = n));
      }));
    }
    
    
    const tree = createTreeFromArray(arr, 'uid', 'parentUID');
    Ответ написан
    4 комментария
  • Проблема с анимацией?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Меняете bottom, который не имеет начального значения - укажите его вместо top.
    Ответ написан
  • Как создать li для каждого элемента массива?

    0xD34F
    @0xD34F Куратор тега JavaScript
    menu.insertAdjacentHTML('beforeend', arr
      .map(n => `<li>${n}</li>`)
      .join('')
    );
    
    // или
    
    menu.append(...arr.reduce((acc, n) => (
      (acc[acc.length] = document.createElement('li')).textContent = n,
      acc
    ), []));
    
    // или
    
    for (const n of arr) {
      menu.appendChild(document.createElement('li'));
      menu.lastChild.innerText = n;
    }

    Ну или можете свой код поправить - унесите let li = document.createElement('li') внутрь цикла.
    Ответ написан
    Комментировать
  • Как получить значения из массива объектов по id?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Сделать из teamNames объект, где ключами будут id, а значениями name. Доставать из этого массива имена при переборе epl, используя team_id в качестве ключа.

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

    const teamNamesObj = Object.fromEntries(teamNames.map(n => [ n.id, n.name ]));
    const eplWithNames = epl.map(n => ({ ...n, team_name: teamNamesObj[n.team_id] }));

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

    epl.forEach(function(n) {
      n.team_name = this[n.team_id];
    }, teamNames.reduce((acc, n) => (acc[n.id] = n.name, acc), {}));
    Ответ написан
    Комментировать
  • Как посчитать количество элементов массива, имеющих определённое свойство?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Конечно, можно прямо посчитать количество интересующих нас элементов:

    const countWithKey = (arr, key) => arr.filter(n => key in n).length;
    
    console.log(countWithKey(arr, 'ключ'));

    Но можно решить задачу и в более общем виде.

    Например, просуммировав данные. Функция суммирования кроме данных получает также функцию, которая из отдельного элемента данных извлекает слагаемое, в данном случае - факт наличия нужного свойства:

    const sum = (data, val = n => n) =>
      Array.prototype.reduce.call(
        data,
        (acc, n) => acc + val(n),
        0
      );
    
    console.log(sum(arr, obj => obj.hasOwnProperty('ключ')));

    Кстати, что даёт более общий вид.
    Считать можно разные суммы. Как, например, обычных массивов из чисел (sum([ 1, 2, 3 ]) // 6), так и более сложные варианты. Например, есть массив, представляющий содержимое корзины с товарами (цена, количество), надо посчитать общую стоимость:

    const cart = [
      { price: 100, count: 5 },
      { price:  10, count: 6 },
      { price:   1, count: 7 },
    ];
    
    const total = sum(cart, item => item.price * item.count); // 567

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

    const likes = sum(document.querySelectorAll('.btn_like .btn__counter'), n => +n.innerText);


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

    function Counter(data, key = n => n) {
      const counted = new Map;
    
      for (const n of data) {
        const k = key(n);
        counted.set(k, (counted.get(k) ?? 0) + 1);
      }
    
      return k => counted.get(k) ?? 0;
    }
    
    const keyExists = Counter(arr, obj => Object.hasOwn(obj, 'ключ'));
    console.log(keyExists(true)); // смотрим, у скольких элементов массива ключ есть
    console.log(keyExists(false)); // и у скольких нет

    Аналогично суммированию, есть разные варианты применения.

    const str = 'hello, world!!';
    
    const chars = Counter(str);
    console.log(chars('h')); // 1
    console.log(chars('!')); // 2
    console.log(chars('x')); // 0

    const persons = [
      { name: 'Вася', birthday: new Date('1999-05-22') },
      { name: 'Маша', birthday: new Date('2004-03-06') },
      { name: 'Катя', birthday: new Date('1976-05-15') },
      { name: 'Петя', birthday: new Date('1987-04-18') },
      { name: 'Коля', birthday: new Date('2000-01-01') },
      { name: 'Дима', birthday: new Date('2003-05-09') },
      { name: 'Миша', birthday: new Date('1996-02-29') },
      { name: 'Таня', birthday: new Date('1981-03-12') },
      { name: 'Олег', birthday: new Date('1992-08-24') },
    ];
    
    const birthMonths = Counter(
      persons,
      ({ birthday }) => birthday.toLocaleString('ru-RU', { month: 'long' })
    );
    console.log(birthMonths('май')); // в мае родилось три человека
    console.log(birthMonths('март')); // в марте два
    console.log(birthMonths('октябрь')); // а в октябре никто

    function* naturalNumbers(n) {
      for (let i = 1; i <= n; i++) {
        yield i;
      }
    }
    
    const numLengths = Counter(naturalNumbers(100), num => `${num}`.length);
    console.log(numLengths(2)); // среди первых ста натуральных чисел - девяносто двухзначных
    console.log(numLengths(3)); // и одно трёхзначное
    console.log(numLengths(0)); // число из нуля знаков? - конечно же нет таких

    Ответ написан
    1 комментарий
  • Как правильно вывести древовидный объект в виде строки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    function objToString(val, tabSize = 2, depth = 0, noIndent = false) {
      const indent = ' '.repeat(tabSize * depth);
    
      return (noIndent ? '' : indent) + (
        val instanceof Array
          ? `[\n${val.map(n => objToString(n, tabSize, depth + 1)).join(',\n')}\n${indent}]`
          : val instanceof Object
            ? `{\n${Object
                .entries(val)
                .map(n => n.map((m, i) => objToString(m, tabSize, depth + 1, i)).join(': '))
                .join(',\n')}\n${indent}}`
            : typeof val === 'string'
              ? `"${val}"`
              : val
      );
    }
    
    
    console.log(objToString({
      numbers: [ 69, 187, 666 ],
      strings: [ 'hello, world!!', 'fuck the world', 'fuck everything' ],
      falsy_values: [ 0, '', NaN, false, null, undefined ],
      object: { xxx: true, yyy: Infinity, zzz: { '!&$': [ [ [ -1 ] ] ] } }
    }));
    Ответ написан
    Комментировать
  • Можно ли через регулярные выражения вставить в текст символ?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Регулярные выражения не нужны:

    const insert = (str, substr, ...indices) => [ 0 ]
      .concat(indices)
      .filter(n => 0 <= n && n <= str.length)
      .sort((a, b) => a - b)
      .map((n, i, a) => str.slice(n, a[i + 1]))
      .join(substr);
    
    // или
    
    const insert = (str, substr, ...indices) => indices
      .sort((a, b) => b - a)
      .reduce((acc, n) => (
        0 <= n && n <= str.length && acc.splice(n, 0, substr),
        acc
      ), [...str])
      .join('');
    
    // или
    
    const insert = (str, substr, ...indices) =>
      ''.concat(...Array.from(
        { length: -~str.length },
        function(_, i) {
          return substr.repeat(this[i] ?? 0) + str.charAt(i);
        },
        indices.reduce((acc, n) => (acc[n] = -~acc[n], acc), {})
      ));

    Но, конечно, можно и с ними:

    const insert = (str, substr, ...indices) => indices
      .filter(n => 0 <= n && n <= str.length)
      .sort((a, b) => a - b)
      .reduce((acc, n, i) =>
        acc.replace(RegExp(`(?<=^.{${n + i * substr.length}})`), substr)
      , str);

    Как использовать:

    // ваш случай
    const str = insert(`${number}`, '-', 3, 5, 8, 10);
    
    // вставлять можно больше одного символа
    insert('abc', ' --> ', 1, 2) // 'a --> b --> c'
    
    // можно по одному индексу несколько раз делать вставку
    insert('abc', '~', 0, 0, 0) // '~~~abc'
    
    // за границы строки вставка не выполняется,
    // за исключением позиции сразу же после конца строки
    insert('abc', '!', -1, 3, 4) // 'abc!'
    Ответ написан
    Комментировать
  • Как заставить работать несколько граф с оценками?

    0xD34F
    @0xD34F Куратор тега JavaScript
    вторая не работает

    Работает. Только не независимо, а как часть первой. Надо не все .grade-item обрабатывать, а только те, у кого в предках тот же .grade-item-block, что и у кликнутого.

    const container = document.querySelector('.nav-student-new-lesson');
    const blockSelector = '.grade-item-block';
    const itemSelector = `${blockSelector} .grade-item`;
    const colors = {
      grades: [
        [ 5, 'rgba(150, 255, 0, 0.3)' ],
        [ 3, 'rgba(255, 150, 0, 0.3)' ],
        [ 1, 'rgba(255,   0, 0, 0.3)' ],
      ],
      default: 'white',
    };
    
    function updateGrade(item) {
      const items = item.closest(blockSelector).querySelectorAll(itemSelector);
      const grade = 1 + Array.prototype.indexOf.call(items, item);
      const color = colors.grades.find(n => n[0] <= grade)[1];
      items.forEach((n, i) => n.style.background = i < grade ? color : colors.default);
    }

    Можно сделать делегированный обработчик:

    container.addEventListener('click', e => {
      const item = e.target.closest(itemSelector);
      if (item) {
        updateGrade(item);
      }
    });

    Или слушать клики непосредственно на .grade-item:

    container.querySelectorAll(itemSelector).forEach(function(n) {
      n.addEventListener('click', this);
    }, e => updateGrade(e.currentTarget));
    Ответ написан
    Комментировать
  • Как переключить подсветку на следующий элемент списка при нажатии стрелок вверх-вниз?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const listEl = document.querySelector('#list');
    const activeClass = 'active';
    let index = 0;
    
    next(0);
    
    document.addEventListener('keydown', function(e) {
      const step = ({
        ArrowDown: 1,
        ArrowUp: -1,
      })[e.key];
    
      if (step) {
        next(step);
      }
    });
    
    function next(step) {
      const elems = listEl.children;
      elems[index].classList.remove(activeClass);
      index = Math.max(0, Math.min(elems.length - 1, index + step));
      // или, если надо, чтобы при переходе от последнего к следующему элементу
      // активным становился первый, а при переходе от первого к предыдущему
      // активным становился последний
      // index = (index + step + elems.length) % elems.length;
      elems[index].classList.add(activeClass);
    }
    Ответ написан
    Комментировать
  • Как вернуть новый массив объектов только с уникальным id вложенного объекта?

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

    Object.values(Object.fromEntries(arr.map(n => [ n.user.id, n ])))
    
    // или, если в результирующий массив должны попадать те из "одинаковых" элементов,
    // что расположены в исходном массиве первыми
    
    Object.values(arr.reduce((acc, n) => (acc[n.user.id] ??= n, acc), {}))
    
    // или, если также надо сохранять взаимное расположение элементов
    
    arr.filter(function({ user: { id: n } }) {
      return !(this[n] = this.hasOwnProperty(n));
    }, {})

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

    function* unique(data, key = n => n) {
      const getKey = key instanceof Function ? key : n => n[key];
      const keys = new Set;
    
      for (const n of data) {
        const k = getKey(n);
        if (!keys.has(k)) {
          keys.add(k);
          yield n;
        }
      }
    }

    Теперь можно делать так (ваш случай): const result = [...unique(arr, n => n.user.id)];.

    Или так:

    Array.from(unique([{id: 1}, {id: 2}, {id: 1}, {id: 1} ], 'id')) // [{id: 1}, {id: 2}]

    Или так: ''.concat(...unique('ABBA')) // 'AB'.

    Или так:

    for (const n of unique(Array(20).keys(), n => Math.sqrt(n) | 0)) {
      console.log(n); // 0 1 4 9 16
    }
    Ответ написан
    Комментировать
  • Как активировать select по нажатию на radio?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const radios = document.querySelectorAll('[name="radios"]');
    const selects = Array.from(radios, n => n.nextElementSibling);
    const onChange = e => selects.forEach(n => n.disabled = n !== e.target.nextElementSibling);
    radios.forEach(n => n.addEventListener('change', onChange));
    Ответ написан
  • Как создать массив чисел, которые увеличиваются с каждой итерацией?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const arithmeticProgression = ({ length, a1 = 0, d = 1 }) =>
      Array.from(
        { length },
        (n, i) => a1 + i * d
      );
    
    
    const arr = arithmeticProgression({
      length: 10,
      a1: 6,
      d: 3,
    });

    или

    function* arithmeticProgression(a1, d, length) {
      for (let i = 0; i < length; i++) {
        yield a1 + i * d;
      }
    }
    
    
    for (const n of arithmeticProgression(100, 10, 5)) {
      console.log(n);
    }
    
    console.log(Array.from(arithmeticProgression(10, -7, 10)));
    Ответ написан
    Комментировать
  • Как сделать object to HTML string?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const voidTags = [ 'input', 'img', 'br', 'hr', ещё какой-то тэг, и ещё, ... ];
    
    function createHTML(data) {
      const attrs = Object
        .entries(data.attrs ?? {})
        .map(n => `${n[0]}="${n[1]}"`)
        .join(' ');
    
      const startTag = `<${data.tagName}${attrs && (' ' + attrs)}>`;
    
      if (voidTags.includes(data.tagName)) {
        return startTag;
      }
    
      const children = (data.subTags ?? [])
        .map(createHTML)
        .join('');
    
      return `${startTag}${data.text ?? ''}${children}</${data.tagName}>`;
    }
    Ответ написан
    Комментировать