Ответы пользователя по тегу JavaScript
  • Можно как-то отрефакторить данный код?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Если правильно понял, в массиве лежит «кольцо» точек. Первая соседствует с последней.
    И к любой выбранной точке надо добавить две новые, слева и справа, с усреднёнными с соседями координатами.
    function addPointCenter(index) {
      const avg = (a, b) => (a + b) / 2;
      const midPoint = (p1, p2) => ({ lat: avg(p1.lat, p2.lat), lng: avg(p1.lng, p2.lng) });
      const insert = (index, point) => latlng.splice(index, 0, point);
    
      const { length } = latlng;
      const current = latlng[index];
    
      const indexLeft = (index - 1 + length) % length;
      const pointLeft = midPoint(current, latlng[indexLeft]);
    
      const indexRight = (index + 1) % length;
      const pointRight = midPoint(current, latlng[indexRight]);
    
      insert(index + 1, pointRight);
      insert(index, pointLeft);
    
      drawMarkers();
    }
    Ответ написан
    1 комментарий
  • Как сделать динамическую длину ключей для обращения к объекту?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Есть готовые модули, например, rhalff/dot-object для работы с нотацией свойств через точку:
    dot.str('qna.habr.com', 'value', this.data);
    /* this.data: 
    {
      qna: {
        habr: {
          com: "value"
        }
      }
    } */

    Установка: npm install dot-object --save
    Ответ написан
  • Как вызвать следующий interval после смены флага?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Можно «подглядывать» за изменениями свойства объекта.
    Предлагаю не переменную isLoading, а свойство некого объекта изменять: flags.isLoading = false;

    const PERIOD = 5000;
    let timeout;
    
    const action = () => {
      console.log('Action!');
      // this.switchNextTab()
      clearTimeout(timeout);
      timeout = setTimeout(action, PERIOD);
    };
    
    const flags = {
      _isLoading: false,
    
      set isLoading(value) {
        this._isLoading = value;
        if (!value) {
          // isLoading стал false
          action();
        }
      },
    
      get isLoading() {
        return this._isLoading;
      },
    };
    
    timeout = setTimeout(action, PERIOD);
    
    // где-то в коде:
    flags.isLoading = true;
    // ...
    flags.isLoading = false; // тут же выполнится action
    Ответ написан
    Комментировать
  • Нужно в js создать таблицу 10 на 10 чтобы 1 шли по диагонали. Остальное 0?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Когда там единицы и нули, я думаю о битах )
    Альтернативная диагональ:
    10 чисел, где включен только 1 бит – в двоичном представлении
    001
    010
    100
    Из каждой цифры (0 или 1) делается ячейка таблицы. Строки оборачиваются в тег tr, и всё это обёртывается в table. Полученный HTML вставляется в страницу.
    Ответ написан
    Комментировать
  • Как обернуть в теги некоторые слова в HTML?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Попробовал сделать через DocumentFragment, рекурсивный обход текстовых Node
    и обёртку найденных слов с помощью Range.surroundContents()

    Получилось как-то переусложнённо. Но наверное лучше, чем регуляркой HTML разбирать: не станет менять слова в атрибутах тегов. Раз уж это разметка, можно работать с DOM.
    Слабое место – не обошлось без регулярного выражения для поиска слов. Т.к. там кириллица, привычные \b для границы слова не работают, пришлось заглядывать впрёд-назад, и регулярка вышла некороткая.

    Криво-длинно, но работает:

    Из исходного HTML делается DocumentFragment — как DOM полноценного документа. Перебираются его узлы. Если узел не-текстовый, рекурсивно перебираем его дочерние узлы.
    В текстовых узлах ищем искомые слова.

    Найденное слово (по одному за раз) заменяется на обёртку с этим словом.
    Вместо 1 исходного текстового узла, у нас становится уже 3: текст-элемент-текст.
    Далее поиск повторяется с хвостовым остатком текста – третьим (текстовым) узлом, пока в тексте не останется искомых слов для замены.

    Решение не лаконичное и не простое. Если возникнут вопросы, пишите, постараюсь объяснить.
    Ответ написан
    7 комментариев
  • Как сравнить переменную с ключами объекта?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Можно отсортировать по ключам по убыванию, и найти find() первый, где данное число окажется больше ключа.
    Если не нашлось такое, отдать последнее значение (с минимальным ключом).
    что за entries ?
    Object.entries(obj) делает из объекта массив пар [[ключ, значение], ... ] — 
    [
      [50: "3500"],
      [100, "6000"], 
      ...
    ]

    const findRange = n => {
      const obj = { 
        50: "3500", 
        100: "6000", 
        200: "8000", 
        300: "10500", 
        500: "13000", 
        501: "индивидуально" 
      };
      const lookup = Object.entries(obj).sort(([a], [b]) => b - a);
    
      return (lookup.find(([k, v]) => Number(k) <= n) ?? lookup.pop())[1];
    };
    
    findRange(49) // "3500"
    findRange(99) // "3500"
    findRange(100) // "6000"
    findRange(500) // "13000"
    findRange(501) // "индивидуально"
    Ответ написан
    Комментировать
  • Как правильно сделать зависящие друг от друга сетевые запросы с помощью Promise.allSettled?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Просто склейте их в одну цепочку. Что-то типа:
    макароны
    const state = {};
    const getJSON = response => response.json();
    getAuth()
      .then(getJSON)
      .then(({ id }) => {
        state.id = id;
        return getUser(id);
      })
      .then(getJSON)
      .then(user => {
        state.user = user;
      })
      .then(() => getOrder('users', state.id))
      .then(getJSON)
      .then(({ order }) => state.order = order)
      .catch(console.error)
      .finally(() => console.log("all done", state));


    возможна ли реализация данной логики с помощью Promise.allSettled?

    Нет. allSettled() параллелит выполнение всех промисов и дожидается, чтобы «все расселись» – будь то resolve или reject.

    Хотя, пожалуй, тут можно последние два запроса запараллелить. Они оба нуждаются сначала в авторизации, а затем могут идти независимо-одновременно.
    const state = {};
    
    // подготовка
    const getJSON = response => response.json();
    const getUser = id =>
      fetchUser(id)
        .then(getJSON)
        .then(({ user }) => (state.user = user));
    const getOrder = id =>
      fetchOrder('users', id)
        .then(getJSON)
        .then(({ order }) => (state.order = order));
    
    // поехали
    getAuth()
      .then(getJSON)
      .then(({ id }) => {
        state.id = id;
        return Promise.allSettled([getUser(id), getOrder(id)]);
      })
      .catch(console.error)
      .finally(() => console.log('all done', state));
    Ответ написан
    Комментировать
  • Как решить задачу по JS?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    function count(min, max) {
      let counter = 0;
      for (let n = min; n <= max; n++) {
        if (!n.toString(10).includes('5')) counter++;
      }
      return counter;
    }
    
    count(4, 17)  // 12
    Определять, есть ли в числе цифра 5 можно и иначе, без преобразования в строку, но так короче )
    Ответ написан
    Комментировать
  • Как подставить нули к дублируемому инпуту?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Если в поле только цифры – сделать число Number(value) и методом toFixed(2) гарантировать 2 знака после запятой.
    Если в поле только пробелы или пусто, нарисовать подчёркивание.
    Применить ко всем трём полям одинаково:
    Ответ написан
    Комментировать
  • Как вывести фото, текст и кнопки в телеграмме в одном сообщении?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    попробуйте так:
    сtx.telegram
      .sendPhoto(
        ctx.chat.id,
        ctx.message.photo[0].file_id,
        { caption: s, parse_mode: 'HTML', reply_markup: markup }
      )

    Наскоро посмотрел: вроде бы, третий параметр telegram.sendPhoto() (исходник) передаётся через функцию fmtCaption() (код) в api тележки, и доп. параметры помимо caption должны пройти без изменений.
    Ответ написан
  • Как сделать паузу в js вычислениях, чтобы отрисовать изменения?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Как вариант, всю тяжёлую работу передать в web worker.

    1. показать лоадер
    2. вынуть из localStorage данные, и отправить их в worker
    3. спиннер крутится, воркер в другом треде считает
    4. воркер наконец пришлёт ответ: большой кусок готового HTML
    5. вставить весь полученный HTML разом
    6. скрыть спиннер
    Ответ написан
    Комментировать
  • Как добавить в js стили классам как в css?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Переписать то же, короче, можно примерно так:
    (names =>
      names.forEach(name => {
        document.getElementsByClassName(name).forEach(({ style }) => {
          style.display = name;
        });
      }))(['block', 'inline-block', 'inline', 'flex', 'inline-flex', 'table', 'inline-table', 'table-caption']);


    Или можно «просто взять, и ..» добавить в head документа сгенерированный CSS:
    Ответ написан
    2 комментария
  • Зачем две функции?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Что происходит
    Каждому элементу коллекции peresortDel вешается слушатель события клика.

    Каким образом
    1. Внутрь forEach() передается функция, которую применят к каждому элементу.
    2. Слушатель события click — тоже функция. Другая, чем в п.1, поэтому их тут.. две.

    Как быть
    Чтобы короче — можно повесить всего один слушатель не на каждый элемент, а на общего родителя где-то выше. Это позволит сэкономить на функции в forEach(), и не создавать новую функцию для каждого элемента.
    commonParent.addEventListener('click', ({ target }) => {
      if (!target.classList.contains("tot-samyj-class")) return;
      target.style.display = "none";
    });
    Подробнее не подскажу, т.к. в вопросе нет действующего примера или хотя бы разметки.
    Ответ написан
    Комментировать
  • Как решить данную задачу?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Т.е. надо все значения умножить на некий общий коэффициент так,
    чтобы сумма их стала 360.
    const normalize = obj => {
      const result = { ...obj }; // shallow copy
      const k = 360 / Object.values(result).reduce((acc, c) => acc + c);
      for (const prop in result) result[prop] *= k;
      return result;
    };
    Ответ написан
    Комментировать
  • Почему возвращается true а не 5?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Ошибка тут:
    оператор ИЛИ возвращает последнюю правду, а по факту дает True, а не 5. Ведь 5 в этом контексте тоже true

    На самом деле ИЛИ || возвращает первую правду. И дальше не проверяет. Т.е. 3 > 1 === true

    Ещё тут важно, что у || приоритет ниже ↓, чем у && ↑. Очерёдность выполнения:
    5 === 5 && 3 > 1 || 5
    (5 === 5 && 3 > 1) || 5
    // && проверит, чтобы все были true
    // и вернёт последний, т.е. вернёт 3 > 1 === true
    // || увидит, что уже есть true и вернёт его, не проверяя 5

    Позавчера, как раз, отвечал на похожий вопрос. Вам же.
    Ответ написан
    5 комментариев
  • Литерал объекта и блок инструкций. Есть ли связь?

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

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

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

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

    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, дальше проверять не пришлось
    Ответ написан
    Комментировать
  • Как получить ссылку через 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 ]
    Ответ написан