Note: Below is the translation of the article “jQuery for JavaScript programmers” , in which the author expresses his opinion about this library, focusing primarily on advanced programmers, and gives several dozen examples of its use.
When
jQuery was released in January 2006, I thought: “another beautiful toy.” Choosing CSS selectors as a basis was, of course, an elegant idea (more details about it in my note
getElementsBySelector ), but the use of chains of transformations looked a little complicated, and the library itself, apparently, did not cover all possible cases. I then regarded jQuery only as a temporary and passing solution.
Only a few months later I realized how wrong I was with respect to her. jQuery is just a piece of engineering. It skillfully covers a fairly wide range of everyday functions while providing a convenient API for extensions with which you can add any other functionality. Abstraction is inherent at the kernel level — it’s about choosing DOM elements — and it extracts maximum benefit from it. And most importantly, using this library implies following a good programming style and combines well with other parts of JavaScript code.
')
Most current jQuery reviews focus on designers and inexperienced developers. I will try to explain why experienced programmers also need it.
Namespacing
The key to creating good JavaScript code for future use is careful namespace management. In JavaScript, there is a single global namespace (the
window
object), and many programmers (and even some libraries) litter it unnecessarily.
Global variables are evil! More prudent developers minimize their intrusion into this space using some methods, such as a
modular model .
jQuery introduces a single object into the global namespace - jQuery function / object. All the rest is either a direct jQuery property or a method of the object returned by a jQuery function call.
What can be said about language improvements? Most libraries provide some similarity to the display, filtering and clipping functions that, unfortunately, are missing from the JavaScript engines that are included in most browsers. Some libraries directly extend the built-in JavaScript classes String and Array, but also not completely safe. String.prototype and Array.prototype are separate global namespaces, and adding any properties to them entails the danger of collisions associated with using the same variable names in different contexts.
JQuery has a number of functions that extend the JavaScript feature, but each of them is available only as a property of the jQuery object:
jQuery.each
,
jQuery.extend
,
jQuery.grep
,
jQuery.map
,
jQuery.merge
and
jQuery.trim
. By definition, they will not conflict with any other code.
The infamous $
function
I was not completely honest when I said that jQuery only introduces one character into the global namespace, in fact there is also
$
: it is used as an abbreviation for jQuery. Thank God, this is done fairly gently: if you need your former
$
function again (for example, if you have a part of the code based on Prototype), you can call
jQuery.noConflict()
to return your old
$
function.
If you need to limit the use of the
$
function for jQuery without fear of collisions when you use the global
$
function in any other way, the jQuery documentation offers the following method:
(function ($) {
// Inside this block, <code> $ </ code> refers to jQuery
// Elegant, right?
}) (jQuery);
At the beginning, I considered the ubiquitous use of
$
in jQuery no more than a clever trick. But if we consider it only in the context of jQuery, then this solution looks very flexible, and I gladly use the abbreviation
$
in my own code.
Select items
Each jQuery statement begins with the selection of one or more DOM nodes.
The jQuery
selector syntax (the internal language of this library) is an interesting hybrid of the CSS 1, 2 specifications, some CSS 3, some XPath, and even a few other extensions. I will not go into details, just give some useful examples:
jQuery('div.panel')
All div
's with class="panel"
jQuery('p#intro')
Paragraph with id="intro"
jQuery('div#content a:visible')
All visible links inside a div
with id="content"
- jQuery ('input [@ name = email]')
jQuery('table.orders tr:odd')
All even rows in a table with
class="orders"
jQuery('a[@href^="http://"]')
All external links (those that start with
http://
)
jQuery('p[a]')
All paragraphs with at least one link
The most interesting of the above are
:visible
and
:odd
, which are specific only to jQuery. It is also worth noting that the choice of attributes uses the
@
sign, which corresponds more to XPath than CSS 2.
The language of selectors is very rich and very similar to regular expressions, so the time spent on learning it will pay off in full.
Do something with them
The object that jQuery selectors return is a pretty interesting beast. It is a set of DOM elements and behaves a bit like an array: it has the
length
property, its elements can be accessed by index and (more importantly)
Firebug regards it as an array when displayed in its console. This is nothing more than a beautiful illusion: a set of elements, in fact, is a jQuery object, which has a large number of methods for selecting, modifying, or expanding an existing set.
In jQuery, there are three different categories of methods: the first one manipulates all the elements that match the pattern, the second ones return the value from the first element found, and the third ones change the selection itself.
I will not list all the available methods (this can be viewed on
visualjquery.com ), but I want to give some examples. If you have Firebug, you can try them yourself: you just need to use the Insert jQuery tab (
javascript:void(function(){var s=document.createElement('script');s.src='http://code.jquery.com/jquery-1.1.2.js'; document.getElementsByTagName('head')[0].appendChild(s);}())
) to load the library itself for any page, and then paste the code samples to the Firebug console (
note: you can without Firebug: just load jQuery using the specified link and bring up the examples in the browser’s address bar, not forgetting javascript:
at the beginning and some alert
at the end (so that the return value is not displayed on the page). e) ).
jQuery('div#primary').width(300);
Sets the width of the div id="primary"
to 300 pixels.jQuery('p').css('line-height', '1.8em');
Sets the line height to 1.8em for all paragraphs.jQuery('li:odd').css({color: 'white', backgroundColor: 'black'});
Applies 2 CSS rules for each item in the list; note that the css () function can take a style sheet object instead of two lines.jQuery('a[@href^="http://"]').addClass('external').attr('target', '_blank');
Adds the "external"
class for all external links (those that start with http://
), then adds target="_blank"
to increase the difference. This example uses the call chain described below.jQuery('blockquote').each(function(el) { alert(jQuery(this).text()) });
For each blockquote tag on the page, it displays an alert message with its text content (including HTML tags).jQuery('a').html(' !');
Replaces all the text in the links on the page with the call "Click here!".
Below are a few examples of methods that return a value from the first element found in a pattern:
var width = jQuery('div').width();
What is the width of the first div
on the page?var src = jQuery('img').attr('src');
What is the value of the src
attribute for the first picture on the page?var color = jQuery('h1').css('color');
What is the color of the first h1
?
I want to note the convenient symmetry of such methods: they are used both for setting attributes (when taking 2 arguments or several properties of the object to be passed) and for reading the values of these attributes (if only one argument is passed). This symmetry is used throughout the jQuery library, which makes memorizing the API very easy.
Finally, there are several methods that modify the entire set of items found. Many of them also provide navigation through the DOM tree:
jQuery('div').not('[@id]')
Returns all div
that do not have an id
attribute.jQuery('h2').parent()
Returns all items that are direct parents of h2
.jQuery('blockquote').children()
Returns all items nested in blockquote
.jQuery('p').eq(4).next()
Finds the fifth paragraph on the page, then finds the next element (i.e., the immediate neighbor to the right).jQuery('input:text:first').parents('form')
Finds the parent element for the form that contains the first input type="text"
field on the page. An optional parameter for parents()
is another selector.
Call chains
The jQuery development team often brags about support in this call chain library, going as far as statements like “jQuery was created to change your JavaScript programming style” right on the main page. Honestly, I personally find this technique more likely a side branch than a road to the future, but I am happy to say that you can use jQuery, avoiding long call chains.
In short, chains can be used for several interesting tricks. In addition to using a set of DOM samples, you can use the
end()
jQuery method to move through the stack of objects and exit the current context. This is a bit difficult to explain, but when you use a method that changes the current (object) context (for example,
children()
or
filter()
), you can use
end()
little later to go back to the previous sample. Jesse Skinner gives a good example of using this feature in his tutorial.
Making AJAX development easier with jQuery :
$ ('form # login')
// hide all <code> label </ code> with the <code> optional </ code> class
.find ('label.optional'). hide (). end ()
// add a red border to all fields of type <code> password </ code> in the form
.find ('input: password'). css ('border', '1px solid red'). end ()
// add a handler to the <code> submit </ code> event for the form
.submit (function () {
return confirm ('Do you really want to send data?');
});
All this big conversion takes just one line. It finds a form, finds some elements inside it, applies changes to them, goes back to the form, and adds a
submit()
event handler to it.
This is a nice concept, but no one forces you to use it if you don’t want it. I was just happy to visually break my code with a few rather eloquent variable names.
Manipulate with DOM
JQuery has several ways for bulk manipulating the DOM. The first is somewhat unexpected: the jQuery function can take as an argument a piece of HTML code that is converted to a DOM element (in fact, it is just a string):
var div = jQuery ('<div> Some text </ div>');
You can use a call chain to add attributes to the
div
as soon as it was created:
var div = jQuery ('<div> Some text </ div>'). addClass ('inserted'). attr ('id', 'foo');
Now add it to the
body
tag:
div.appendTo (document.body)
Or paste it using the selector in the existing code:
div.prependTo ('div # primary')
We intercept events
All JavaScript libraries need methods for handling events, and jQuery is no exception. As in the case of
attr()
and
css()
, methods for events can serve two purposes: calling them with a function assigns an event handler as an argument, calling without an argument emulates the occurrence of this event:
jQuery('p').click(function() { jQuery(this).css('background-color', 'red'); });
For all paragraphs, we expose the mouse click handler, on which they turn red.jQuery('p:first').click()
We emulate click for the first paragraph on the page.
Similar functions are used for other browser events:
mouseover
,
keyup
, etc. It should be noted that when invoking an event handler, the
this
refers to the element that caused this event; using
jQuery(this)
is a common practice to call jQuery methods on this element.
A couple of functions related to events deserve special mention:
jQuery ('a'). hover (function () {
jQuery (this) .css ('background-color', 'orange');
}, function () {
jQuery (this) .css ('background-color', 'white');
});
hover()
is an abbreviation for two events at once:
onmouseover
and
onmouseout
.
jQuery ('p'). one ('click', function () {alert (jQuery (this) .html ());});
one()
sets an event handler to be deleted after its first call. In the above example, all paragraphs should
alert (
alert ) their content after the first click on them.
jQuery also supports its own events through
bind()
and
trigger()
methods (like
click()
). Own events can take arguments passed by the array in the
trigger()
call:
jQuery (document) .bind ('stuffHappened', function (event, msg) {
alert ('What happened:' + msg);
});
jQuery (document) .trigger ('stuffHappened', ['Hi!']);
Unobtrusive ( unobtrusive ) programming
This topic is very close to me. I still believe that the best web applications are those that can function even with scripts disabled, and unobtrusive javascript will be the best method to achieve this when events are assigned to elements only after the entire HTML page has user will boot (for more details you can familiarize yourself with
unobtrusive programming and
Hijax ).
JQuery has great support for this approach. First, the selector paradigm for node selection is fundamental for both jQuery and unobtrusive programming in general. Secondly, jQuery provides solutions for the
window.onload problem, based on Dean Edwards’s research on the operation of the “DOM loaded” event for various browsers (for
example, see more details about this issue in my translation published earlier ). You can set a handler function when the DOM is ready for it:
jQuery (document) .ready (function () {
alert ('DOM ready!');
});
And even more, you can abbreviate this entry by assigning your function directly to jQuery ():
jQuery (function () {
alert ('DOM ready!');
});
jQuery and AJAX
JQuery has the best AJAX API I've ever seen in large libraries. The simplest form of an AJAX call is as follows:
jQuery ('div # intro'). load ('/ some / fragment.html');
It will execute a GET request to
/some/fragment.html
and insert the HTML code into the
div#intro
that it will receive.
The first time I saw this, I was not very impressed. Just a beautiful abbreviation, but if you need something more complicated, for example, to display the AJAX-loading indicator? jQuery provides a set of custom events (
ajaxStart
,
ajaxComplete
,
ajaxError
and others) for use when necessary. Also in this library there is a more advanced low-level API for complex AJAX interactions:
jQuery.get ('/ some / script.php', {'name': 'Simon'}, function (data) {
alert ('Server replied:' + data);
}); // GET request to /some/script.php?name=Simon
jQuery.post ('/ some / script.php', {'name': 'Simon'}, function (data) {
alert ('Server replied:' + data);
}); // POST request to /some/script.php
jQuery.getJSON ('/ some.json', function (json) {
alert ('JSON issued:' + json.foo + '' + json.bar);
}); // Returns and converts the response from /some.json as JSON
jQuery.getScript ('/ script.js'); // GET request to /script.js and eval ()
Extensions
Considering this whole set of functions in the standard package, it is worth noting that the downloaded jQuery version takes up only 20 KB, and even less if you apply archiving (
.gz
). Additional functionality beyond the scope of this delivery can be organized with extensions that can (and do) add new methods to an existing jQuery object. If you like, you can do something like this:
jQuery ('p'). bounceAroundTheScreenAndTurnGreen ();
The extension mechanism in jQuery provides documented methods for adding them to the system. The simplicity and ease of use attracted a large community of authors of such extensions;
directory extensions has more than a hundred examples.
Another nice feature is the ability to add your own selectors as well as your own methods.
The moreSelectors extension adds methods like
div:color(red)
, which, for example, selects all
div
with red text.
Couple of words about holes
Studying jQuery with more respect, I ran into one philosophical problem. In recent years, I have advised my acquaintances to work with the JavaScript library only if they want to parse the source code and see how it actually works. My position was based on the classic article of Joel Spolsky - the
Law of Generalized Holes . In it, the author is based on the fact that the more complex your API is, the more difficult it will be to correct the situation when holes are found in it. Browsers are one of the most unreliable applications, so be prepared to tear your hair when you encounter a similar situation for your application, on which everything will depend.
In certain cases, jQuery uses truly unique methods to achieve this or that functionality: some parts (for example, the source code of selectors) of this library look daunting. If you so need an understanding of how the library works, then jQuery for most developers will not help much with this task. However, jQuery's immense popularity, coupled with a certain lack of bad reviews about it, seems to speak only in its favor.
I think I will have to reconsider my initial advice. Not so important how the library actually works. To understand this, you need to know some basic concepts, the differences between browsers and the set of methods that the library uses to get around them. No library can prevent incomprehensible browser behavior in 100% of cases, but the more knowledge you have about standards and underlying concepts, the easier it will be for you to determine if the problem lies in your code, in the library you are using, or in the implementation features that are inherent at their base.
As a conclusion
I hope I expressed enough facts for a positive conclusion about jQuery: it is not just
another library. It contains a lot of interesting ideas that can surprise even quite experienced JavaScript programmers and teach them something new. Even if you do not use it in your work, it is worth spending some time and exploring the jQuery “ecosystem”.
Thanks to everyone who read the article. I would appreciate comments on the topic.
Web Optimizator: checking the speed of loading sites