jQuery from the inside out - introduction

  • Tutorial
At work, I had to participate in interviewing candidates for the position of client sider in our company several times, to look at their knowledge in Javascript. Surprisingly, none of them really knew how jQuery works from the inside out, even those who marked their jQuery knowledge as “excellent”, alas.

JQuery has a very low entry threshold, it is often written and used about wherever possible (and even where, in general, it is not necessary), so some do not even look at pure Javascript. Why, they say, know him when there is jQuery, and on it - tons of examples and ready-made plugins? Even on Habré I saw an article about drawing on Canvas, where the author connected jQuery and used it only once - in order to access Canvas by its identifier. And he did not consider it something abnormal.

Sorry, distracted. The essence of the post and the following parts of the series is to talk about how the library works from the inside and what happens in it as some methods are executed.

Source code


The project sources are here . Everything is divided into several modules, it is assembled (by someone even successfully) into one with the help of Grunt . For analysis in the article, I will use the code of the latest stable version (at the time of writing, this is 1.8.3).

Figuratively, in this article we will consider a script that can be obtained by gluing intro.js. core.js, [sizzle] (briefly), sizzle-jquery.js, support.js (also briefly), and outro.js.

The intro.js and outro.js scripts are needed just to wrap the library code in an anonymous function, so as not to litter the window. The window and undefined parameters are passed to the function (this parameter is not passed, and therefore undefined). What for? Such variables do not change their names during minification, but the names of function parameters are compressed and such manipulations result in serious profit.

Initialization


The first thing we do when loading jQuery is working out core.js , the core of the framework. What happens at the initialization stage, in addition to declaring a ton of RegExp and variables used later:

First of all, links to jQueryits alias are saved $, when they are already in the window. This is done in case the noConflict function is called , which returns the $ object (and if noConflict is set to true, then jQuery) back to its place, and as a result of its work gives us the jQuery described already in this script itself. The function is useful when you plan to use your code and jQuery on a third-party resource and do not want to break anything to people.

A local function is created.jQuery, which is a kind of "constructor", which takes on a selector and context. A function that developers work with most of their time. That it will be at the very end exported to window.jQueryand window.$( exports.js ). Further, this object will expand, by adding additional methods to its prototype ( jQuery.prototype, it is - jQuery.fn). The aforementioned “constructor” calls one of the methods in jQuery.fn- init , about it a little later.

Attention, magic:
jQuery.fn.init.prototype = jQuery.fn
That is why, from the result of the work of this very “constructor”, you can always reach out to all jQuery methods.

Actually, it is jQuery.fnexpanded by basic methods, among which jQuery.extend , with the help of which the objects are expanded, including the further expansion of the functionality of jQuery itself.

Service is created hash class2type, which is necessary framework for the work function type and its derivatives ( isArray, isFunction, isNumericetc.). Here you can pay attention to special magic - the usual typeofone is not very convenient for defining some types of variables, therefore this method exists for this in jQuery. Accordingly, its implementation is slightly different from the usual one typeof.

And finally, a rootjQueryvariable is created in which the result of the execution lies jQuery(document); it is with respect to it that the elements from will be searched for initif the context is not set directly by the developer.

Everything seems to be relatively simple, but all this concerns only core.js. Any module does something when loading and it is better to consider them separately. We separately mention support.js, in which immediately upon initialization a lot of tests are carried out to determine the capabilities of the browser.

JQuery object


So what is a jQuery object and why?

Usually the result of the work $([какой-то селектор])is approximately the following object:

{
    0: Элемент,
    1: Элемент2,
    context: Элемент
    length: 2,
    selector: ‘тот самый какой-то селектор’
    __proto__: (как и писали выше, прототип у объекта - jQuery.fn)
}

It is because of the property that for lengthsome reason many are mistaken and think that it is actually an array. In fact, the length property is manually maintained inside jQuery and is the number of returned elements that are located in the object’s indexed keys indexed from scratch. This is done precisely so that you can work with this object as an array. The selectorselector string is placed in the property , if we searched by it, and in the contextcontext by which we searched (if not specified, then it will be - document).

Remember that any jQuery function that is not intended to return any special results always returns an object whose prototype is - jQuery.fnthanks to which you can build quite large chains of calls.

jQuery.fn.init


So, what happens when we do something like $([какой-нибудь селектор])? Read carefully? That's right, the same "constructor" will be called. To be more precise - we will return new jQuery.fn.init([тот самый селектор]).

First, the function will check whether the selector is passed to it at all, and if it is not passed (or an empty string is passed, null, false, undefined) - in this case we will return an empty jQuery object, as if we had accessed it through window. $.

Then it will be checked whether the selector is a DOM element. In this case, jQuery will return the object directly with this element. Example with $(document.body):
{
    0: <body>,
    context: <body>,
    length: 1,
    __proto__: ...
}

If the selector is a string, then relative to the context (if there is no context, then this is document, see about rootjQueryabove), the find method of the specified selector will be executed , i.e.:
$('p', document.body) -> $(document.body).find('p')
$('p') -> rootjQuery.find('p')

If the selector is something like #id, then the usual one will be called to search for the element document.getElementById(hello, dude with Canvas from the beginning of the article).

But if instead of the selector html code is transmitted (this is determined by the presence of the opening tags of the tag at the beginning of the line and the closing at the end), jQuery will try to parse it ( parseHTML , which we will discuss in more detail in the next part ) and create these elements on the basis of it and return the result already with them. Here is what we get as a result of work :$('

Йо-хо-хо

я - на втором уровне')

{
    0: <h1>
    1: <p>
    length: 2
    __proto__: ...
}

Pay attention to the span inside the paragraph - in the results it will also be inside it, in the element with index 1.

For cases when a function is input instead of a selector, jQuery will call it when the document is ready for work. Here promise is used , which should highlight a separate chapter. For some reason, many people use a slightly longer analogue - $(document).ready( callback )(in the comments they say that - more readable), but in the end it turns out the same.

jQuery.find


To search for a document in the library jQuery uses Sizzle , so that find, as well as the methods expr, unique, text, isXMLDocand containsa direct link to the corresponding methods of Sizzle, or are simple methods wrapper over them. How selectors work in jQuery was written more than once and on Habr it is possible to find all this. As a result of the work, findwe get the same jQuery object with all the elements found.

On a separate line, I dare say that neither jQuery nor Sizzle cache the results of the method find. And why would they do that? Do not pull the method often unnecessarily, if it is possible to find everything in advance - find and put in a separate variable.

If Sizzle doesn’t suit you with something, but it happens, you can use something of your own (or someone else's) instead, see sizzle-jquery.js , this is where the links to methods from Sizzle are created. In this case, do not forget to throw Sizzle out of the build.

Conclusion


jQuery is growing and growing, now the library has grown to almost 10 thousand lines of code (excluding Sizzle). Nevertheless, the source code is divided into several files, neatly written and even commented in places. Do not be afraid to peek there, but even vice versa - if you feel that you don’t know how what you want to use works, do not be too lazy to look at the library sources. This applies not only to jQuery, but to any library in general.

Remember that jQuery is a library whose purpose is not only to make life easier for the developer by concise code that is obtained with its help, but also to make one interface for working in all possible browsers, including prehistoric ones, which adds a certain overhead. That is why it is important to know what the library does for you. In some cases, you can do without these one hundred kilobytes (remember that you still see the Edge icon on your phones) and without overhead on calls and testing the capabilities of the browser. For example, when writing an extension for Chrome or Firefox, with a probability of 90%, it will not bring you any profit.

My article was not as big as I was afraid of and it’s very good - it will be easier to read (I hope). In the field of professional web development, I’m only 7 years old, therefore, as a beginner, of course, I may not know something, and know something - not quite (completely) wrong or not completely. Feel free to correct me, supplement, criticize, ask.

PS As it turned out, Habré already has an article on this topic from the wonderful author of TheShock - How jQuery works : we study the source . I’m leaving my article because someone has already added it to my favorites and it is unlikely that I will be delighted with the inscription “the article is placed in draft copies”.

Content Cycle


  1. Introduction
  2. DOM manipulation
  3. Attributes, properties, data

Also popular now: