Ответы пользователя по тегу JavaScript
  • Как сократить или оптимизировать скрипт?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Если задача на каждом шаге дать active нашим и убрать остальным — для step_X и элементов с классами .circle_X и .line_X.
    Тогда можно примерно такую функцию написать:
    const setStep = (n) => {
      const ACTIVE = 'active';
      for (let i = 1; i <= 3; i++) {
        const action = i === n ? 'addClass' : 'removeClass';
    
        this[`step_${i}`][action](ACTIVE);
        $(`circle_${i}`)[action](ACTIVE);
        $(`line_${i}`)[action](ACTIVE);
      }
    }
    Тут возможны сложности с получением step_X, не известно, в каком контексте они объявлены. Но сам принцип, надеюсь, понятен.
    Ответ написан
  • Почему рандомные элементы в массиве повторяются?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Предлагаю решение немного изменить, потому что работать со строками и искать их в уже собранных вариантах – долго и ненадёжно.

    Вместо этого составить массив всех возможных уникальных пар индексов.
    Этот массив «всех» вариантов перемешать. Например, красивым алгоритмом Фишера-Йейтса (или Кнўта). В массиве пар точно нет повторений, и порядок стал случайным.
    Теперь осталось отрезать от этой колбасы кусок нужной длины. И заменить индексы словами.

    spoiler
    // перемешивает массив случайным образом
    const shuffle = arr => {
      let currentIndex = arr.length, randomIndex;
      while (currentIndex > 0) {
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex--;
        [arr[currentIndex], arr[randomIndex]] = [arr[randomIndex], arr[currentIndex]];
      }
      return arr;
    };
    
    const getRandomPairs = (arrA, arrB, n) => {
      const [lengthA, lengthB] = [arrA.length, arrB.length];
      const indexPairs = [];
      for (let a = 0; a < lengthA; a++) {
        for (let b = 0; b < lengthB; b++) {
          indexPairs.push([a, b]);
        }
      }
    
      shuffle(indexPairs);
    
      indexPairs.length = Math.min(n, indexPairs.length);
    
      return indexPairs.map(pair => [arrA[pair[0]], arrB[pair[1]]].join(' '));
    };
    
    // использование
    const NAMES = ['Иван', 'Marya', 'Gendalf', 'Rick'];
    const SURNAMES = ['Sus', 'Ger', 'Gray', 'Graims'];
    
    getRandomPairs(NAMES, SURNAMES, 8);
    
    // [ "Rick Graims", "Marya Sus", "Gendalf Gray", "Gendalf Graims", "Gendalf Sus", "Marya Gray", "Иван Gray", "Rick Sus" ]
    Ответ написан
    Комментировать
  • Как функции декораторы работают изнутри?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Что делает декоратор — получает одну и создаёт новую функцию.

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

    1. Каким образом аргумент функции double() передаётся в аргумент функции, которую возвращает декоратор?

    Наоборот: теперь работают с новой функцией, которую вернул декоратор. А уже она, внутри, вызывает double() в которую и передаёт аргумент, с которым её вызвали.

    2. Почему не работает прямой вызов функции-декоратора? decorator(double(5))
    в таком варианте аргументом в decorator() попадает что? — не сама функция double, а результат её выполнения с аргументом 5.

    Наверное, вам пока непривычно, что аргументом функций может быть не только, скажем, число,
    а и целая функция. Почувствуйте разницу:
    (fn2( fn1 ))(arg)
    // fn2 получает аргументом функцию fn1
    // возвращает новую функцию, и уже та выполняется
    // с аргументом arg
    
    fn2( fn1( arg ))
    // fn1 выполняется с аргументом arg
    // результат попадает аргументом в fn2
    // возвращается результат вызова fn2
    Ответ написан
    3 комментария
  • Как понять если мой скрипт открыт в еще одной вкладке?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Можно использовать шину обмена сообщениями BroadcastChannel – есть во всех современных браузерах.

    Не совсем понял задачу. Если достаточно отключать остальные, когда новая вкладка запускает скрипт, то новичок просто запускает сообщение «всем молчать!» (все выключаются) и начинает сам слушать сообщения, пока ещё одна вкладка не появится с предложением остальным выключиться.

    Если нужно вести список вкладок, добавлять новую, при отключении активной, снова запускать одну из заглушенных — чуть сложнее. Скрипт, запускаясь, генерит уникальный ID для себя. Так он сможет отличать себя от других. Нужно поддерживать где-то общий массив вкладок – это можно и в LocalStorage.
    Сложный момент - снова запустить скрипт в одной из заглушенных вкладок, когда закрылась активная. Закрытие вкладки не генерит обрабатываемого события, поэтому придётся как-то с таймерами постоянно проверять, «а не запуститься ли мне?». Может что-то умнее можно придумать.. Сейчас лень )
    Ответ написан
    1 комментарий
  • Как работают приложения реального времени?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Инициатива не на той стороне:
    не клиент должен запрашивать снова и снова «есть чё?»,
    а сервер, когда что-то происходит-появляется, в этом же событии пусть толкает сообщение заинтересованным получателям.

    Один из вариантов решения — упомянутые в других ответах веб-сокеты.

    Приложения реального времени используют «событийную» архитектуру. В обе стороны.
    На сервере: появилась новость – это событие, есть его обработчики (вызвалась функция), где это сообщение рассылают тем, кто сейчас на связи (установлено WebSocket соединение), и подписывался на события такого типа.
    На клиенте: нажали вдруг кнопку лайк! – слушатель-обработчик этого события (функция) отправил сообщение на сервер, мол под таким-то постом юзер Ю поставил лайк.
    Ответ написан
    Комментировать
  • Как получить массив дат со следующими пятью днями?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Array(5) // длина массива
      .fill()
      .map((_, i) => {
        const D = new Date();
        D.setDate(D.getDate() + i);
        return D;
      })
    вернет требуемый массив дат
    Ответ написан
    1 комментарий
  • Какой функцией декодировать эту строку - чтобы русские буквы получились?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    toString() прекрасно сделает работёнку: грязно и дёшево )

    (
      "\u042d\u0442\u043e \u0442\u0435\u043a\u0441\u0442 \u043a\u043e\u0442\u043e\u0440\u044b \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u043e\u0439 \u0444\u0438\u0433\u043d\u0451\u0439 \u0437\u0432\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d \u0438 \u0431\u043e\u0433 \u0437\u043d\u0430\u0435\u0442 \u043a\u0430\u043a \u0435\u0433\u043e \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u044b\u043c"
    ).toString()  // "Это текст которы ..."

    по сути, тут и делать ничего не надо — это просто разные способы записать одну и ту же строку.

    Как число можно записать, например, и 1000 и 1e3 и 0x3E8,
    так и букву, например, можно записать несколькими способами: "ё", "\u0451".
    «В памяти» в итоге окажется одно и то же значение.
    Ответ написан
    Комментировать
  • Как найти в массиве, элементы другого массива и узнать их положение?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    const alpha = 'abcdefghijklmnopqrstuvwxyz'.split(''); // массив ["a", ... "z"]
    
    'pavel'.toLowerCase().split('').map((c) => alpha.indexOf(c)) 
    // [ 15, 0, 21, 4, 11 ]

    Если не требуется перемешанный алфавит, а годится в стандартном порядке a..z то можно использовать UTF таблицу, где латиница с маленькой буквы начинается с 97 (совпадает с ASCII):
    'pavel'.toLowerCase().split('').map((c) => c.charCodeAt(0) - 97)
    // [ 15, 0, 21, 4, 11 ]
    Ответ написан
    Комментировать
  • AddEventlistener и oninput, как выкрутиться, если надо удалить и проверить на наличие одновременно?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Слушателей события повесить только один раз, сразу.

    Добавить переменную типа let isActive = false; – флаг состояния: активно или нет. Как сейчас у вас наличие/отсутствие слушателя.
    По событию blur – ставить в false, input или focus – ставить true.
    Не повторять себя – обновление значения innerHTML = Math.round() сейчас дважды. Достаточно явно вызвать функцию.
    Лучше не использовать подчёркивание в названиях переменных / функций, это не наш стиль )
    Ответ написан
    2 комментария
  • Задачка на массивы и циклы JS?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Лучше, наверное, без временного массива, по-честному in-place:
    берёшь пару элементов и меняешь их местами.
    • Первый с последним.
    • Второй с предпоследним.
    • ?????
    • Profit!
    В цикле придётся пройти всего пол-массива.
    синтакс

    Современный синтакс позволяет менять местами два элемента без временной переменной:
    // a и b взаимно обменялись значениями:
    [ a, b ] = [ b, a ];
    
    
    const arr = [1, 2, 3, 4, 5];
    [arr[0], arr[4]] = [arr[4], arr[0]];
    arr // [5, 2, 3, 4, 1]

    Ответ написан
    2 комментария
  • Как добавить массив на страницу?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    раз есть массив, и для каждого элемента нужно получить на выходе карточку, нужна функция:
    на вход элемент массива, на выходе – карточка.

    И тогда
    initialCards.forEach(item => {
      // создать карточку
      const element = makeElementFromItem(item);
    
      // установить эту карточку куда-то в DOM-дереве
      document.body.appendChild(element);
    });
    Вам осталось реализовать функцию makeElementFromItem() — но там в начале у вас уже есть все эти createElement() – думаю, вы справитесь.
    Ответ написан
    Комментировать
  • Как вытащить число из десятичной дроби?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Если на входе не числа, а строки, то можно регуляркой заменить ноль-точку-нули в начале на пустую строку:
    '0.0000001024'.replace(/^0?\.?0*/, '') // получится строка "1024"


    upd. т.к. числа даются именно как числа, вместо 0.0000001024 после преобразования toString() мы увидим "1.024e-7"
    Решение то же по смыслу, но брать всё до "e" и убирать точку
    Ответ написан
    Комментировать
  • Как экспортировать return функции которая внутри функции?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Может как-то так
    const selectTrack = new Promise(resolve => {
      document.querySelectorAll('.chartsCard')
        .forEach(el => el.addEventListener('click', () => resolve(el.dataset.musicid)));
    });
    
    selectTrack.then(track => {
      // тут что-то сделать с выбранным треком
      console.log('выбранный трек', track);
    });
    Ответ написан
    Комментировать
  • Как найти последний индекс в массиве в диапозоне с помощью findIndex()?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    раз пошла такая пляска.. на костылях, то почему бы не
    array
      .map(el => el > min && el < max) // получился массив булевых значений
      .findIndex((c, i, arr) => c && i === arr.lastIndexOf(true)) // а чё, так можно было?!
    Ответ написан
    Комментировать
  • Как получить разницу между двумя датами в днях и в часах в плагине datetimepicker?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Сначала получить разницу между двумя объектами Date в часах.
    Затем посмотреть, сколько в эти часы влезает целых суток, и вычесть их.

    const diffHours = Math.ceil((endDate - startDate) / 36e5); // точно в бОльшую сторону округлять?
    const days = Math.floor(diffHours / 24);
    const hours = diffHours - days * 24;
    
    console.log(`Срок аренды: ${days} дней и ${hours} часов`);
    Ответ написан
    1 комментарий
  • Как разбить интервал дат на периоды?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Можно просто прибавлять часы:
    D = new Date();
    
    D.setHours(D.getHours() + 12) // подвинули вперёд на 12 часов
    даты корректируются «автомагически».

    TODO: проверить, не будет ли сюрпризов в переходах на летнее/зимнее время, когда клиент в поясе, где сохранились эти переходы.
    spoiler

    Примерная реализация. Косяк в часовом поясе текстового представления даты: вне зависимости от входного формата, на выходе даты будут в UTC:
    (
    (start, finish) => {
      const date = new Date(start);
      const dateFinish = new Date(finish);
      const result = [];
    
      while (date <= dateFinish) {
        result.push(date.toISOString());
        date.setHours(date.getHours() + 12);
      }
      return result;
    }
    )('2020-01-01T00:00:00+03:00', '2020-03-15T11:58:01+03:00')
    /*
    Array(149) [ "2019-12-31T21:00:00.000Z", "2020-01-01T09:00:00.000Z", "2020-01-01T21:00:00.000Z", "2020-01-02T09:00:00.000Z", "2020-01-02T21:00:00.000Z", "2020-01-03T09:00:00.000Z", "2020-01-03T21:00:00.000Z", "2020-01-04T09:00:00.000Z", "2020-01-04T21:00:00.000Z", "2020-01-05T09:00:00.000Z", … ]
    */
    Ответ написан
    Комментировать
  • Как скрыть меню при нажатии на любую другую область?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Ещё пара идей:
    1. рисовать прозрачный div прямо под меню поверх всего остального и слушать click на нём – так любой клик «мимо меню» будет отловлен этим div'ом
    2. слушать клик на корневом document – событие «всплывает» наверх, и если никто его раньше отловит, дойдёт до document. Этот способ менее надёжный, т.к. мимо меню можно кликнуть на другом элементе, где клики ловят и дальше не отпускают.
    Ответ написан
    Комментировать
  • Кто поможет решить задачу по JavaScript?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    узнать, есть ли атрибут у элемента: element.hasAttribute('maxlength')

    установить атрибут: element.setAttribute('maxlength', 20)

    выбрать все: document.querySelectorAll('input[type=password]')

    План:
    1. выбрать все с типом password;
    2. пройти по ним циклом forEach()
    3. внутри смотреть, есть ли уже атрибут maxlength;
    4. если нет, добавить атрибут
    5. выполнить alert() в любом случае
    Ответ написан
    Комментировать
  • Как сделать cекундомер без setInterval и setTimeout?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Я за RAF! : )

    let rafSeconds = 0;
    const rafStart = Date.now();
    const tick = () => {
      const seconds = (Date.now() - rafStart) / 1000 | 0;
      if (rafSeconds !== seconds) { // секунды изменились!
        rafSeconds = seconds;
        // TODO: отрисовать новые секунды
      }
      window.requestAnimationFrame(tick);
    }
    
    tick();
    Ответ написан
    2 комментария
  • Как узнать сколько лет человеку через input?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Слушать событие изменения — "input", брать значение – это будет строка типа "2022-01-19"
    Из неё конструировать объект Date.
    Втрой объект Date создать на сейчас. И сдвинуть год на 18 назад.
    Сравнить, какой больше:

    Ответ написан
    Комментировать