Как стать автором
Обновить

Комментарии 78

Наблюдается следующее: JS как ЯП очень популярный и востребованный имея море фреймворков и библиотек эволюционирует в кита с солянкой. Jquery появился потому что не было querySelectorAll. Ждем когда он в себя заберет текущие фреймворки?
Фреймворк — это не библиотека, фреймворк — это не язык.
Кроме JQuery распространенных таких библиотек нет.

Что есть 'чистый javaScript'?


jQuery — это не только методы для выборки

Речь идет не о переписке JQuery, а о миграции проекта. У меня в последнем, например, используется методов 5-10 из JQuery, все они могут быть так переписаны.

Речь тут только о селекторных функциях. AJAX и другое — это отдельная история.
Ну так это сложно назвать 'миграцией с jQuery', это 'миграция с 10 функций jQuery'.
Не сочтите за занудство, но это всё таки абсолютно разные вещи.

Плюс, было бы неплохо вводную в статью добавить, потому что всё прекрасно знают, что быстрее vanillajs ничего нет, но написать подобную обёртку для выборки элементов каждый может
Это миграция сайта с JQuery на Javascript ES6. Сколько JQuery функций используется на сайте не играет роли.
Миграция в данном случае это метод и процесс, а не конкретная библиотека-заменитель.
Ну так у вас ни метод ни процесс не описан.
Нужно переписать функции jQuery — ну да, это логично.
А что по поводу подводных камней, сложностей, каких то советов?

Вашу статью можно уместить в одно предложение 'Напишите функции, подобные существующим в jQuery и используйте их, вместо jQuery' — ок

С таким подходом, вы можете заменить jQuery в статье на что угодно (angular, knockout), раз вам не важно количество функции, тем более функция выборки везде есть, вот её и будем переписывать.

Вашу статью можно уместить в одно предложение 'Напишите функции, подобные существующим в jQuery и используйте их, вместо jQuery' — ок

Совершенно верно. Именно в этом смысл статьи.

Конечно с учетом того, что новые функции получаются на порядок производительней прежних и реализация их достаточно проста. Если вы можете добиться такого повышения эффективности и при переписывании angular или knockout и вам от них нужна только функция выборки, а не фреймворк — почему нет?
Совершенно верно. Именно в этом смысл статьи.

Был ли смысл целую статью писать?

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

До тех по пока Вы не пишете сложных функций. Не для всех функции есть аналоги в чистом js.

Если вы можете добиться такого повышения эффективности и при переписывании angular или knockout и вам от них нужна только функция выборки, а не фреймворк — почему нет?

Может быть потому что я выигрываю в поддержке, мне проще найти разработчиков, знакомых с angular, а не с моей (или Вашей) поделкой. Angular протестирован, есть много людей, которые его поддерживают, огромный зоопарк компонентов готовых и т.д.

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

Это возможно только при потере части функциональности. То есть все равно придется просмотреть весь старый код чтобы понять какими фичами можно будет пожертвовать.

Частичная оптимизация не даст ничего, поскольку jquery с его селекторами обычно используется не ради селекторов как таковых а ради того что можно сделать с элементами выбранными посредством них. Для примера $('.foobar').addClass('bla').removeClass('tutu'), ну заменим мы селектор на натив, а дальше то что? Либо циклы, либо опять заворачивать в jquery, либо писать собственную реализацию, тем самым на выходе получив jquery #2
Разве в статье не написано про реализацию нужных методов?
addClass -> el.classList.add(className);
Разве я говорил об этом?
Не знаю. Я не понимаю, о чем вы говорите.
Я не понимаю, о чем вы говорите.

Про циклы говорит:


$('.foobar').addClass('bla')

или


Array.from(document.getElementsByClassName("foobar")).forEach(el => {
    el.classList.add('bla');
});
В любом случае самым быстрым вариантом (увы и ах) будет простой советский for (var c = 0; c < els.length; c++) {… }
В 99% случаев больше потеряете на выросшем от таких конструкций размере бандла.
Возможно и так, но если говорить о размере бандла то document.querySelectorAll и document.getElementById — претендуют на первое место в раздувании размера )
уже все есть, зачем писать велосипеды?
Array.from(document.querySelectorAll('a'))
    .forEach(el => {
       el.classList.add('test');
       el.classList.remove('test');
   })


+ меня бесит порядок аргументов в jquery в функциях ex.: each(index, element)
А вы попробуйте это прогнать по перформанса и посмотрите что будет быстрее
Для Вас так критична производительность? Зачем Вы изначально jquery в таком случае брали?
Для меня то нет, а вот для автора похоже, что да. В ином случае это выкидывание jquery просто ради того чтобы его выкинуть.
Прошу прощения, вопрос автору адресован был, конечно же, просто веткой промахнулся как то
ок
Я от нее и сейчас не отказываюсь
НЛО прилетело и опубликовало эту надпись здесь
Шоб красиво было + по максимуму использовать весь доступный сахар.
Шоб красиво тогда уж
Object.prototype.find = function(s){return this.querySelectorAll(s);}
Object.prototype.bind = function(cssSelectors,events,callback,debug=false){
  events = events.split(',');
  elements= this.find(cssSelectors)||this;
  elements.forEach(element=>{
    events.forEach(event=>{
      element.addEventListener(event,callback);
      if (debug) console.dir(element+' listen '+event);
    });
  });
}
document.bind('a,p','click,mouseup',(e)=>{});


Ну и в таком духе всё хождение по DOM'у можно задекорировать.
Object.prototype.on = function(f,c){return Array.from(this,(i)=>i.addEventListener(f,c));}
Object.prototype.find = function(s){return this.querySelectorAll(s);}
Object.prototype.first = function(s){if(!s) return this.firstElementChild;return this.querySelector(s);}
Object.prototype.next = function(){return this.nextElementSibling;};
Object.prototype.prev = function(){return this.previousElementSibling;};
Object.prototype.last = function(){return this.lastElementChild;};
Object.prototype.parents = function(cssSelectors){
  if(!cssSelectors) return this.parentElement;
    cssSelectors = cssSelectors.split(',');
    const a=[];
    for(let i=0;i<=cssSelectors.length;i++) {
      var p=this.parentElement;
      while(p){
        if (p.matches(cssSelectors[i])) {a.push(p);}
        p=p.parentElement;
      }
  }
  return a;
};
Это пример того как нельзя делать…
В продакшне не стоит, накидать прототип интерфейса — почему нет?
Прототип можно и на jquery накидать.
Не стоит потому что можно на jquery? Ну ок.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Вот только Array.from можно заполифилить, а NodeList.forEach — не в любом браузере. Потому что Array — родной для JS объект, а NodeList — нативный.
НЛО прилетело и опубликовало эту надпись здесь

Я не то слово сказал. Вот правильное: exotic object.


Если у прототипа NodeList не объявлен внутренний метод [[DefineOwnProperty]] — то никаким полифилом вы метод forEach ему не добавите. Это возможно, к примеру, в старых версиях IE где объекты DOM были COM-объектами.

НЛО прилетело и опубликовало эту надпись здесь
Порядку аргументов есть извинение: в jQuery .each появился раньше, чем .forEach в Array.prototype.
НЛО прилетело и опубликовало эту надпись здесь
Ну и смысл?
Смысл, наверное, в том, чтобы читать статью и пытаться понять, о чем она, а не выхватывать из нее знакомые слова, придумывать на лету свои фантазии, вытаскивать свои фобии и бороться с ними в комментариях.
НЛО прилетело и опубликовало эту надпись здесь
Присоединяюсь
Здравствуйте. Благодарю за статью — интересный подход. Интересно, можно ли подобным образом реализовать миграцию jquery ajax?
НЛО прилетело и опубликовало эту надпись здесь
Нет, ну что вы, это нереально.
А чем стандартный fetch или его полифил не устраивает?
Смысл приведенной в статье миграции — чтобы не переписывать весь код, по селекторам он обычно довольно объемный. А AJAX вызовов обычно немного, перевести их на fetch не должно составить труда.
// jQuery
$(selector).load(url, completeCallback)

// Native
fetch(url).then(data => data.text()).then(data => {
  document.querySelector(selector).innerHTML = data
}).then(completeCallback)
НЛО прилетело и опубликовало эту надпись здесь
с куками
fetch(url, {
  credentials: "same-origin"
}).then(data => data.text()).then(data => {
  document.querySelector(selector).innerHTML = data
}).then(completeCallback)
НЛО прилетело и опубликовало эту надпись здесь
Не помешало бы тесты сделать общедоступными, а то тестирования выглядит мягко говоря «сферическим котом в вакууме». Может вы там для jQuery скормили страницу на пол мегабайта, а JS ваш пример с тремя нодами.
В добавок почему сравнение идет с jQuery 2.0? Последняя версия 3.3.1 и между 2 и 3 версией огромная разница в скорости.

И примеры никудышные, попробуйте выбрать чистым JS вот такое:
$('#form[name*="regsitr"] .field-wrap:eq(4) :checkbox:checked')


jQuery выбирают для удобства разработки. Если вам нужна скорость, вы можете комбинировать стандартные функции и методы jQuery.

Но все эти «переходы» сразу прекращаются когда речь заходит о событиях…
НЛО прилетело и опубликовало эту надпись здесь
Чутка ошиблись:
document.querySelectorAll('#form[name*="regsitr"] .field-wrap:nth-of-type(5) [type=checkbox]:checked')
Справедливости ради: такие селекторы — вернейший признак говнокода.
А теперь покажите код на чистом js для

$('.some-node').wrap('<div class="wrapper"></div>')
               .fadeOut(function(event) {
                   $(this).closest('.wrapper')
                          .slideUp();
               });
НЛО прилетело и опубликовало эту надпись здесь
Во-первых, jQuery для анимации использует requestAnimationFrame, если эта функция доступна, то есть тот же механизм, что и транзишены. Во-вторых, не подскажите чем делать fadeOut на 10-м IE?
НЛО прилетело и опубликовало эту надпись здесь
Но как, если поддержка транзишенов появилась только в 11-м IE?
НЛО прилетело и опубликовало эту надпись здесь
Возможно. Впрочем, это не сильно изменяет ситуацию, так как на поддерживаемом мной ресурсе постоянных пользователей с IE8 больше тысячи человек.
Интересно, кто больше тормозит прогресс: Билл Гейтс со своим IE8, пользователи, которые на нем сидят, или разработчики, поддерживающие этих пользователей на их IE8
Существует такое мнение, что IE11 будет существовать ещё очень-очень долго. Доля его стабилизируется на уровне пары процентов — вроде бы и немного, но не настолько, чтобы полностью ими пренебречь.
Причина — именно в его устаревших/маргинальных/нестандартных технологиях. У большинства они как заноза в заднице, но некоторым людям и компаниям они наоборот необходимы. И видели они ваш абстрактный прогресс в белых тапках, у них есть конкретные потребности.
В общем, ресурсы, рассчитанные на широкую аудиторию, вынуждены будут поддерживать IE ещё несколько лет.
Боюсь, что у разработчиков может и не быть выбора. Например, если основная аудитория сайта — пожилые жители маленького провинциального городка, то заказчик в договоре зафиксирует необходимость нормально отображаться на очень старых компьютерах с очень старыми браузерами.
Если заказчик понимает, что за те же деньги, но без поддержки рудиментов он может получить продукт с на 20% большей функциональностью, то вопросов нет. Это его выбор.
Есть репутационные издержки, которые проще упредить, чем потом бороться с ними.
Например, я продаю водяные краны. Ко мне на сайт заходит какой-то клерк из ЖЭКа со своего старенького пентиума и видит полностью поломаный сайт. Вы наверное думаете, что он сразу же поймёт, что проблема в его браузере? Да щас. Он решит, что сайт хлам и как пить дать контора раздолбайская. Больше того, он потом ещё своему начальнику скажет, что эта контора (как там она называется? забыл. да и черт с ней) гавно.
Зато на сайте чистенький ES6, ога.
Во-первых, он половину сайтов видит в таком виде, и если не совсем дурак, то поймет, в чем дело (верней вы ему явно об этом большими буквами вверху страницы напишите)
Во-вторых, для таких случаев удобно делать отдельный шаблон с минимумом функциональности на дубовом HTML без шика. Наверно все CMS это позволяют (несколько шаблонов). Это опять же может быть проще, чем делать один шаблон для всех ПК.
Вы напишете. Он скажет ну, что же понятно, что купить, здесь не выйдет. В результате купит на сайте из второй половины. Ведь затраты на новый компьютер или обновление программного обеспечения будут больше чем стоимость товара, который он у вас хотел купить.
В том то и дело, что на порядок большие деньги. Вы исходите только из затрат на сайт. А заказчик учитывает и затраты на другое программное обеспечение и затраты на оборудование и затраты на внедрение этого программного обеспечения и затраты на обучение персонала и возможно изменения бизнес-процессов. И бах таких рабочих мест может быть не 10 и даже не 100, а тысячи.
В конструкторе класса желательно парсить sel, чтобы более эффективно применять querySelectorAll(), getElementsByClassName() и getElementById()
Это прекрасно. Сколько оверхеда даст парсинг селектора?
Думаете, простая работа со строками (разбить по пробелам, определить тип: тэг-класс-id) занимает больше времени, чем проходы по DOM-у?
Получится что-то в таком духе? (код не тестировал, написано просто из головы)
function $ (selector) {
	const chunks = selector.trim().split(/\s+/);
	if (chunks.length === 1) {
		const firstChar = chunks[0].charAt(0);
		const word = chunks[0].slice(1);
		if (firstChar === '#') {
			return document.getElementById(word);
		}
		else if (firstChar === '.') {
			return document.getElementsByClassName(word);
		}
	}
	else {
		return document.querySelectorAll(selector);
	}
}

Думаю, что да, это будет медленнее.

А в реальности код будет ещё сложнее, потому что у меня не учтены по-нормальному атрибуты и ряд других нюансов.

Всю статью можно было заменить этой ссылкой: You Might Not Need jQuery


Только вот внезапно окажется, что не вся функциональность jQuery пишется в одну-две строчки:


// jQuery
$('.inner').wrap('<div class="wrapper"></div>');

// Native
document.querySelectorAll('.inner').forEach(el => {
  const wrapper = document.createElement('div');
  wrapper.className = 'wrapper';
  el.parentNode.insertBefore(wrapper, el);
  el.parentNode.removeChild(el);
  wrapper.appendChild(el);
});

И если у нас реально много ручных DOM-манипуляций, то jQuery все еще остается хорошим выбором. Хотя лучше, конечно, взять какой-нибудь фреймворк из "большой тройки" :)

Поправка: el.parentNode.removeChild(el); можно не делать.

НЛО прилетело и опубликовало эту надпись здесь

Наговнокодили, лишились кроссбраущерности, но выиграли пару наносекунд

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации