Привет. Мне 17 лет и я JS-разработчик. Возможно это приговор, а может быть это классическое приветствие в «Клубе анонимных JS-никовпрограммистов» — мне этого не узнать. Сейчас во многом моя работа заключается в работе с данными, их обработкой, фильтрами, сортировкой и так далее. Естественно, что я использую не нативный JS в проектах. Сегодня будем делать фильтры на чистом js-е. Увидим насколько это круто и быстро. Узнаем возможности es6 и сделаем рефакторинг кода. Заинтересованных прошу под кат.

Разве чистый JS не крут?


Сейчас, да и в принципе давно уже, мало кто пишет на чистом js. Все хотят писать на современных фреймворках. Я не являюсь исключением и на работе в основном пишу на VueJS(2.0+) и стареньком AngularJS. И этот выбор полностью оправдан. Не буду углубляться в подробности, но в большинстве случаев при грамотном построении приложения на фреймворке вы выиграете в скорости, поддерживаемости и читаемости.

Так к чему же эта статья?


Я хочу повествовать о том, что не стоит забывать о чистом js-е. Ведь все же мы начинали с простого:

console.log('Hello world');

Вы же не будете писать на фреймворке такое? Хотя, возможно, я очень плохо с вами знаком. В этой статье я хочу написать фильтры на чистом js-е. Задача, в принципе, тривиальная и не требует каких-либо задатков гения. Я постараюсь написать как можно более сжатый код. Не гарантирую, что читателю, который не знаком с особенностями js-а будет понятно. Однако я постараюсь описать весь процесс как можно подробнее.

Начнем


Для начала примерно набросаем, что нам надо и как это будет работать.
Нам нужны данные. Пусть будет статический массив. Поехали.

let list = ['JavaScript','Kotlin','Rust','PHP','Ruby','Java','MarkDown','Python','C++','Fortran','Assembler']

(Заранее прошу прощения, если не указал ваш любимый язык)

Отлично, у нас есть данные. На самом деле эти данные должны получаться через запросы к серверу, но у нас, как и у «ООО» — упрощенная модель.

Для вывода я сделал инпут и список. Выглядит это вот так:

<input type="text" id="search">
<ul id="results">
</ul>

В input пользователь вводит запрос, а список будет заполняться в зависимости от запроса. И еще определим, что, если input пустой, то мы будем выводить весь список.

У нас есть данные и пользовательский интерфейс(можете смеяться). Теперь нам нужна функция, которая отрендерит нам список.

function renderList(_list=[],el=document.body){
  _list.forEach(i=>{
    let new_el = document.createElement('li')
    new_el.innerHTML=i
    el.appendChild(new_el)
  })
}

Получилось вот так. Функция принимает два аргумента — массив с элементами и элемент DOM-дерева, к который мы хотим нарисовать список. Если первый аргумент не задан, то мы говорим функции, что это пустой массив. Аналогично с элементом дерева.

Далее мы перебираем все элементы массива в цикле и для каждого элемента создаем узел DOM-дерева, добавляем внутрь этого узла сам элемент и добавляем его в конец нашего родительского элемента. В принципе ничего сложного.

На данном этапе код выглядит примерно так:

let list = ['JavaScript','Kotlin','Rust','PHP','Ruby','Java','MarkDown','Python','C++','Fortran','Assembler']
const result = document.getElementById('results')
renderList(list,result)
function renderList(_list=[],el=document.body){
  _list.forEach(i=>{
    let new_el = document.createElement('li')
    new_el.innerHTML=i
    el.appendChild(new_el)
  })
}

А само приложения вот так:

image

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

function filter(val,list){
let result=[];
  list.forEach(i=>{
    if(i.indexOf(val)!=-1)
      result.push(i)
  })
return result;
}

У нас есть черновой вариант. Теперь соединим все вместе, добавим обработчик и поехали. Код теперь такой:

let list = ['JavaScript','Kotlin','Rust','PHP','Ruby','Java','MarkDown','Python','C++','Fortran','Assembler']
const result = document.getElementById('results')
renderList(list,result)
function filter(val,list){
let result=[];
  list.forEach(i=>{
    if(i.indexOf(val)!=-1)
      result.push(i)
  })
return result;
}
function renderList(_list=[],el=document.body){
  _list.forEach(i=>{
    let new_el = document.createElement('li')
    new_el.innerHTML=i
    el.appendChild(new_el)
  })
}
document.getElementById('search').addEventListener('input',e=>{
let new_arr = filter(e.target.value,list)
renderList(new_arr,result)
})

А браузер нам показывает вот это:

image

Упс. Забыли отчищать родительский элемент перед рендером. Добавим это в функцию рендера:

el.innerHTML='';

Теперь у нас все работает. Примерно также работают фильтры на вашем любимом фреймворке. Но мы же хорошие программисты и мы хотим сделать все красИвее, а может красивЕе. К счастью, я не филолог. Вернемся к нашей функции фильтра и попробуем ее переписать.

Для начала заменим if на тернарный оператор:

(i.indexOf(val)!=-1)?result.push(i):'';

Покопавшись в документации, я нашел, что можно юзать побитовое отрицание. Работает оно по формуле -(N+1). То есть при нашем значении -1 в indexOf мы получаем по формуле -(-1+1)=0. То есть это уже готовый false для нашего условия. Перепишем:

(~i.indexOf(val))?result.push(i):'';

А теперь десерт. forEach уже не модно. Есть же ES6. Там есть метод для перебора массива — filter. Он возвращает значение, если оно соответствует условию. Применим его:

function filter(val,list){
console.time('test')
  return list.filter(i=>(~i.indexOf(val)))
};

Красиво, не так ли?

Теперь переделаем обработчик. Запишем все в одну стрелочную функцию. У меня получилось вот так:

document.getElementById('search').addEventListener('input',e=>renderList(filter(e.target.value,list),result))

Я надеюсь, что все понятно. Берем отфильтрованный массив и кидаем его как аргумент для рендера.

Захотел замерить время обработки. Использовал модные функции.

На этом я остановился. Полный и рабочий код получился такой:

let list = ['JavaScript','Kotlin','Rust','PHP','Ruby','Java','MarkDown','Python','C++','Fortran','Assembler']
const result = document.getElementById('results')
renderList(list,result)
function filter(val,list){
console.time('test')
  return list.filter(i=>(~i.indexOf(val)))
};
function renderList(_list=[],el=document.body){
	el.innerHTML='';
  _list.forEach(i=>{
    let new_el = document.createElement('li')
    new_el.innerHTML=i
    el.appendChild(new_el)
  })
  console.timeEnd('test')
}
document.getElementById('search').addEventListener('input',e=>renderList(filter(e.target.value,list),result))

image

Такое приложение получилось очень шустрым и нетрудным для понимания. Среднее время для таких данных — 0.3 миллисекунды. А размер после сжатия через babel дает всего 782 байта.

image

Рабочий пример можете найти по ссылке
Этой статьей я хотел лишь натолкнуть людей не забывать про чистый js. Не так все и плохо там. Пользуйтесь нативными функциями и используйте es6.

Спасибо Houston Теперь пример выглядит вот так и не зависит от регистра.
Спасибо за внимание.

Комментарии (55)


  1. makcums
    22.11.2017 11:07
    +1

    Эхх, о времена, о нравы… Начинали мы не с console.log(), а с document.write("Hello world!") :)


    1. Ankell Автор
      22.11.2017 11:28

      К сожалению(а может к счастью), у меня ещё нет бороды и я начинал с console.log) А вообще спасибо)


      1. makcums
        22.11.2017 11:32

        Да я же абсолютно не со зла. Сам вспомнил те времена, когда не было Реактов, ЕС6,7,8,...,2015 (да-да, несмешная шутка), но был ИЕ6.
        П.С. у меня тоже нет бороды :(


        1. Ankell Автор
          22.11.2017 11:48

          Так и я не со зла) Просто появилось желание написать что-то на чистом js-е. И дабы пригубить это желание решил написать статью)


        1. Zenitchik
          22.11.2017 17:50

          ИЕ6.

          5.5
          У меня борода не растёт (зараза, и витамины не помогают).


          1. Ankell Автор
            23.11.2017 11:28

            Вот и я помню ie 5.5) На win 95 шла, вроде бы) Только я на 95-ке в mortal combat 4 играл в основном)Не было место кодингу


      1. helgisbox
        22.11.2017 13:15

        Мне показалось, что борода — это мода современной молодежи. А так по поводу статьи — очень хорошо, что на хабре есть такие. Иногда ликбез полезен. Старые доки из поисковиков исчезают (да и не только из поисковиков, хостинги закрываются), а новые — вот такие, иногда бывают полезны. Ну, когда нужно сверстать какой-нибудь отчетик, а копать мануалы лень. Хотя, лично меня, частенько за использование JS ругают. Но мне нравится ;)


    1. pehat
      22.11.2017 14:24

      Молодёжь… Только alert(), только хардкор!


      1. makcums
        22.11.2017 14:25

        Пфф! Алерт для отладки!


  1. RidgeA
    22.11.2017 11:08
    +1

    Array.prototype.filter — это ES5, а не ES6

    Если говорить об ES6 то почему бы не использовать Array.prototype.includes вместо вот этого

    ~i.indexOf(val)
    

    в
    function filter(val,list){
    console.time('test')
      return list.filter(i=>(~i.indexOf(val)))
    };
    

    ?
    И красоты, тут, честно говоря, лично я не наблюдаю.


    1. Ankell Автор
      22.11.2017 11:26

      Для начала можете статью прочитать. Насчёт filter вы правы. Действительно es5. Array.prototype.includes не годится. Я ищу подстроку в строке. Тогда уж String.prototype.includes. Как вы понимаете — логи в консоль только для проверки времени. Как говорят:«Обвиняешь — предлагай». Я не вижу от вас более изящного решения. Если оно заключается в замене index of, то я считаю это достаточно мизерным изменением


      1. RidgeA
        22.11.2017 11:44

        Консоль ни при чем, это понятно.
        Вот тут, ИМХО, гораздо понятнее и нету сомнительных трюков с битовыми операторами:

        function filter(val, list){
          console.time('test')
          return list.filter( i => i.includes(val) )
        };
        


        1. Ankell Автор
          22.11.2017 11:54

          Я считаю, как уже говорил, это минорным изменением и код изменение лучше не сделало. Спасибо


    1. ihost
      22.11.2017 13:13

      Если говорить об ES6 то почему бы не использовать Array.prototype.includes вместо вот этого

      Безотносительно ко всей статье, но именно includes в некоторым смысле вредная штука — способ выкинуть поддержку как минимум IE11 и Samsung TV browser на пустом месте
      Если синтаксические конструкции ES7+ легко раз-babel-иваются, а для ES6-функционала polyfills во всех современных браузерах не нужны и по умолчанию их давно уже никто не включает в bundle-ы, то includes — фактически единственное исключение и способ нажить неудобства при deployment-е


      1. justboris
        22.11.2017 18:10

        подключаем https://polyfill.io и проблема решена?


        1. ihost
          22.11.2017 20:11

          Или babel-polyfill, если зависимости собираются webpack-ом и поставляются на клиент в виде bundle-а? Окей, но скорее всего нет, поскольку есть один важный аспект — вопросы оптимизации, включая объем трафика для bundle-а и вычислительные ресурсы для выполнения на клиенте.


          Применение единого bundle-а со всеми polyfills и transpile-кодом на современных браузерах приводит к существенному оверхэду, поэтому рекоммендуется разворачивать отдельный bundle для современных клиентских агентов (раз, два).


          Условно все относительно-современные браузеры поддеривают ES6, и для них может приозводиться доставка непосредственно ES6-кода. Для старых браузеров можно применять polyfills, transpile-ить код, или вообще просить пользователя обновиться для просмотра ресурса — это вопрос отдельный.


          Теперь если взять все браузеры с ES6, то часть из них, включая IE11, Smart TV, Tizen, не поддерживают ES7, но отлично понимают ES6. Если вспомнить соответствующую спецификацию комитета TC39, то 6-ая версия включает всего два изменения — оператор возведения в степень и includes. ВСЁ.


          Исходя из этого вопрос — имеет ли смысл заморачиваться с отдельным bundle-ом с polyfills и transpile-ингом с уровня ES7 до ES6 (*), по сути ради одной единственной функции, которая чуть менее, чем на 100% — всего лишь синтаксический сахар для arr.indexOf(value) > 0? Настраивать развертывание, кеширование отдельного bundle-а, отдельные функциональные тесты на каком-нибудь SauseLabs, ради одной малополезной функции?


          (*) При условии, что такое легко реализовать; babel по умолчанию, вроде бы, так не умеет, так что задача приобретает еще один виток сложности


          1. justboris
            22.11.2017 20:15

            Вы хотя бы немного мою ссылку читали? Сервер читает userAgent, и присылает полифиллы нужные этой версии браузера. Если браузер не может только Array.includes, то загрузится только полифилл для него.


            1. ihost
              22.11.2017 20:31

              Сервер читает userAgent

              Производить проверку браузера, исходя из строки агента, не рекоммендуется — современным методом является feature discovery — к примеру, вариант для ES6, но это даже не столь существенно


              Самое главное — такое решение плохо сочетается с самой идеей bundle-ирование клиентского кода. Конечно, можно загрузить предложенную библиотеку как статику и добавить в externals, но тогда bundle все равно или будет целиком содержать излишний исходный код, или требовать условной сборки, зависимой от клиентского агента.


              1. justboris
                22.11.2017 21:22

                Конечно, можно загрузить предложенную библиотеку как статику и добавить в externals

                Вы точно разбираетесь, чем полифилл отличается от библиотеки?


                Его не надо импортировать. Подключили скрипт на страницу, он добавил в нативные объекты недостающие методы, ваш код может спокойно к ним обращаться в любом браузере.


                1. ihost
                  23.11.2017 10:53
                  +1

                  Подключили скрипт на страницу

                  Какой скрипт, на какую страницу. о чем Вы вообще? Как у Вас организован deployment, bundle-ирование и доставка кода на клиент?


                  Если Вы делаете transpile-инг на серверной стороне, то и все необходимые polyfills надо интегрировать сразу, чтобы сборщик зависимостей исключил дубликаты. Если не делаете — то код просто сломается на старых клиентских агентах из-за синтаксических ошибок, тогда и polyfills вообще не понадобится уже — и так страница не откроется.


                  Получается, что Вы предлагаете разрабатывать на синтаксисе ES5, но с функциями из ES7? Смысла мало, но если в Вашем проекте Вам там удобно — кто ж запретит, юзайте на здоровье


                  Вы точно разбираетесь, чем полифилл отличается от библиотеки?

                  Ничем не отличаются, что одно package, что другое package. Правда обычно polyfill package не является прямой prod-зависимостью других пакетов, а добавляется явно во входной точке конфигурации того же webpack-а или другого bundler-а, если Вам угодно.


                  Однако в таком случае встречный вопрос — regenerator-runtime это в Вашей терминологии polyfill или абстрактный library?


                  Его надо явно import-ить (Как видимо "библиотека" в Вашей терминологии), но при этом он модифицирует глобальное пространство процесса (Как видимо "полифилл" в вашей терминологии)


                  Впрочем, позволю резюмировать. Каждый deploy-ит как хочет, выбирает клиентские агенты, какие поддерживать, а какие нет, решает, оптимизировать производительность или сделать попроще, забив на это. Для каждого случая это можно решать отдельно. Однако если вспомнить, что все это ради одной функции, то лучше на нее забить.


                  1. justboris
                    23.11.2017 11:45

                    Если бы вы все-таки сходили по ссылке, и прочитали что из себя представляет сервис polyfill.io, то большинство ваших вопросов отпали бы сами собой.


                    1. ihost
                      23.11.2017 17:25
                      +3

                      сервис polyfill.io

                      Сторонний сервис, который судя по обзору документации и единственному стороннему устаревшему пакету для bundle-ирования, не стыкуется с концепцией упаковки и доставки кода на клиент, не говоря уже о chunk splitting, feature detecting-based bundles, HMR и тому подобное.


                      Как это использовать с react-scripts, или уж тем более с resolve-scripts, с изоморфным кодом data layer-а, и чтобы при этом оставалась поддержка требуемых клиентских агентов без избычного кода — совершенно неясно, и вероятно, вообще невозможно.


                      Если Вы где-то используете и для Ваших задач подходит — на здоровье, никто не против. В серьезных же проектах лучше отказаться от одной малополезной функции, ради упрощения и стабилицаии продукта.
                      Посмотрите на тот же React (includes vs indexOf) — на клиентской стороне ни одного includes, та парочка что есть — это серверный task runner.


                      Разумеется, на node.js в НЕ-изоморфном окружении можно использовать что угодно, хоть stage-0 со всякими флагами. На клиенте или изоморфном коде следует подходить аккуратнее.


                      1. justboris
                        24.11.2017 12:34

                        Как это использовать с react-scripts, или уж тем более с resolve-scripts

                        1. Удаляем import "babel-polyfill", если он есть.
                        2. В html файле добавляем скрипт перед основным бандлом

                        <!-- полифиллы -->
                        <script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script>
                        <!-- ваш бандл -->
                        <script src="/static/js/bundle.js"></script>

                        Что здесь сложного?


                        1. ihost
                          24.11.2017 17:16
                          +1

                          react-scripts, или уж тем более с resolve-scripts
                          Что здесь сложного?

                          Тем что надо отдельно настраивать конфигурируемую head-секцию с внешнием сценарием через React Helmet ?


                          Тем что из-за синхронной загрузки скриптов увеличивается время загрузки страницы? А если CDN этого внешнего сервиса отвалится, то и web-приложение тоже? А также тем, что начинаются проблемы с offline-режимом, и к примеру, невозможно зарегистрировать service worken для удаленного СDN: https://filipbech.github.io/2017/02/service-worker-and-caching-from-other-origins ?


                          Тем что это может уже не сработать, если браузер поддержал ES modules-подобную загрузку, которая уже асинхронная, и если предполагался polyfill уровня ES8+, то он мог не успеть загрузиться?


                          Тем что нельзя установить жесткую CSP-политику для безопасности web-приложения, к примеру, отключающую eval для внешних сценариев или аналогичную?


                          В общем, можно дискутировать бесконечно. На каждое решение — свой потребитель. Как Вам уже не раз говорилось ранее — нравится — пользуйтесь на здоровье.


                          1. justboris
                            24.11.2017 20:07

                            Причем здесь React-helmet? create-react-app создает вам в проекте вот такой html-файл. Добавляем в него еще один скрипт и все.


                            Сложно?


                      1. justboris
                        24.11.2017 12:36

                        В серьезных же проектах лучше отказаться от одной малополезной функции

                        includes сам по себе не очень хороший пример, но о динамической генерации полифиллов полезно знать. Promise и fetch не завезли в IE11, и при помощи такого способа можно динамически подгрузить полифиллы, не нагружая пользователей Chrome бесполезным кодом.


                        1. ihost
                          24.11.2017 16:52

                          о динамической генерации полифиллов полезно знать

                          Безусловно. А еще лучше иметь заранее подготовленные bundle-ы для версия браузеров. Более того, есть решения, которые позволяет также включать сразу ES Modules для современных клинетских агентов, не выполняя дифференциации генерируемой HTML-страницы, а делая это исходя из feature discovery: статьи как настроить раз и два.


                          Promise и fetch не завезли в IE11

                          Разумеется. Для fetch-а в исходном коде вообще скорее всего не будет прямого вызова, а изоморфный импорт import fetch from 'isomorphic-fetch'.


                          Это все довольно очевидные вещи. Весь тред собственно о том, если не использовать ES8+, то выбрасывание многострадального и довольно бесполезного includes позволяет сэкономить тонну работы по deployment-у.


                          Если вдруг ваше приложение использует ES8+, то и говорить не о чем. Собственно, как Вы сами частично и признаете:


                          includes сам по себе не очень хороший пример

                          А весь тред только об includes и есть.


  1. pifpafka
    22.11.2017 11:40

    Когда увидел заголовок «Глупый JS. Делаем фильтры «по красоте»», думал что сейчас будет что то интересное «по красоте»… Дочитал и чувство что кинули =( Я думаю все же если это фильтр, хоть он и типа «примитивный», но на пользовательский ввод в нижнем регистре он хотя бы должен корректный результат выдавать ИМХО. Удачи :)


    1. Ankell Автор
      22.11.2017 11:42

      Отчасти у каждого свое мнение. По моему скромному мнению учёт регистра — излишество. Делается это в пару строк. Акцент статьи — не на создание самого фильтра. Я призываю людей писать на чистом js-е) Хотя я не реформатор и не революционер. Просто такое мнение у студента)


    1. Rastishka
      22.11.2017 18:04

      Вот вот. Ожидал быстрый фильтр по индексируемому массиву или типа того. Было бы по красоте.


      1. Ankell Автор
        22.11.2017 18:29

        Специально для вас. ссылка
        Регистр теперь не проблема.
        Только время упало в два раза.
        Статья не является гайдом к написанию фильтров на js-е)


  1. Houston
    22.11.2017 11:43

    На вкус и цвет, конечно.


    const list = ['JavaScript', 'Kotlin', 'Rust', 'PHP', 'Ruby', 'Java', 'MarkDown', 'Python', 'C++', 'Fortran', 'Assembler'];
    
    const result = document.getElementById('results');
    
    renderList(list, result);
    
    function filter(val, _list) {
      return _list.filter(it => it.indexOf(val) !== -1);
    }
    
    function renderList(_list = [], el = document.body) {
      el.innerHTML = _list.map(item => `<li>${item}/li>`);
    }
    
    document.getElementById('search').addEventListener('input', e => {
      console.time('test');
      renderList(filter(e.target.value, list), result);
      console.timeEnd('test');
    });
    


    1. Ankell Автор
      22.11.2017 11:51

      Спасибо) Почему-то поздним вечером не дошел до другого способа рендера) А мысли были рядом) Спасибо ещё раз) Я просто ещё учусь и не собирался учить других)


    1. Houston
      22.11.2017 11:56

      О, в renderList забыл сделать join('') в конце. Уже не исправить)


  1. Slowz
    22.11.2017 12:15

    Извините, но я кажется не понял посыла сего опуса. Что вы имеете в виду под словами «чистый JS»? Отсутствие фреймворков? Или ручное управление DOM?
    Вы продемонстрировали решение очень простой задачи. Любой маломальски знакомый с веб-разработкой решил бы эту задачу примерно так же. Проблемы ведь появляются при масштабировании :) Чем больше проект, чем больше связанность различных элементов и чем больше интерактивности, тем сложнее становится управлять всем этим в ручную. Именно за этим и появились фреймворки)
    Разумеется, для простых вещей, например лэндинг с каким-то уровнем интерактивности спокойно обойдется без сторонних библиотек. В таких задачах совершенно излишне подключать что-то мощное.
    Вообще, конечно удачи в изучении языка. Быть увлеченным студентом прекрасно.
    P.S. У вас что-то ужасное с форматированием кода. Лучше исправить.


    1. Ankell Автор
      22.11.2017 12:36

      Все в совокупности, что ты назвали — для меня чистый js. Без бандлеров, без сборщиков и прочей лабуды. С вами согласен, но далеко не каждый «маломальский знакомый с разработкой» сделает это так. Вы можете говорить только за себя


      1. iShatokhin
        22.11.2017 15:33

        Из статьи.

        Сейчас, да и в принципе давно уже, мало кто пишет на чистом js. Все хотят писать на современных фреймворках. Я не являюсь исключением и на работе в основном пишу на VueJS(2.0+) и стареньком AngularJS.

        Это скорее относится не к JS, а к DOM API. Чистый JS не содержит в себе даже console, не говоря об document. Я, к примеру, не работаю с DOM/HTML, т.ч. как видите, не все хотят писать на модных фреймворках.


  1. lair
    22.11.2017 12:29

    Покопавшись в документации, я нашел, что можно юзать побитовое отрицание

    Не надо использовать битовые операторы вместо логических. Просто не надо.


  1. KirEv
    22.11.2017 13:22

    Рабочий пример можете найти по ссылке


    в хроме — работает, в ие8 — не работает, не сам код, а сам сервис =)

    глупость вот в чем:

    1. проверяйте существование элементов перед использованием, особенно когда

    document.getElementById


    2. если делаете фильтр, он как минимум должен фильтровать не учитывая регистр входных данных, вот хочу найти «Kotlin» или «JavaScript», не вводить же мне «JavaScript», строчу «javascript», «Javascript», «JavaSCript», etc…

    3. не нужно «архивировать» логику


    1. Ankell Автор
      22.11.2017 13:24

      Спасибо большое) В следующий раз исправлюсь


    1. justboris
      22.11.2017 18:14

      Вы специально IE8 держите, чтобы молодых разработчиков троллить?


      1. KirEv
        22.11.2017 18:23

        почему сразу троллить? Вы не смотрите как то или иное выглядит в разных браузерах? ради интереса :)

        win7 стоит чуть больше 2х лет, нет привычки накатывать свежие обновления от микрософт, да и по работе бывает нужно отдебажить что-то под ИЕ <9… у некоторых клиентов и того хуже (:…

        PS: давным давно было ооочень много html-верстки, пришлось ставить зоопарк браузеров и их версий, потом пришли представители интернет-провайдера инет починить, мастер когда увидел количество установленных браузеров — смотрел на меня как на придурка )


        1. Zenitchik
          22.11.2017 18:28

          Как я Вас понимаю. У меня на работе ровно та же картина с зоопарком браузеров.


  1. kahi4
    22.11.2017 13:35
    +1

    // list дальше по коду не меняется, должен быть const
    let list = ['JavaScript','Kotlin','Rust','PHP','Ruby','Java','MarkDown','Python','C++','Fortran','Assembler']
    
    // красивиое и понятное название переменной, да
    const result = document.getElementById('results')
    
    // вызывать функцию до объявления конечно можно, но не нужно
    renderList(list,result)
    
    // зачем фильтр два раза объявлен?
    function filter(val,list){
    let result;
      list.forEach(i=>{
        if(i.indexOf(val)!=-1)
          result.push(i)
      })
    return result;
    }
    
    // вообще сама конструкция array.filter подразумевает что у вас будет не обертка над ней
    // а где-то в коде list.filter(predicate);
    // а тут этот самый предикат объявлен
    function filter(val,list){
    console.time('test')
      return list.filter(i=>(~i.indexOf(val)))
    };
    
    function renderList(_list=[],el=document.body){
    
        // Удаляйте элементы правильно, раз на то пошло.
       // https://jsperf.com/innerhtml-vs-removechild
       // В идеале даже делать дифф и не удалять не удалившиеся
      el.innerHTML=''; // то есть, то нет точки с запятой, уж определитесь
    
      _list.forEach(i=>{
        // const опять же
        let new_el = document.createElement('li')
        new_el.innerHTML=i // а погуглить правильный путь не пробовали?
        el.appendChild(new_el)
      })
      console.timeEnd('test')
    }
    
    // Как отписываться от этого события будете?
    // Бизнес-логика в хандлере. +1, мне нравится
    document.getElementById('search').addEventListener('input',e=>renderList(filter(e.target.value,list),result))

    А еще почему используете стрелочные функции и let, но игнорируете классы?
    Смешена логика и отображение, да вообще, "по красоте" как-то некрасиво получилось.


    сжатия через babel

    Ничего бейбель не жмет, он не для этого предназначен.


    1. Ankell Автор
      22.11.2017 13:48

      Спасибо большой за советы) Буду придерживаться)


    1. iShatokhin
      22.11.2017 16:39

      Ничего бейбель не жмет, он не для этого предназначен.

      Babel предназначен в том числе и для минификации кода


  1. webdevium
    22.11.2017 14:43

    Я один заметил в коде вставку дочерних элементов в цикле?! А если таких 10 кило?
    Ребята, астанавитесь…


    1. Tenebrius
      22.11.2017 15:02

      Рендерить 10 000 DOM-объектов вообще дело подсудное…


  1. Rastishka
    22.11.2017 18:32

    Написать что ли статью «Делаем сложение двух чисел по красоте».
    Без фреймворков, на ванильном чистом js.


  1. JSmitty
    22.11.2017 19:10
    -1

    Поучаствую в олимпиаде:

    const list = ['JavaScript', 'Kotlin', 'Rust', 'PHP', 'Ruby', 'Java', 'MarkDown', 'Python', 'C++', 'Fortran', 'Assembler'];
    const result = document.getElementById('results');
    const renderResult = list => renderList(list, result);
    const renderFilteredResult = val => renderResult(list.filter(i => (~i.indexOf(e.target.value))));
    const searchHandler = ({target: {value}}) => renderFilteredResult(value);
    
    renderResult(list);
    
    function renderList(list = [], el = document.body) {
        el.innerHTML = '';
        list.forEach(i => {
            let new_el = document.createElement('li');
            new_el.innerHTML = i;
            el.appendChild(new_el);
        })
    }
    
    document.getElementById('search').addEventListener('input', searchHandler);
    


  1. i360u
    22.11.2017 21:20

    Молодой человек, почитайте что-нибудь на тему соглашений о оформлении кода, ваши будущие коллеги будут вам благодарны.


  1. Odrin
    23.11.2017 10:27
    +1

    new_el.innerHTML=i
    И если в данных будут теги, то все сломается. Использовать надо textContent.

    Такое приложение получилось очень шустрым
    Если уж вы так топите за производительность, то делать appendChild в цикле надо в DocumentFragment, а не в «живой» DOM элемент.


  1. dopusteam
    23.11.2017 10:52

    Не буду углубляться в подробности, но в большинстве случаев при грамотном построении приложения на фреймворке вы выиграете в скорости, поддерживаемости и читаемости.


    Скорости разработки?


    1. Ankell Автор
      23.11.2017 10:55

      Ну если вы используете какой-нибудь шаблон, аля create-react-app, то скорость ваша, как минимум, не уменьшится


      1. dopusteam
        25.11.2017 18:48

        Я просто уточнить хотел, какую скорость Вы имеете в виду — скорость разработки или скорость работы приложения(производительность)