Реализация, аналог и адаптация для «чистого» JavaScript'а JQuery функции JQuery(); и прилегающие к ней
Когда-то библиотека jQuery была хорошим помощником для программистов. Так как она позволяла в разы облегчить создание функционала, который в то время с помощью одного JavaScript было почти нереально написать, и предоставляла очень хорошую кроссбраузерность.
Сейчас же JavaScript получил множество больших обновлений, функции в которых получили большое количество полифиллов и могут заменить функции jQuery. Но, к сожалению, JS до сих пор не научился делать большинство функций, которые присутствуют в jQuery.
В этой статье я расскажу про самую главную функцию jQuery — jQuery(); .
Функция JQuery(); состоит из двух функций — основной и так называемой обложки. Вы запускаете обложку, обложка запускает основную функцию и возвращает из неё результат.
Обложка выглядит следующим образом:
Как видно из кода, когда мы запускаем функцию jQuery(); она запускает функцию init с теми же параметрами из своего прототипа. Именно функция init является основной.
Далее нам следует создать прототип для нашей функции, в конструкторе которой мы будем ссылаться на функцию jQuery. Заметка: в старых версиях jQuery, параметр constructor не указывается.
Дело в том, что разработчики приравняли объект jQuery.prototype и jQuery.fn , тем самым задав для двух параметров один объект, чтобы иметь возможность более кратко добавлять новые функции для объектов.
Теперь начнём создавать основную функцию. Я не буду расписывать полную структуру функции, т.к. это займёт у меня минимум неделю, а напишу как реализуется более краткий вариант по примеру jQuery.
У jQuery вся функция состоит из условий, которые перебирают данные полученные функцией, и массива, в который скидываются нужные элементы.
Начальный вид функции выглядит так:
Рассмотрим первое условие — если селектор является строкой. Если это строка, то нам следует проверить: это селектор или HTML код (ведь jQuery таким образом может парсить HTML код).
В jQuery для проверки, является ли первый аргумент HTML кодом, используется регулярное выражение проверка первого, последнего символов и общее количество символов, которое должно быть больше либо равно трём.
Если первый аргумент является HTML кодом, то происходят следующие действия:
-
С помощью специальных функций, парсится HTML код и живой массив, который вернула функция парсинга, объединяется с основным массивом.
К сожалению, я не расскажу про то, как реализована эта функция, т.к. у неё слишком много ответвлений, про которые можно писать отдельную статью. Но вы не расстраивайтесь, про то, как работает эта функция, уже написали. Вы можете прочитать эту статью перейдя по следующей ссылке: habrahabr.ru/post/164533
Я же расскажу вам про альтернативные функции, с помощью которых можно реализовать данный функционал.
-
Первая альтернатива — создадим элемент, в который с помощью innerHTML внесём нашу строку с кодом и заберём уже готовые DOM элементы.
Если мы заглянем в исходники jQuery, то увидим, что у них данная функция реализуется следующим образом:
Альтернатив у функции jQuery.merge() есть несколько:
-
Первой альтернативой является функция Array.concat(); , которая объединяет массивы.
Но данная функция не подойдёт, если вы хотите присоединить к массиву HTML коллекцию или список Node, так как у вас выведется массив в массиве, вместо объединения.
Но это довольно легко исправить: нужно преобраовать живой массив в обычный. Это можно сделать с помощью функции [].slice.call() .
Или же это можно сделать перебрав все элементы живого массива и переместив их в обычный массив.
Поиск элементов по селектору, с помощью этой библиотеки, выглядит следующим образом:
Но я воспользуюсь её JavaScript альтернативой — document.querySelectorAll( String selector ); . Единственный недостаток этого метода перед библиотекой Sizzle — он начинает работать только с IE9+.
Прежде чем выводить элементы по селектору, нам нужно проверить аргумент context и убедится, что он не является элементом или элементами, в которых нужно искать элементы по селектору. Я не буду расписывать каждый шаг, так как в коде объяснил все шаги.
В jQuery все эти проверки заменены функцией поиска — .find(); . Поэтому запись jQuery(selector, elements); является сокращённой функцией jQuery(elements).find(selector);
Сейчас наша основная функция выглядит следующим образом:
Теперь рассмотрим второе условие — если селектор является DOM элементом. Если селектор является DOM элементом, то мы просто вставляем этот элемент в основной массив, который потом выводим.
Перейдём к третьему условию — если селектор является массивом. Если если это массив, то мы объединяем его с основным массивом, который потом выводим. Объединять массивы мы будем с помощью вышенаписанной функции.
Теперь о четвёртом условии — если селектор является объектом с параметрами. Если селектор является объектом с параметрами, то как и в варианте с DOM элементом, просто вносим объект в массив и выводим.
Рассмотрим пятое условия — если селектор является живым массивом. Если селектор является живым массивом, то мы переносим элементы с него в основной массив. Действия выглядят, как и в случае с массивом.
Осталось рассмотреть последнее условие — если селектор является функцией. Когда селектор — функцией, то функция jQuery( Function ); является сокращённой функцией jQuery(document).ready( Function ); .
Когда мы посмотрим в исходники jQuery, то увидим, что там данная функция реализуется следующим образом:
Если мы рассмотрим код, то увидим, что он построен на двух отдельных вариантах запуска скрипта после загрузки DOM:
-
Первый вариант — запуск скрипта через событие DOMContentLoaded повешенного на document . Этот вариант будет работать начиная с IE9+.
-
Один из простых способов ― перенести <script></script> в body после всех элементов. При таком расположении сначала загрузится DOM, а потом скрипт.
Эту функцию я заменю одной из альтернатив — событием readystatechange , о которой писал выше.
Всё, мы записали действия для всех условий и наша функция практически готова. Осталось к параметру __proto__ основного массива присвоить прототип главной функции, чтобы потом можно было создавать дополнительный функционал для jQuery объектов. Объект __proto__ довольно новый и начинает работать только с IE11+. Поэтому мы сделаем некий полфилл.
Функция готово. В конечном итоге она будет выглядеть следующим образом:
Теперь мы можем использовать функцию, как в обычном jQuery и писать для его объектов новые функции через прототип.
На этом я закончу эту статью. Главное помнить: jQuery тоже написан на JavaScript :)