Pull to refresh

Comments 64

К сожалению(а может к счастью), у меня ещё нет бороды и я начинал с console.log) А вообще спасибо)
Да я же абсолютно не со зла. Сам вспомнил те времена, когда не было Реактов, ЕС6,7,8,...,2015 (да-да, несмешная шутка), но был ИЕ6.
П.С. у меня тоже нет бороды :(
Так и я не со зла) Просто появилось желание написать что-то на чистом js-е. И дабы пригубить это желание решил написать статью)
ИЕ6.

5.5
У меня борода не растёт (зараза, и витамины не помогают).
Вот и я помню ie 5.5) На win 95 шла, вроде бы) Только я на 95-ке в mortal combat 4 играл в основном)Не было место кодингу
5.5?
На 95, на 98, на Me.
В эпоху Me отдельная проблема была — сподвигнуть юзеров пересесть с 5.5 на 6. Ну, типа «Вы пользуетесь устаревшим браузером», знакомо, правда? )))
Мне показалось, что борода — это мода современной молодежи. А так по поводу статьи — очень хорошо, что на хабре есть такие. Иногда ликбез полезен. Старые доки из поисковиков исчезают (да и не только из поисковиков, хостинги закрываются), а новые — вот такие, иногда бывают полезны. Ну, когда нужно сверстать какой-нибудь отчетик, а копать мануалы лень. Хотя, лично меня, частенько за использование JS ругают. Но мне нравится ;)
UFO just landed and posted this here
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)))
};

?
И красоты, тут, честно говоря, лично я не наблюдаю.
Для начала можете статью прочитать. Насчёт filter вы правы. Действительно es5. Array.prototype.includes не годится. Я ищу подстроку в строке. Тогда уж String.prototype.includes. Как вы понимаете — логи в консоль только для проверки времени. Как говорят:«Обвиняешь — предлагай». Я не вижу от вас более изящного решения. Если оно заключается в замене index of, то я считаю это достаточно мизерным изменением
Консоль ни при чем, это понятно.
Вот тут, ИМХО, гораздо понятнее и нету сомнительных трюков с битовыми операторами:
function filter(val, list){
  console.time('test')
  return list.filter( i => i.includes(val) )
};
Я считаю, как уже говорил, это минорным изменением и код изменение лучше не сделало. Спасибо
Если говорить об ES6 то почему бы не использовать Array.prototype.includes вместо вот этого

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

Или 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 по умолчанию, вроде бы, так не умеет, так что задача приобретает еще один виток сложности

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

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

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


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

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

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


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

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

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


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


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


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

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


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


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


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

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

сервис 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 со всякими флагами. На клиенте или изоморфном коде следует подходить аккуратнее.

Как это использовать с 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>

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

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 для внешних сценариев или аналогичную?


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

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


Сложно?

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

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

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

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


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

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


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


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


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

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

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

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

Ты что с него еще «поисковый индекс» какой то спрашиваешь?)

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


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');
});
Спасибо) Почему-то поздним вечером не дошел до другого способа рендера) А мысли были рядом) Спасибо ещё раз) Я просто ещё учусь и не собирался учить других)

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

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

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

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

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

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


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

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

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

document.getElementById


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

3. не нужно «архивировать» логику
Спасибо большое) В следующий раз исправлюсь

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

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

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

PS: давным давно было ооочень много html-верстки, пришлось ставить зоопарк браузеров и их версий, потом пришли представители интернет-провайдера инет починить, мастер когда увидел количество установленных браузеров — смотрел на меня как на придурка )
Как я Вас понимаю. У меня на работе ровно та же картина с зоопарком браузеров.
// 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

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

Спасибо большой за советы) Буду придерживаться)
Я один заметил в коде вставку дочерних элементов в цикле?! А если таких 10 кило?
Ребята, астанавитесь…
Рендерить 10 000 DOM-объектов вообще дело подсудное…
Написать что ли статью «Делаем сложение двух чисел по красоте».
Без фреймворков, на ванильном чистом js.
Поучаствую в олимпиаде:
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);

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

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

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


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

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

Мне кажется, что вопрос спорный.

Я, к сожалению, не смог проверить скорость на ангуляре и вью. Там через директивы идут фильтры и повесить логи не получилось. Ищу пути обхода) Сомневаюсь, что на ангуляре и прочих фреймворках скорость будет выше.

Я имею в виду, что фреймворк (неважно какой, vju, angular, react) — это почти всегда замедление скорости работы, по сравнению с чистым js

В идеальном случае в ваккууме — ванильный JS будет быстрее, это да.


В реальном — если код получается большой, там будет легко забыть добавить где-нибудь проверку и вызвать лишний рендер, или подписаться на событие два раза вместо одного. И такая ошибка убьет всю пользу от микро-оптимизаций ванильного JS.


Во фреймворках такие проверки обычно встроены и страхуют вас от очевидных ошибок.

С вами полностью согласен. До сих пор ищу как затестить время на том же ангуляре. С большими данными и в большом приложении неоспоримо побеждает фреймворк. На ванильном, каждый знает, что писать что-то крупное не стоит. Но с каким-то небольшим приложением стоит присмотреться к ванили. Все-таки есть ощутимые преимущества
Sign up to leave a comment.

Articles