From the jQuery API docs site for ready
All three of the following syntaxes are equivalent:
$(document).ready(handler)
$().ready(handler) (this is not recommended)
$(handler)
After doing homework - reading and playing with the source code, I have no idea why
$().ready(handler)
is not recommended. The first and third ways, are exactly the same, the third option calls the ready function on a cached jQuery object with document:
rootjQuery = jQuery(document);
...
...
// HANDLE: $(function)
// Shortcut for document ready
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
But the ready function has no interaction with the selector of the selected node elements, The ready source code:
ready: function( fn ) {
// Attach the listeners
jQuery.bindReady();
// Add the callback
readyList.add( fn );
return this;
},
As you can see, it justs add the callback to an internal queue( readyList) and doesn't change or use the elements in the set. This lets you call the ready function on every jQuery object.
Like:
regular selector: $('a').ready(handler) DEMO
Nonsense selector: $('fdhjhjkdafdsjkjriohfjdnfj').ready(handler) DEMO
Undefined selector:$().ready(handler) DEMO
Finally... to my question: Why $().ready(handler) is not recommended?
I got an official answer from one of the jQuery developers:
$().ready(fn) only works because $() used to be a shortcut to $(document) (jQuery <1.4)
So $().ready(fn) was a readable code.
But people used to do things like $().mouseover() and all sorts of other madness.
and people had to do $([]) to get an empty jQuery object
So in 1.4 we changed it so $() gives an empty jQuery and we just made $().ready(fn) work so as not to break a lot of code
$().ready(fn) is literally now just patched in core to make it work properly for the legacy case.
The best place for the ready function is $.ready(fn), but it's a really old design decision and that is what we have now.
I asked him:
Do you think that $(fn) is more readable than $().ready(fn) ?!
His answer was:
I always do $(document).ready(fn) in actual apps and typically there's only one doc ready block in the app it's not exactly like a maintenance thing.
I think $(fn) is pretty unreadable too, it's just A Thing That You Have To Know Works™...
Since the different options do pretty much the same thing as you point out, it's time to put on the library writer hat and make some guesses.
Perhaps the jQuery people would like to have $() available for future use (doubtful since $().ready is documented to work, even if not recommended; it would also pollute the semantics of $ if special-cased).
A much more practical reason: the second version is the only one that does not end up wrapping document, so it's easier to break when maintaining the code. Example:
// BEFORE
$(document).ready(foo);
// AFTER: works
$(document).ready(foo).on("click", "a", function() {});
Contrast this with
// BEFORE
$().ready(foo);
// AFTER: breaks
$().ready(foo).on("click", "a", function() {});
Related to the above: ready is a freak in the sense that it's (the only?) method that will work the same no matter what the jQuery object wraps (even if it does not wrap anything as is the case here). This is a major difference from the semantics of other jQuery methods, so specifically relying on this is rightly discouraged.
Update: As Esailija's comment points out, from an engineering perspective ready should really be a static method exactly because it works like this.
Update #2: Digging at the source, it seems that at some point in the 1.4 branch $() was changed to match $([]), while in 1.3 it behaved like $(document). This change would reinforce the above justifications.
I would say its simply the fact that $() returns an empty object whereas $(document) does not so your applying ready() to different things; it still works, but I would say its not intuitive.
$(document).ready(function(){}).prop("title") // the title
$().ready(function(){}).prop("title") //null - no backing document
More than likely this is just a documentation bug and should be fixed, the only downside to using $().ready(handler) is it's readability. Sure, argue that $(handler) is just as unreadable. I agree, that's why I don't use it.
You can also argue that one method is faster than another. However, how often do you call this method enough times in a row on a single page to notice a difference?
Ultimately it comes down to personal preference. There is no downside to using $().ready(handler) other than the readability argument. I think the documentation is miss-leading in this case.
Just to make it patently obvious that there is some inconsistency in the three, plus I added the fourth often used form: (function($) {}(jQuery));
With this markup:
<div >one</div>
<div>two</div>
<div id='t'/>
and this code:
var howmanyEmpty = $().ready().find('*').length;
var howmanyHandler = $(function() {}).find('*').length;
var howmanyDoc = $(document).ready().find('*').length;
var howmanyPassed = (function($) { return $('*').length; }(jQuery));
var howmanyYuck = (function($) {}(jQuery));
var howmanyYuckType = (typeof howmanyYuck);
$(document).ready(function() {
$('#t').text(howmanyEmpty + ":" + howmanyHandler + ":"
+ howmanyDoc + ":" + howmanyPassed + ":" + howmanyYuckType);
});
The displayed results of the div from the last statement are: 0:9:9:9:undefined
SO, only the Handler and Doc versions are consistent with the jQuery convention of returning something of use as they get the document selector and with the Passed form you must return something (I wouldn't do this I would think, but put it in just to show "inside" it has something).
Here is a fiddle version of this for the curious: http://jsfiddle.net/az85G/
I think this is really more for readability than anything else.
This one isn't as expressive
$().ready(handler);
as
$(document).ready(handler)
Perhaps they are trying to promote some form of idiomatic jQuery.
Related
If I define a JavaScript code snippet in my HTML, like so:
<div id=myElem onMyUpdate="alert('Update called for ' + this.id)">...
then what is the most elegant way of evaluating it from within JavaScript with this properly assigned?
What I came up with so far is something like this:
if (elem.hasAttribute('onMyUpdate'))
(function () { eval(elem.getAttribute('onMyUpdate')) }).call(elem);
which looks terrible (to me), but works. Any better/more elegant alternatives?
MDN says there used to be the second argument to eval() for doing just that but it's deprecated now; MDN then suggests to use operator with() instead, which, if you follow the link provided, turns out to be made deprecated by the latest standard. Dead end, in other words.
(As a side note, StackOverflow ignores the word this in search terms and thus it may miss relevant answers - is there a way of telling it not to?)
Edit: I forgot to mention: no jQuery please, just vanilla JavaScript
How about this:
if(elem.hasAttribute('onMyUpdate')) {
var fun = new Function(elem.getAttribute('onMyUpdate'));
fun.call(elem);
}
Ideally, you should do this completely unobtrusively, and without the use of eval:
<div id="myElem"></div>
.
var elem = document.getElementById('myElem');
elem.onMyUpdate = function () {
alert(this.id);
};
// ...
elem.onMyUpdate && elem.onMyUpdate();
Instead of using this you can use elem.
<div id=myElem onMyUpdate="alert('Update called for ' + elem.id)">...
js:
if (elem.hasAttribute('onMyUpdate')){ // all variable available here will be available inside eval.
eval( elem.getAttribute('onMyUpdate') );
}
A more elegant solution would be to use custom events, bind handlers to some custom events on your HTML elements and trigger them in some other parts of your code. See this tutorial and the answer by Sidharth Mudgal for some examples.
Does creating and reusing a reference increase performance appreciably when the selector is $(this)?
I create references for my jQuery selectors when I use the same selector multiple times in the same scope. The following is more efficient
var jSel = $('div.some_class input.some_other_class');
some_function1(jSel);
some_function2(jSel);
than this
some_function1($('div.some_class input.some_other_class'));
some_function2($('div.some_class input.some_other_class'));
But what if the selector is simply $(this) where this is a dom element inside a jQuery method. Should I bother to create a reference to $(this) and reuse the reference or can I create multiple $(this) selectors and expect similar performance?
Is the following
var jSel = $(this);
some_function1(jSel);
some_function2(jSel);
significantly faster than the following?
some_function1($(this));
some_function2($(this));
Is the following significantly faster than the following?
No. It is microscopically faster; in the realms of just a few microseconds.
Does that stop you assigning the result to a variable and using that? No. Using a variable can give more meaning to what this is, and can be easier to type. Plus, if you stopped wanting to operate on $(this), and instead wanted $(this).next(), you have to change it in one place instead of n.
You'll find the jQuery constructor is highly optimized for accepting a single DOM element as a parameter. The following is the exact code that gets executed when you call $(DOMElement) (after the jQuery object has been created, of course):
var match, elem, ret, doc;
// Handle $(""), $(null), or $(undefined)
if ( !selector ) {
return this;
}
// Handle $(DOMElement)
if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
}
// Handle lots of other param types, but we hit the above one, so we've stopped now...
It all depends on how many calls you make. It's certainly faster to set a variable equal to something that does work than to keep doing the same work, but the difference will be extremely negligible in your sample. If you're doing this in a loop of 5 million, the difference will be less negligible and setting the variable will be faster as it only does the work once and not 5 million times.
In this particular case, if you're really writing functions that expect a jQuery object as a parameter (as in your examples), you could just re-write those functions as jQuery methods. Then you could write:
$(this).some_function1().some_function2();
It's pretty easy to write jQuery methods, at least simple ones. The general (again, simple) form is:
jQuery.fn.some_function = function() {
return this.each(function() {
// stuff you want to do
});
};
this is a reference to the object. Using $(this) takes a bit of time (because of jQuery turning it into an array) but this time is irrelevant IMHO. So the first method should be a bit faster, but actually you won't notice the difference.
http://jsperf.com/jquery-cache-vs-no-chace
Should give you a basic idea of speed difference. In most of the simple cases it probably wouldn't affect your code execution speed noticeably but where JS is a bottleneck every bit helps + it's always a best choice to make good practices a routine!
A lil benchmark:
http://jsperf.com/jquery-this-selector-performance
I've been enjoying Lynda.com's Jquery Essential Training, and I've noticed that in the beginning the instructor uses:
Fig. 1
$("document").ready(function(){
fun stuff goes here
});
However, somewhere along the line he starts using:
Fig. 2
$(function(){
fun stuff goes here
});
From the way he speaks, it sounds as if they are completely synonymous (some inherent jquery shorthand?) but as far as I can tell, it's never explicitly touched upon.
I'm sure someone could clear this up quickly for me. I found this but I believe that question is slightly different--I understand the concept of calling a function on document ready versus one that is globally available; (those functions also have names.)
The instructor uses phantom functions (I think that was the term for a function without a name,) and when typing out Fig. 2, he says "So this will be on document ready..."
Yes, they are exactly the same, just aliases.
From the jQuery site:
All three of the following syntaxes are equivalent:
$(document).ready(handler)
$().ready(handler) (this is not recommended)
$(handler)
The default context is the document, so if you pass in some random mumbo jumbo string that does not reference an HTML node, it will be the document.
$('fdsljkfdslj').context is document. And because the default context is the document, this means you don't have to specify it and can just feed a function to jQuery, $(function() { });
And I think you mean $(document) instead, since specifying the string document isn't as popular, because document passes the real document object to jQuery. But again, this will be the same as passing nothing or mumbo jumbo string since we pass document literally.
I had that question in mind for a long time.
Theoretically, jQuery core function accepts an optional value that can be a DOM element - $(".searched",$("#context")[0]) - or a jQuery object - $(".searched",$("#context") ) .
I discovered that last question reading that fine article.
But i really cant see the difference between use a context and pass a more complex css expression. If there is no difference in the way it works, is there any perfomance difference?
Thanks
It gets converted to a DOM element (in Sizzle, the context portion) to search in either of your cases, ultimately doing a .find() under the covers.
If you're concerned about performance (why not be as fast as possible?), you should use this instead:
$("#context .searched")
This version gets converted back into a jQuery object:
$("#context")[0]
So it's a bit slower on the jquery side, since it has to be wrapped in a jquery object before the .find() call, that performance difference is very minimal, but it's the only difference so I'm noting it :)
The major difference would be that $(".searched", context); can take a variable as a context as well. It is effectively doing $(context).find('.searched'); under the hood, and I think the second version is more readable anyway, so I usually use that.
The use for this situation would be something like this:
$.fn.highlightSearch = function() {
return this.each(function() {
$('.searched', this).addClass('highlighted');
// the commented line performs the same thing:
// $(this).find('.searched').addClass('highlighted');
});
};
$('#context').highlightSearch();
$('.somethingElse').highlightSearch();
Notice that in this case, you can't simply append the new selector on the end of the original.
If you have no other reason to hold a copy of $('#context'), then using $('#context .searched') is going to be quicker, and simpler. However, if you already had $('#context') stored in a variable, its better to use .find(select) or the $(selector, context) form to search for your contained elements.
Readability: a CSS selector like $("#context .searched") is far more readable than the other.
I find myself doing a lot of this kind of JQuery:
$('.filter-topic-id').each(function () {
var me = $(this);
if (me.text() == topics[k]) {
me.parent().show();
}
});
I store $(this) in a variable called me because I'm afraid it will re-evaluate $(this) for no reason. Are the major JavaScript engines smart enough to know that it doesn't have to re-evaluate it? Maybe even JQuery is smart enough somehow?
They are not smart enough to know not to revaluate $(this) again, if that's what your code says. Caching a jQuery object in a variable is a best practice.
If your question refers to your way in the question compared to this way
$('.filter-topic-id').each(function () {
if ($(this).text() == topics[k]) { // jQuery object created passing in this
$(this).parent().show(); // another jQuery object created passing in this
}
});
your way is the best practice.
Are the major JavaScript engines smart enough to know that it doesn't have to re-evaluate it?
No. But if you are using jQuery you are presumably aiming for readability rather than necessarily maximum performance.
Write whichever version you find easiest to read and maintain, and don't worry about micro-optimisations like this until your page is too slow and you've exhausted other more significant sources of delay. There is not a lot of work involved in calling $(node).
You could try to profile your code with Firebug and see if using $(this) many times slows your app or not
There is no good way that a javascript can determine that the following is true:-
fn(x) == fn(x);
Even if this was possible not calling the second fn could only be valid if it could be guaraneed that fn has not have other side-effects. When there is other code between calls to fn then its even more difficult.
Hence Javascript engines have no choice but to actually call fn each time it is invoked.
The overhead of calling $() is quite small but not insignificant. I would certainly hold the result in a local variable as you are doing.
this is just a reference to the current DOM element in the iteration, so there's little or no overhead involved when calling $(this). It just creates a jQuery wrapper around the DOM element.
I think you'll find that calling the jQuery function by passing a dom element is perhaps the least-intensive of ways to construct the object. It doesn't have to do any look-ups or query the DOM, just wrap it and return it.
That said, it definitely doesn't hurt to use the method you're using there, and that's what I do all the time myself. It certainly helps for when you create nested closures:
$('div').click(function() {
var $this = $(this);
$this.find("p").each(function() {
// here, there's no reference to the div other than by using $this
alert(this.nodeName); // "p"
});
});