• Литерал объекта и блок инструкций. Есть ли связь?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Усы похожие, даже идентичные. Но по смыслу ничего общего.

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

    А блок инструкций сам по себе или со всякими do {} while () и if (condition) {}

    В общем, вроде бы, различия однозначны и коллизий не возникает:
    function foo() {}; // пустой блок
    foo({}); // передали пустой объект аргументом
    
    {} // пустой блок инструкций
    ({}) // отдельно висящий никому не нужный пустой объект
    
    [{}] // создали массив с пустым объектом
    {[]} // внутри блока создали пустой массив и забыли про него
    «Умные» редакторы кода подсвечивают усы разными цветами и ругаются на бессмысленность  бытия  пустых блоков и неиспользуемых выражений.
    как это выглядит
    6378cb1e939e9216154366.png
    Ответ написан
    Комментировать
  • Объясните смысл vue + vuex?

    Vuex – светофор на перекрёстке. Вносит порядок ценой ограничений.
    В деревне можно и без него. В большом городе – никак.

    Мухи отдельно, котлеты отдельно. Тут данные, тут их отображение, а тут мы меняем данные.
    Глобальную переменную откуда-то вдруг изменили, но никто не отреагировал.
    Ответ написан
    Комментировать
  • Не могу сделать аналог вывода простых чисел. В чем проблема?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Рабочий пример из учебника (с форматированием) хорош предсказуемостью циклов.
    Цикл for() сходу устанваливает ограничения и следит за тем, чтобы на каждой итерации все эти i, j увеличивались.

    Цикл while() — опасный анархист. Легко впадает в бесконечный цикл, если в каком-то из условий забыть i = i + 1 Что у вас в последней попытке и присутствует:
    butthurt: while (i <= 10) {
      while (j < i) {
        alert('Внутренний цикл ' + j);
        if (i % j === 0) continue butthurt;
    «Нет выхода», если i % j === 0: никто из них не поменяется и будет крутиться бесконечно.

    Как вариант:
    const LIMIT = 10;
    let i = 2;
    while (i <= LIMIT) {
      let j = 2;
      let isPrime = true;
      while (j < i && isPrime) {
        alert(`Внутренний: ${i} / ${j}`);
        if (i % j === 0) isPrime = false; // делится, значит не простое
        j++;
      }
      alert(`Внешний: ${i} - ${isPrime ? 'ПРОСТОЕ' : 'не простое'}`);
      i++;
    }
    Отказался от меток циклов и от continue – нежелательны именно из-за вносимой путаницы.
    Ответ написан
    1 комментарий
  • Как правильно модифицировать дату для value input?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    ВременнАя зона "Z" — это UTC.
    А в поле ввода, очевидно, хочется видеть время в часовом поясе браузера пользователя.

    Есть несколько способов получить строку формата "YYYY-mm-ddTHH:MM" в часовом поясе браузера. Например, вытаскивать отдельно часы, минуты и т.п. и собирать в строку.
    const timeFromBackend = "2022-11-15T20:00:00Z";
    const localTime = new Date(timeFromBackend); // 23:00 Msk
    const oo = n => n.toString(10).padStart(2, '0');
    const YYYY = localTime.getFullYear();
    const MM = oo(localTime.getMonth() + 1);
    const DD = oo(localTime.getDate());
    const HH = oo(localTime.getHours());
    const II = oo(localTime.getMinutes());
    const localTimeForInput = [YYYY, MM, DD].join('-') + 'T' + [HH, II].join(':');
    console.log(localTimeForInput); // 2022-11-15T23:00

    Или добавить минуты смещения нашего часового пояса, чтобы получить строку времени сразу целиком:
    const timeFromBackend = "2022-11-15T20:00:00Z";
    const localTime = new Date(timeFromBackend); // 23:00 Msk
    const shiftedTime = new Date(localTime);
    shiftedTime.setMinutes(shiftedTime.getMinutes() - shiftedTime.getTimezoneOffset());
    const timeForInput = shiftedTime.toISOString().substring(0, 16);
    console.log(timeForInput); // "2022-11-15T23:00"


    Обратное преобразование из локального времени в поле ввода — в UTC время для бэкенда:
    const timeFromInput = "2022-11-15T22:00";
    const date = new Date(timeFromInput);
    const timeForBackend = date.toISOString().substring(0, 19) + 'Z';
    console.log(timeForBackend)  // "2022-11-15T19:00:00Z"
    Ответ написан
    2 комментария
  • Почему в console.log получаю разные результаты от операторов?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Логические операторы && и || возвращают свои операнды:

    1 && "2" // строка "2"
    0 && "2" // число 0
    
    0 || "2" // строка "2"
    1 || false // число 1

    Логическое И &&: для позитивного результата нужно, чтобы оба операнда были как-true. Проверка идёт слева направо. Как только наткнулись на как-false, возвращается он. Прошли всю цепочку и все по пути были как-true — вернули последний из них.

    Логическое ИЛИ || даст позитивный результат, как только наткнётся хоть на один как-true. Его и вернёт. Ну или проверит все значения и если все как-false, вернёт последний из них.

    1 && "2" && "habr" // вернёт "habr"
    "1" && 0 && "qna" // 0
    
    0 || false || "habr" === "qna" // false, результат ("habr" === "qna")
    0 || 1 || 2 || true // 1, дальше проверять не пришлось
    Ответ написан
    Комментировать
  • Что делать, почему ffmpeg не работает?

    На хосте надо установить ffmpeg.

    Можно просто скачать исполняемый файл и положить в /usr/local/bin/ или /usr/local/sbin/ например.
    Ответ написан
    Комментировать
  • Как получить ссылку через this?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Геттер render находится в одном объекте, который под ключом "settings".
    А data – в другом объекте, который под ключом "template".

    Так что только через store можно "зайти":
    const store = [
      {
        template: {
          data: [1, 2, 3],
        },
        settings: {
          get render() {
            console.log(store[0].template.data);
          },
        },
      },
    ];
    
    store[0].settings.render  // [ 1, 2, 3 ]
    Ответ написан
  • При выборе div блока он должен скрыться?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Может, просто удалять кликнутые?
    Ответ написан
    3 комментария
  • Как отнять 2 месяца от текущей даты?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    const dateTwoMonthsBack = new Date();
    dateTwoMonthsBack.setMonth(dateTwoMonthsBack.getMonth() - 2);
    
    const id = 'testId'; // TODO: remove
    
    const params = {
      page_size: 200,
      manager: id,
      last_kpi_graded__lte: dateTwoMonthsBack.toISOString().substring(0, 10),
    };
    
    const url =
      'http://10.1.5.65/api/personal/users/?' +
      Object.entries(params)
        .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
        .join('&');
    
    console.log(url);
    // http://10.1.5.65/api/personal/users/?page_size=200&manager=testId&last_kpi_graded__lte=2022-09-16
    
    // fetch(url);
    Ответ написан
    Комментировать
  • Как проверять строки на равность, начиная с определённого момента?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Пока только про сравнение двух строк.

    Предлагаю прокатиться одной строкой вдоль второй.
    _________zzzoooABCuuu
    xxxABCiii      |||
     xxxABCiii     |||
      xxxABCiii    |||
    ...            |||
                xxxABCiii
    ...
                        xxxABCiii
    Начать ещё до их пересечения – это максимально возможное их несовпадение.
    И сдвигать по одной позиции вправо.

    Сравнивать, считая ошибки: количество не совпавших позиций.

    Взять тот сдвиг, где ошибок минимум.

    С «минимальными отличиями» пока не придумал ничего толкового. В этом коде просто предполагаю, что единично-отличные символы находятся не с краю совпадающих строк. Иначе всегда можно присобачить по 1 лишнему символу в начале и в конце, заявив, что именно они в этот раз случайно оказались разными )
    шит-код
    function mostCommon(a, b) {
      const A = a.split('');
      const B = b.split('');
      const min = {
        diff: A.length + B.length,
        index: -A.length,
        start: undefined,
        finish: undefined,
      };
    
      for (let offset = -A.length; offset < B.length; offset++) {
    		let diff = Math.max(0, -offset) + Math.max(offset + A.length - B.length, 0);
    		const initialDiff = Math.max(0, -offset) + Math.max(offset + A.length - B.length, 0);
        const start = Math.min(Math.max(0, offset), B.length);
        const finish = Math.min(Math.max(0, offset + A.length), B.length);
        let matchStart;
        let matchFinish;
        for (let i = start, isMatchStarted = false; i < finish; i++) {
          if (B[i] !== A[i - offset]) diff++;
          else {
            if (!isMatchStarted) {
              matchStart = i;
              isMatchStarted = true;
            }
            matchFinish = i;
          }
        }
    
        if (diff < min.diff) {
          min.diff = diff;
          min.index = offset;
          min.start = matchStart;
          min.finish = matchFinish;
        }
      }
    
      console.log(min, b.substring(min.start, min.finish + 1));
    
      return min;
    }
    
    mostCommon('xxx>abcABCxxx', 'bbbzzz>abcAXCiiiqqq');
    // { diff: 7, index: 3, start: 6, finish: 12 } >abcAXC

    На примере из вопроса:
    mostCommon("1246380924534", "88899212465809");
    // { diff: 6, index: 6, start: 6, finish: 13 } 12465809
    Ответ написан
    3 комментария
  • Как реализовать алгоритм наложения нот в чарте ритм-игры?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    setInterval(), setTimeout() — не точны. Для музыки/ритма/игры лучше полагаться на абсолютные метки времени и часы компьютера.

    // в относительных единицах от старта песни
    const hits = [ { time: 0 }, { time: 24 }, { time: 36 }, ];
    
    // on play start
    const timeK = 1200; // в зависимости от темпа
    const playStartTime = Date.now();
    const events = hits.map(hit => {
      hit.ts = playStartTime + timeK * hit.time;
      return hit;
    });
    // теперь у каждой ноты есть время ts, когда она должна сыграть
    
    // внутри цикла requestAnimationFrame, который часто-часто,
    // сраниваем текущее время с нотами,
    // если разница менее 100 мс, ноту можно "играть"
    const now = Date.now();
    events.filter(note => Math.abs(note.ts - now) < 100).forEach(note =>play(note));
    Наверное, надо смотреть и «в прошлом» пропущенные ноты – мало ли, комп притормозил.. И убирать сыгранные ноты из массива, чтобы не возвращаться к ним.
    Ответ написан
    1 комментарий
  • Как закрыть блок на крестик и запомнить, что он был закрыт?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Состояние страницы описывается набором закрытых блоков. Понадобится ещё и время их закрытия, чтобы игнорировать устаревшие. Предлагаю хранить объект, где ключи – id блоков. А значения – timestamp когда их закрыли. Что-то типа
    const boxState = {
      "block-ad-123": 1668436835032,
      "block-ad-456": 1668436842279,
    };
    Хранить этот объект можно в localStorage, переведя в строку: JSON.stringify(boxState)

    Изначально закрытых блоков нет, просто пустой объект.

    Алгоритм
    Загрузили страницу, все блоки видны.
    Считали состояние из localStorage, и если там пусто, взяли пустой объект.
    Пройти по объекту, и если прошло еще мало времени по очередному ключу, скрыть его блок.
    Если времени прошло много – удалить этот ключ из стейта.
    Если при обходе объекта были удаления – сохранить обновлённый стейт в localStorage.
    spoiler
    const boxKey = 'BOX_STATE'; // ключ для хранения в localStorage
    const boxState = JSON.parse(localStorage.getItem(boxKey)) ?? {};
    
    const TTL = 36e5; // сколько держать блок скрытым, в миллисекундах (1 час)
    const expiredIds = [];
    Object.entries(boxState)
      .forEach((key, value) => {
        if (value + TTL < Date.now()) {
          // устарел, более не скрываем
          expiredIds.push(key);
        } else {
          // актуален, скрываем блок
          document.getElementById(key).classList.add("hide");
        }
      });
    
      if (expiredIds.length) {
        expiredIds.forEach(id => delete boxState[id]);
        localStorage.setItem(boxKey, JSON.stringify(boxState));
      }


    При нажатии на крестик:
    1. добавить в стейт id этого блока и текущее время Date.now(),
    2. сохранить состояние в localStorage,
    3. добавить класс блоку.
    spoiler
    const onClose = ({ target }) => {
      const block = target.closest('div.block');
      const { id } = block;
      boxState[id] = Date.now();
      localStorage.setItem(boxKey, JSON.stringify(boxState));
      block.classList.add("hide");
    };
    document.querySelectorAll('img.x-button')
      .addEventListener('click', onClose);
    Ответ написан
    Комментировать
  • Код должен выводить текущий месяц, но почему-то не выводит, почему?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Всё, что связано с датами в JS – в объекте Date.
    Из него можно вытащить и время и месяц и всё остальное.
    Месяцы в этом объекте обозначаются числом от 0 (январь) до 11 (декабрь).

    Понадобится создать объект Date, отображающий «сейчас: new Date()
    И вытащить из него значение месяца getMonth()

    Чтобы перевести полученное число 0..11 в слово, как вариант, можно составить массив имён месяцев:
    const monthNames = ['январь', 'февраль', ... 'декабрь'];
    Удобно: под индексом 0 тут как раз "январь", под 11 "декабрь".
    Ответ написан
    Комментировать
  • Как объединить две функции в одну?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Тут 6 параметров – две группы по 3:
    1. кого слушаем #search_table VS #search_card
    2. что ищем input[name^=name] VS [data-item-name="name"]
    3. и с чем сравниваем val() VS text()


    Вытащить всё в параметры:
    const addFilter = (listenSelector, findSelector, methodName) => {
      $(listenSelector).keyup(function search() {
        const search = this;
        const searchValue = $(search).val().toLowerCase();
    
        $("#tabname tbody tr")
          .find(findSelector)
          .each(function () {
            const currentValue = $(this)[methodName]().toLowerCase();
            $(this).closest("tr").toggle(currentValue.includes(searchValue));
          });
      });
    };
    
    addFilter('#search_table', 'input[name^=name]', 'val');
    addFilter('#search_card', '[data-item-name="name"]', 'text');
    Ответ написан
    7 комментариев
  • Как сменить фон на всех открытых страницах?

    Использовать shared web worker:
    при «установке» цвета, в shared worker уходит сообщение, которое принимают все открытые страницы с этого домена в этом же браузере.

    Цвет меняется от полученного от воркера сообщения.
    Ответ написан
    Комментировать
  • Собрать все ошибки error в массив и вернуть промис?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Чтобы выполнить все запросы, и после получить массив по итогам, можно использовать метод Promise.allSettled() – передать в него массив промисов запросов Axios, и в следующий then() попадёт массив с результатами:
    const batch = new Array(214)
      .fill()
      .map((_, i) => `https://example.com/api/${i}`) // URL запросов
      .map(url => axios.get(url));
    
    Promise.allSettled(batch)
      .then(axiosResults => {
        const results = [];
        const errors = [];
    
        axiosResults.forEach(({ status, res }) => {
          if (status === 'fullfilled') {
            results.push(res);
          } else if (status === 'rejected') {
            errors.push(res);
          }
        });
    
        return { results, errors };
      })
      .then(({ results, errors }) => {
        console.log('Вот результаты: %o, а вот ошибки: %o', results, errors);
      });
    Ответ написан
  • Как сократить запись if?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Хорошо бы в какой-то переменной держать состояние, которое бывает одно из двух: true / false

    let isExpanded = false; // единственный источник правды
    
    el.addEventListener('click', () => {
      isExpanded = !isExpanded; // переключить
    
      // показать
      linkusersnew.innerText = isExpanded ? 'Свернуть' : 'Развернуть';
      userwrap.style.height = isExpanded ? '600px' : '400px';
      newdel.style.display = isExpanded ? 'flex' : 'none';
    });
    Ответ написан
    Комментировать
  • Не работает код Js что делать?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Заглядывайте в консоль браузера — сообщения об ошибках бывают весьма полезны.
    - const signinbtn = document.queryselector('.signn-btn');
    - const signupbtn = document.queryselector('.signup-btn');
    - const formbox = document.queryselector('.formbox');
    + const signinbtn = document.querySelector('.signin-btn'); // имя класса
    + const signupbtn = document.querySelector('.signup-btn');
    + const formbox = document.querySelector('.formbox');

    Та же проблема потери заглавных букв в addEventListener и classList.
    Косяки с именами классов кнопок — проверяйте. В разметке одно имя класса, в querySelector() – чуть другое.

    На будущее, пожалуйста, такие простыни кода не пихайте в текст вопроса, а создавайте песочницу с работающим кодом, например, на Codepen.io:
    Ответ написан
    2 комментария
  • Как из массива строк получить те, у которых длина равна 5?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Целиком elem не нужен — только его свойство length (длина)

    const arr = ['katya', 'Karolina', 'Vladislav', 'Anna', 'Habr', 'Lepra'];
    console.log(
      arr.filter(({ length }) => length === 5)
    );
    Ответ написан
    Комментировать
  • Как оптимизировать нерекурсивный обход дерева?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    судя по данным, тут не бинарное дерево, и в свойстве v всегда число ("v" for "value"),
    а в свойстве c — опциональный массив дочерних элементов ("c" for "children").

    Проверка if (last && Array.isArray(last.v)) { тут, видимо, лишняя.
    Хотя самый первый раз как раз v это массив.. Так что нужна, если данные именно такие.

    Как и if (last && typeof last.c === 'object') {, за исключением корневого свойства, где это таки объект.

    По мелочи — все 4 проверки одинаково проверяют наличие last

    Оптимизировать что-то — зачем? Тут лишняя операция, если только сортировка результатов, скрывающая порядок обхода.
    Ответ написан
    Комментировать