Ответы пользователя по тегу JavaScript
  • Как разобраться с this в javascript окончательно?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Вот была неплохая статья на Хабре с попытками разобраться с this в JavaScript.
    • Первый случай, метод объекта – при непосредственном получении и вызове делает этот объект this'ом.
    • Второй же случай — функция, внутри другой («да»), не стрелочная, «нет», «нет» ... «нет» — this равен глобальному объекту. Если включить строгий режим, вместо Window получим undefined.

    Статья не столько объясняет (объясняет под спойлерами Комментарий), сколько предлагает алгоритм рассуждений, «таблицу умножения» для запоминания — чтобы предсказывать значение this.
    Ответ написан
    7 комментариев
  • Как вызвать функци после setTimeout?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Как-нибудь так:
    const delay = seconds => new Promise(res => setTimeout(res, 1000 * seconds));
    
    const parse = async () => {
      // ...
    };
    
    const main = async () => {
      await delay(10); // подождать 10 секунд
      await parse();   // что-то там спарсить
      reloadPage();    // перезагрузить страницу
    };
    
    window.addEventListener('load', main);
    Ответ написан
    7 комментариев
  • Из-за чего элементы массива возвращают 3?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Объявленная через устаревший var переменная i всплывает наверх, видна отовсюду и поёт похабные частушки сохраняет видимое для всех созданных функций единое значение 3 по окончании цикла. Это не то, что задумано.

    Использование спортивных, современных const и let чудесным образом исправляет досадное недоразумение:
    const arr = []; // ведь сам массив не планируется заменять
    
    for (let i = 0; i <= 2; i++) { // главное: i теперь видна только внутри цикла
       arr[i] = function () {
          console.log(i);
       };
    }
    
    arr[0](); // 0
    arr[arr.length - 1](); // 2
    в исходном коде только лишь заменили var на const (не так важно) и let (вот это изменило всё!).

    Можно использовать и стрелочную функцию:
    const arr = [];
    for (let i = 0; i <= 2; i++) {
       arr[i] = () => console.log(i);
    }
    Ответ написан
    Комментировать
  • Как элементы массива сделать значениями объекта?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Короткий способ: создание объекта из пар [ключ, значение] методом fromEntries():
    Object.fromEntries(arr.map((v, i) => [i + 1, v]))

    как это работает
    Из исходного массива методом map() создаётся новый, где каждый элемент это тоже массив:
    [ [1, 'a'], [2, 'b'], ... ]
    Такой массив массивов годится для передачи в Object.fromEntries() для получения искомого объекта.
    Ответ написан
    Комментировать
  • Нужно обьект записать в БД MySQL, как сделать?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    попробуйте так
    - let query = "INSERT INTO user_records.users (id, name, username, email, city, phone) values?";
    + let query = `INSERT INTO user_records.users
    +   (id, name, username, email, city, phone)
    +   VALUES (?, ?, ?, ?, ?, ?)
    + `;
    Ответ написан
  • Как вставить тег br, чтобы числа выводились с новой строки?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Можно таблицу собрать из этих чисел:
    const arr = [ 1, 2, 3, 4, 5, 6, 7] ;
    const html = `<table><tbody>
    ${ arr.map(n => `<tr><td>${n}</td></tr>`).join() }
    </tbody></table>`;
    
    document.write(html); // вообще так лучше не делать

    правильнее

    ..создать элемент, в него засунуть HTML и элемент вставить в DOM-дерево
    const table = document.createElement('table');
    const rows = arr.map(n => `<tr><td>${n}</td></tr>`).join();
    table.innerHTML = rows;
    document.body.appendChild(table);

    Ответ написан
    Комментировать
  • Почему везде используют const вместо let в JS?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Редактор кода домой не отпустит, пока переменную, которую нигде не изменяют,
    не объявить вместо let — const )

    Иммутабельность должна быть явной!

    При чтении кода гораздо удобнее для понимания изначально знать, что от константы сюрпризов не ждать.
    А переменную стоит посмотреть внимательнее: где, как, зачем и на что меняют.
    Ответ написан
    Комментировать
  • Как группировать объекты по заданному свойству с помощью reduce?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Обращение к lodash.has() тоже навеное, недопустимо в задании?

    Ошибка в том, что ключом назначаете criteria,
    а надо значение этого свойства очередного юзера: key = user[criteria]
    – так, если в criteria строка "mark", переменная key получит значение 3 у первого юзера.

    spoiler
    в одну нечитаемую строку:
    const groupBy = (usersArr, criteria) => usersArr.reduce((acc, user) => ((acc[user[criteria]] ??= []).push(user), acc), {});
    Ответ написан
  • Как удалить гласные в строке?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Под капотом движок регулярок довольно большой и «тяжёлый». В этой задаче можно обойтись массивами и их эффективными методами.

    Разбить начальную строку на массив букв, отфильтровать его, сохранив только не-гласные, склеить:
    function disemvowel(str) {
      const vowels = ['a', 'e', 'i', 'o', 'u'];
      return str
        .split('')
        .filter(char => !vowels.includes(char))
        .join('');
    }
    
    console.log(disemvowel('Twinkle, twinkle, little star, How I wonder what you are.'));
    // Twnkl, twnkl, lttl str, Hw I wndr wht y r.
    Ответ написан
    1 комментарий
  • Как отфильтровать ненужные записи?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Object.values(data)
      .flatMap(({ person }) => Object.values(person))
      .filter(({ age }) => age === 18)
    
    // [ { name: "alex", age: 18 } ]
    Ответ написан
    2 комментария
  • Как сверить id из двух массивов?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    const hasItemById = (arr, searchId) => arr.some(({ id }) => id === searchId);
    
    hasItemById(arr, arr2[0].id) // true
    hasItemById(arr, 100) // false
    Ответ написан
    Комментировать
  • Возникла проблема, не могу понять как выполнить условие задачи?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    забыли уменьшать счётчик attempt на каждой итерации

    -    while(remainingLetters > 0 && attempt > 0) {
    +    while(remainingLetters > 0 && attempt-- > 0) {
    Ответ написан
  • Как возвести в квадрат каждый элемент в массиве?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Минутка лишних усложнений и новых концепций.

    В JavaScript примитивные значения (числа, например) копируются/передаются «значением», не сохраняя никакой связи с оригиналом. А объекты (например, массив) передаются «ссылкой» на оригинал.

    Судя по неудачной попытке, был расчёт, что изменив elem, изменится и его «оригинал» – элемент массива. Но нет. Число возвели в квадрат, но в массиве всё осталось по-прежнему.

    Будь elem не числом, а объектом, трюк сработал бы.
    пример
    let arr = [ {x: 1},  {x: 2},  {x: 3},  {x: 4},  {x: 5} ];
    
    for (let elem of arr) {
      elem.x = elem.x ** 2;
    }
    // [ {"x": 1}, {"x": 4}, {"x": 9}, {"x": 16}, {"x": 25} ]


    А в случае с примитивами (числом, строкой) надо как-то вложить квадратное значение обратно в массив в нужную ячейку. Этого-то и не хватает в коде.
    Ответ написан
    Комментировать
  • Не могу найти ошибку в условии, в консоли выводит 0, что делать?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Пара ошибок:
    1. for .. in перебирает имена свойств объекта ('a', 'b', 'c', ...)
      а тут требуются значения (10, 20, 30, ...) – значения перебирает for .. of
    2. значения — числа. Чтобы забрать первую букву (цифру) нужна строка. Поэтому надо каждое значение сначала сделать строкой. Например, методом toString():
      const num = 10; // число
      num.toString() // результат "10" – строка текста
    Поправьте эти два момента и всё наладится.

    Можно и в одну нечитабельную строку:
    Object.values(obj).reduce((acc, c) => acc + c.toString().match(/^[12]/), 0) // 2
    но здесь используется тяжёлый механизм регулярных выражений, хотя вполне можно без него; и неочевидное приведение типа Boolean к Number ради краткой записи.
    Ответ написан
    Комментировать
  • Как добраться до вложенного объекта в массиве?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Буквально в лоб добраться до пола первой подруги или друга первого юзера можно так:
    users[0].friends[0].gender

    Для решения задачи сначала нужно вытащить из каждого элемента массива (из каждого user) только его свойство friends (массив). Был объект user, стал только его массив friends. Методом map()

    Причём, в массиве friends методом filter() надо оставить только тех, где gender === 'female'

    Так из начального массива users получится массив массивов – иногда пустых, иногда с девушками.
    Массив массивов сделать просто-массивом, без пустышек, можно методом flat()

    Ну а потом можно эти два последовательных метода map(fn).flat() заменить на один, делающий то же самое, flatMap(fn)

    spoiler
    users.flatMap(({ friends }) => friends.filter(({ gender }) => gender === 'female'));
    
    // [ {"name":"Mira","gender":"female"}, {"name":"Aria","gender":"female"}, {"name":"Keit","gender":"female"} ]
    Ответ написан
    1 комментарий
  • Как улучшить производительность данного кода?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    не нужно на каждой позиции составлять окно заново.

    Заполнили окно в самой левой позции. Посчитали его "кардинальность" (число уникальных).

    Далее на каждом шаге удаляется 1 элемент слева и добавляется 1 элемент справа. Смотрим, изменилась ли кардинальность:
    - удаляемый элемент ещё есть в оставшихся? Нет – значит мы уменьшили кардинальность на 1.
    - то же с добавляемым: уже есть такой в середине окна? Нет – значит, увеличили кардинальность на 1.

    Такое решение прокатило и по перформансу, хотя там есть вложенные мини-циклы для поиска удаляемого/добавляемого значений в остающемся огрызке. Наверняка, есть более элегантные решения.
    spoiler
    function countContiguousDistinct(k, arr) {
      let cardinality = 0;
      for (let i = 0; i < k; i++) {
        if (i === arr.indexOf(arr[i])) cardinality++;
      }
      const result = [cardinality];
      
      const isNotInWindow = (value, arr, start, finish) => {
        for (let j = start; j < finish; j++) {
          if (arr[j] === value) return false;
        }
        return true;
      }
      
      for (let i = 0; i < arr.length - k; i++) {
        const L = arr[i];
        const R = arr[i + k];
        if (L !== R) {
          if (isNotInWindow(L, arr, i + 1, i + k)) cardinality--;
          if (isNotInWindow(R, arr, i + 1, i + k)) cardinality++;
        }
        result.push(cardinality);
      }
      
      return result;
    }
    Ответ написан
    Комментировать
  • Как спарсить HTML таблицу в массив объектов?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Можно создать элемент template, вставить в него HTML строку, и забрать из него DocumentFragment.

    Там уже найти строки-ячейки как в обычном документе:
    const htmlString = `<table>
      <tr><td>Apple</td><td>12</td></tr>
      <tr><td>Banana</td><td>34</td></tr>
    </table>`;
    
    const tmpl = document.createElement('template');
    tmpl.innerHTML = htmlString;
    const df = tmpl.content;
    
    const rows = df.querySelectorAll('tr');
    const result = [];
    rows.forEach(row => {
      result.push([...row.children].map(td => td.textContent));
    });
    
    result // [["Apple","12"],["Banana","34"]]
    Ответ написан
    Комментировать
  • Как разбить текст на теги?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    можно создать временный элемент <template>, вставить в него этот HTML,
    и забрать из него DocumentFragment

    Фрагмент — это примерно как DOM-документ, его можно рекурсивно обойти через свойство children

    Например, в строке содержится такой HTML:
    <div>
      <p>Text</p>
      <ul>
        <li>Apple</li>
        <li>Banana</li>
      </ul>
    </div>
    И примерно такой код:
    const tmpl = document.createElement('template');
    tmpl.innerHTML = msg; // строка с HTML
    const df = tmpl.content; // DocumentFragment
    
    df.children // массив из одного элемента: наружний div
    df.children[0].children // массив с двумя эл.: параграфом и списком
    df.children[0].children[1].children[1].textContent // "Banana"
    Ответ написан
    2 комментария
  • Как заменить каждый из символов подстроки на звездочку?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Если с минимумом изменений, то так:
    -        field = field.replace(badWords[i], '*');
    +        field = field.replaceAll(badWords[i], '*'.repeat(badWords[i].length));
    звёздочку повторить столько раз, сколько букв в заменяемом слове.
    Ответ написан
    6 комментариев
  • Приемы рендера компонентов вместо плейсхолдеров внутри строки во Vue?

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

    Строку разбить на узлы: текстовые и компоненты. Сделать какой-то минимальный компонент для просто-текстовых кусков.

    Например, из строки 'lorem ipsum dolor [placeholder|1] sit amet [placeholder|2]'
    сделать массив
    [
      ['text', 'lorem ipsum dolor'],
      ['copy', 1],
      ['text', 'sit amet'],
      ['copy', 2],
    ]
    если я правильно понял, что каждый из плейсхолдеров копирует значение после вертикальной черты – первый копирует 1, второй 2.

    В темплейте перебрать этот массив примерно так
    <template v-for="item in items">
      <component :is="text" v-if="item[0] === 'text'">{ item[1] }</component>
      <component :is="copy" v-if="item[0] === 'copy'" :value="item[1]" />
    </template>
    Ответ написан