Ответы пользователя по тегу JavaScript
  • Как подключить сторонний polyfill (classlist-polyfill) в Babel?

    @ned4ded
    Верстка, Фронтенд
    Во первых, classlist-polyfill - не бабель-плагин, сл-но его нельзя добавить в бабель.

    Во вторых, classlist polifill - это полифил для dom браузера, а не для js (разница в том, что dom - это апи, с которым можно взаимодействовать по средствам запуска js в браузерном окружении). Бабель полифилит js, но не dom.

    В третьих, чтобы dom-полифил заработал в браузере, его нужно в этом браузере запустить, для этого его нужно импортировать перед тем скриптом, который будет этим полифилом пользоваться. Бабель - это транспайлер, он не занимается конкатенацией js-модулей в один файл, для этого нужно использовать вебпак, роллап или еще какой-либо бандлер.

    Подведем итог, тебе нужно сначала настроить вебпак, который будет собирать модули js в один файл; потом импортировать в script.js полифил для браузера; потом нужно прогнать script.js через бабель, чтобы получить заполифиленный js (этим занимается, например, вебпак, он собирает скрипты в один или несколько файлов, прогоняет файлы через транспайлер).
    Ответ написан
  • Когда передается функция как аргумент мы получаем на нее ссылку или копию самой функции?

    @ned4ded
    Верстка, Фронтенд
    ссылку,

    раньше на хекселете курс по программированию на js использовал функциональный подход, можешь попробовать обратиться к их материалам.

    частично на книге SICP был основан это курс, можешь попробовать обратиться к ней, в исходниках к этой книге используется функциональный язык Scheme (Structure and Interpretation of Computer Programs - Abelson, Sussman).

    не уверен, что конвейер и композиция имеют прямое отношение к фп.
    Ответ написан
  • Как складывается отрицание (!) и пустой массив?

    @ned4ded
    Верстка, Фронтенд
    Очень спорный вопрос для собеседования, откровенно говоря.

    Операторы сложения и вычитания имеют унарную версию: употребление такого оператора перед значением конвертирует значение в числовое.
    console.log(+"1"); // prints 1
    console.log(+"s"); // prints NaN


    В случае +[], что эквивалентно Number([]), массив преобразуется в 0. Соответственно в операции !+[] используется 2 оператора подряд (например, как !! во второй части выражения), сначала происходит преобразование массива в ноль с помощью унарного оператора сложения +[] и конвертация нуля в true с помощью оператора !. В первой части выражения получаем true.

    Массив рассматривается как truthy значение, сл-но двойной оператор not во второй части выражения дает значение true (грубо говоря, это способ конвертировать массив в булевый тип).

    В итоге (!(+[])) + (!![]) (я позволил себе расставить скобки, чтобы был более очевиден порядок выполнения), конвертится в true + true, что конвертится в 1 + 1, собственно, вот и ваша двойка.

    ps Я хз, люди, которые составляют такие задачи, видимо, просто глумятся.

    более наглядная последовательность преобразований:
    !+[] + !![];
     
    /* +[] converts to 0 */
    
    !0 + !![];
    
    /* !0 converts to true */
    
    true + !![];
    
    /* ![] converts to false */
    
    true + !false;
    
    /* !false coverts to true */
    
    true + true;
    
    /* both true values convert to numbers */
    
    1 + 1;
    
    /* equals 2 */


    Небольшой апдейт. На немой вопрос "почему конвертация массива в число дает 0, а конвертация массива в булевой тип дает true, тогда как true != 0?" можно ответить след. образом:
    а) Почему конвертация массива в число дает 0? Массив является объектом в js, для конвертации объекта в число его нужно сначала конвертировать в примитив. В данном случае для простого объекта вызывается метод toString(). Метод toString() на массиве возвращает конкатенацию строковых значений массива, что для пустого массива дает пустую строку "". Подробнее о логике конвертации объекта в примитив в спеке, ecma-262/5.1/9.1. Далее конвертируется строка в число, что для пустой строки равно 0, подробнее пункт 9.3.1 спеки.

    б) Почему конвертация массива в булевый тип дает true? Простой ответ: согласно пункту 9.2 спецификации. Если поразмышлять, то скорее всего это означает, что объект существует (а он не может не существовать, если существует ссылка на него).
    Ответ написан
  • Как иметь постоянно актуальные данные?

    @ned4ded
    Верстка, Фронтенд
    Для этого используются websocket'ы и паттерн message broker для бека. Например, реализованный с помощью либы rabbitmq для php.

    Фронт подписывается на обновления через сокеты, бек отправляет уведомления о новых объектах, при получении сообщения фронт обновляет свои данные.

    10000к плоских объектов - это не много, но если там сложная вложенная структура с большое количеством полей и вы проводите какие-то операции затратные над объектами, то лагать будет, если вы не будете обрабатывать их в фоне.
    Ответ написан
  • Как ускорить выполнение JavaScript в браузере? Как распаралелить JavaScript?

    @ned4ded
    Верстка, Фронтенд
    Распараллелить - нет, но вы можете чанковать текст и парсить его чанки асинхронно, что освободит основной поток.

    const arr = [1, 2, 3, 4, 5];
    
    const rec = (theArr) => {
        const [first, ...rest] = theArr;
    
        if (!first) return;
    
        setTimeout(() => {
            /* do some parsing, example: */
            if ([3, 4].includes(first)) alert('found it!');
    
            return rec(rest);
        }, 0);
    };
    
    rec(arr);
    Ответ написан
  • Как правильно подключить ExtractTextPlugin?

    @ned4ded
    Верстка, Фронтенд
    1. Вы забыли добавить инстанс самого плагина в массив plugins

    plugins: [
        new HtmlWebpackPlugin({ template: 'src/index.html'}),
        new ExtractTextPlugin("styles.css")
      ]


    В самом репозитории плагин помечен как deprecated, т.е. устаревший и неподдерживаемый. Воспользуйтесь, если есть такая возможность, плагином MiniCssExtractPlugin

    2. "Подскажите как её решить и чтобы результирующий css импортировался в simple-piskel-clone/src/index.js ?"

    Это невозможно, вебпак при импортировании стилей просто строит граф зависимостей и через HtmlWebpackPlugin добавляет линк на него в html файл. Т.е. вам нужно импортировать в js файл сам базовый .scss файл, тогда вебпак при бандле его распарсит по заданным условиям, скомпилирует в style.css и подгрузит его на страницу. Ну или если вы просто делаете сборку без HtmlWebpackPlugin, то вручную импортируйте собранный css в запрашиваемую клиентом страницу.
    Ответ написан
  • Почему выбивает ошибку в функции?

    @ned4ded
    Верстка, Фронтенд
    Добрый день.

    Метод getItem возвращает либо Products, либо undefined, если продукт не найден. Сделайте терминальное условие и укажите строгую типизация для используемого массива далее.

    addToCart = (id: number) => {
      let tempProduct: Products[] = [...this.state.products];
      const item = this.getItem(id);
      if(item === undefined) {
        // ... инструкция при возникновении терминального условия, например, ошибка
        return;
      }
      const index = tempProduct.indexOf(item as Products); // строгая типизация для item
            
      // ...
    };


    Возможно, если вы укажите тип возвращаемого значения, то не потребуется терминальное условие (но это нужно проверить, я так навскидку не могу утверждать со 100% уверенностью). Такой подход подвержен багам при исполнении js.

    getItem = (id: number): Products => {
      return this.state.products.find(item => item.id === id);
    };


    BTW, я бы не стал называть на вашем месте тип Products во мн. ч. Просто Product, т.к. по сути это единичная сущность.
    Ответ написан
  • Почему объект доступен из замыкания?

    @ned4ded
    Верстка, Фронтенд
    Добрый день.

    Вы удаляете ссылку на объект в переменной user, но не сам объект и не саму абстрактную ссылку (их может быть много). В js нельзя удалить объект, его удалением занимается garbage collector, вы можете удалить все ссылки и тогда объект будет удален из памяти.

    При передачи объекта в замыкание, там сохраняется ссылка на него, а не на переменную user.

    Собственно, даже чуть более простой код будет работать точно так же:
    let object = { test: 'hey' }
    
    let another = object
    
    object = null
    
    console.log(another)
    // { test: 'hey' }
    Ответ написан
  • Правильно ли обворачивать весь скрипт в async?

    @ned4ded
    Верстка, Фронтенд
    Сделать можете, но вне анонимной функции код будет синхронный. Если речь идет об оборачивании всего скрипта и у вас 1 файл с 200-300 строками, то вполне нормально, как по мне. Если вы хотите обернуть angular приложение, то чутье мне подсказывает, что вы запутаетесь и / или возникнут какие-нибудь проблемы с импортами (не проверял). Более того, вам нужно ловить reject внутри такой анонимной функции через try-catch на верхнем уровне.

    Но, как по мне, async нужно использовать только там, где он действительно упрощает работу, для многих вещей вполне подойдут promise, а где-то и колбеки.
    Ответ написан
  • Стоит ли переходить с var на let и const?

    @ned4ded
    Верстка, Фронтенд
    Это значительно ровно настолько, насколько вы обеспокоены удобочитаемостью и организованностью вашего кода.

    Рекомендую ознакомиться, если найдется время airbnb codestyle

    Есть, конечно, и практическое значение в использовании const, let и иных фишек es6+, включая иммутабельность значений примитивов первого и скоупов обоих, но раз вы не сталкиваетесь в повседневности с такими проблемами, которые помогают решать константы и блочные переменные, то и знать вам о них, наверное, ни к чему?)
    Ответ написан
  • Как сделан скролл без скроллбара?

    @ned4ded
    Верстка, Фронтенд
    Он не скрыт, а отключен для вебкита. Если вы зайдете в фаерфокс, то увидите скролл.

    Собсвтенно, там отключает скролл псевдоэлемент ::-webkit-scrollbar;

    Вот код:
    * ::-webkit-scrollbar {
        display: none;
    }


    Проблема в том, что скролл не ререндерится после дизейбла данного свойства в хроме, а остается невидимым. Видимо, какой-то баг. Если изменить стили таким образом:
    * ::-webkit-scrollbar {
        display: block;
        background-color: hsl(240, 100%, 50%);
    }


    то увидите синюю полоску справа.
    Ответ написан
  • Почему запись .setAttribute('style', 'text-align:center;') неправильная?

    @ned4ded
    Верстка, Фронтенд
    td = document.createElement('td').setAttribute('colspan', '6').setAttribute('style', 'text-align:center;');


    это не jquery, после вызова первого метода setAttribute не возвращается $-элемент (т.е. отсутствует имплементированый в $ method chaining ), но возвращается undefined.

    вам нужно написать:
    const td = document.createElement('td');
    td.setAttribute('colspan', '6');
    td.setAttribute('style', 'text-align:center;');
    // console.log(td);
    // <td colspan="6" style="text-align:center;"></td>
    
    // ps я бы написал через сеттер 
    // td.style.textAlign = 'center';
    // td.colSpan = 6;
    Ответ написан
  • Как сделать чтобы EventListener не работал некоторое время?

    @ned4ded
    Верстка, Фронтенд
    На мой взгляд, самый верный вариант - снимать листнер на время действия скролла, т.к., с точки зрения оптимизации, браузер не будет чекать во время анимации даже булевый флаг:
    (() => {
      const scrollingFn = () => {
       window.removeEventListener('wheel', scrollingFn);
    
       $.scrollTo($('.something'), 1000, {
         onAfter: () => window.addEvenListener('wheel', scrollingFn),
       });
      }
    
      window.addEventListner('wheel', scrollingFn);
    })();
    Ответ написан
  • Почему не работает фильтр по свойствам класса?

    @ned4ded
    Верстка, Фронтенд
    В целом, вы, похоже, просто запутались в в контексте и ссылках:

    name.filter(product => name === undefined || product.name === this.name); 
    // в этом месте вы пытаетесь отфильтровать переданную опцию name, которая является строкой "anything 4",
    // так же контекст this.name - будет undefined, потому что в данном случае вы передаете стрелочную функцию, 
    // this которой будет ссылаться на объект, в котором она была создана, т.е. - на Shop. У Shop нет свойства name
    // правильный вариант: 
    const filtered = this.products.filter(product => {
     return product.name === undefined || product.name === name
    });


    Все последующие функции вам нужно отредактировать по тому же принципу.

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

    class Shop {
        constructor(products) {
            this.products = [];
        }
    
        addProduct(newProduct) {
            this.products.push(newProduct);
        }
    
        filterProduct(fn) {
          return this.products.filter(fn);
        }
        
    }
    const shop = new Shop();
    shop.addProduct(new Product("product 1", 1, 2000));
    shop.addProduct(new Product("item 2", 2, 100));
    shop.addProduct(new Product("some 3", 3, 500));
    shop.addProduct(new Product("anything 4", 4, 1000));
    
    const filtered = shop.filterProduct((product) => product.name === 'anything 4' && product.count > 3 && product.price >= 500);
    
    // console.log(filtered): [ Product { name: 'anything 4', count: 4, price: 1000 } ]


    На самом деле, есть еще много мелких моментов:
    1) С данными лучше работать функционально и не допускать добавления, удаление и проч. операции в текущем объекте, т.е. объект должен быть иммутабельным. При добавлении товара нужно создавать новый объект Shop.

    2) Вытекает из первого - зачем вам в конструкторе Shop сигнатура products, когда вы ее не используете? По сути, ее должно использовать именно для сохранения передаваемого массива продуктов.

    3) В объектах, работающих с данными, особенно когда идет фильтрация, сортировка и проч операции, лучше сразу имплементировать fluent-interface.
    Ответ написан
  • Как проверить, есть ли объект в массиве?

    @ned4ded
    Верстка, Фронтенд
    const arr = [
      {lat: 52.289591, lng: 21.030541},
      {lat: 52.289591, lng: 21.030541},
      {lat: 51.09464, lng: 17.019549},
    ];
    
    const uniq = arr.filter(
      (el, i, array) => !array
        .slice(0, i)
        .find(({lat, lng}) => lat === el.lat && lng === el.lng)
    );


    https://repl.it/@ned4ded/ElementaryVeneratedTelevision
    Ответ написан
  • Слайдер пролистывает чере один слайд?

    @ned4ded
    Верстка, Фронтенд
    Добрый вечер. Файл app.js, содержащий исполняющий код для этого слайдера, подключен в двух местах. Полагаю, что удаление одной из ссылок на него ликвидирует проблему, т.к. eventlistner вешается на кнокпи дважды.
    Ответ написан
  • Как сделать слайдер, переключающийся по таймеру?

    @ned4ded
    Верстка, Фронтенд
    setTimeout() - функция однократного действия. Используйте setInterval() или рекурсию.

    Можете почитать тут.
    Ответ написан
  • Что не так с этим кодом?

    @ned4ded
    Верстка, Фронтенд
    Все просто, ты пытаешься работать с html data=* атрибутом через .data() метод jquery, что не совсем одно и тоже.

    Сделай это через метод .attr(). Например, если исправить код вот здесь:

    var action = $(this).attr('data-action');

    то твой пример заработает (т.е. id у тебя нигде не используется).

    Почему не работает .data()? А вот почему:
    The data- attributes are pulled in the first time the data property is accessed and then are no longer accessed or mutated (all data values are then stored internally in jQuery).


    Т.е. используется этот метод только для сбора данных со страницы единожды, далее с этими данными работать можно только через .data() метод внутри jquery (изменять, удалять, дополнять).
    Ответ написан
  • Как сделать переход по ссылке с помощью input?

    @ned4ded
    Верстка, Фронтенд
    Добрый день! Могу лишь помочь вам с высоты своих скромных знанйи (я в http не очень шарю). Но мне кажется, вы немного запутались в языке самого протокола и процессе отправки данных с формы.

    Текст отправляется именно такой, потому что ? - это %3F в unicode. Любое name с формы будет перекодировано в base64. Сам же ? в конец строки браузера подставляется при формировании запроса к серверу (т.е. браузером, а не вами), сл-но, его нужно исключить.

    Тоже самое происходит со знаком амперсанд. Браузером автоматически собираются параметры с формы и отправляются на сервер используюя такую структуру: key=value&key2=value2...

    Следующий код сформирует запрос ?kek=&results=<your_text> к целевому пути

    <form action="/targetPage.html" method="GET">
        <input name="kek" hidden>
        <input type="text" name="results" value=""> // здесь нужно будет ввести текст
      </form>


    Как видите, в таком случае после слова kek подставляется знак равенство, т.к. это соответствует протоколу http. Веротяно, можно настроить http сервер, который сможет принимать и обрабатывать запросы без = (без пустого параметра), но я в точности вас сейчас просветить по этому моменту не смогу.
    Ответ написан
  • Как сделать эфект ховер на карточки товаров как на tiffany или sunlight?

    @ned4ded
    Верстка, Фронтенд
    На Tifanny это реализовано с помощью js. Сильно сомневаюсь, что тут нужна доп. библиотека. При наведении на товар добавляется целый блок в секцию товара. После mouseleave (хз, как назвать это по-русски, отведение курсора?) блок удаляется.

    У них использован js, вероятно, для сокращения веса страницы, увеличения скорости рендеринга.

    Как ни странно, на Sunlight это реализованно сильно по-другому. Там через js добавляется только класс к блоку, все остальные его элементы уже заранее собраны.

    Совпадение стилей - случайность, возможно, дизайн кто-то у кого-то стырил (причем весь дизайн, у них совпадает не только эффект при наведении на карточку товара, но много чего еще).

    На чистом css реализовать можно, но без анимации. Что-то вроде:

    .card
        .card__info
        .card__info-more

    .card__info:hover ~ .card__info-more { display: block };


    Все это вы вполне могли узнать сами, используя инструменты разработчика ;)
    Ответ написан