I am sorry if this is a dumb or easy question but I am fairly new to Javascript/jQuery. The past month I have really started to delve into the land of scripting and have seen two different, maybe three, ways people use var in Javascript/jQuery.
The way I use a var is like so,
var nav = $('nav');
nav.hide();
A very common way I have seen people use vars,
var nav = $('nav');
$(nav).hide();
From the answers,
var $nav = $('nav');
$nav.hide();
From what I have learned from searching through Google is what you typed inside the variable is saved there to later be used. I then figured if I wrote the $() around the var when I was using it, it would duplicate the $(). Yet both ways seem to work so I know it does not duplicate it and therefore can tell that it is the same thing.
Is there a correct way to use vars or are both equally the same and it doesn't matter?
I apologize again if this is a known answer and will be happy to remove it if someone can show me the original question but I couldn't find anything on it.
A great bit of information from an answer that I didn't mark as the answer but I find to be very important.
var element = document.createElement("div");
$("body").append(element);
$(element).hide();
In the example above, $(element) is necessary, because it takes a DOM
object and converts it to a jQuery selector. jQuery functions only
work on jQuery selectors, so you couldn't simply do element.hide().
$() creates a new jQuery object. If you save a jQuery object to a variable it is pointless to create another jQuery object from it, although it still works. You will often see people wrap variables that were previously created as jQuery objects in $() purely due to bad practice and either forgetting it's already an object...or not understanding what they just created in the first place
Perhaps you may have seen
var $nav = $('nav');
$nav.hide();
Using the $ prefix is a common practice to denote that the variable is a jQuery object for code readability mostly
Both variables store a jQuery object, which has access to jQuery methods. The latter approach unnecessarily tries to re-wrap that jQuery object in another jQuery object. The former approach is 'correct,' in that it's more efficient and less, to be frank, silly.
I've seen this issue in a lot of places. People use a lot of $ when they don't need to. Some use it just as an ornament on their variable name, which adds to the confusion.
First of all, there are no jQuery variables, only JavaScript variables, and as you said, variables store information. When the right hand side begins with $(), you're storing the results of a jQuery function in the variable. In the vast majority of cases, what you'll be storing is called a jQuery selector.
In the case of var nav = $('nav'), what you're storing is a selector representing all the elements in the DOM that are nav tags, i.e. that look like <nav></nav> (or equivalent).
As others already mentioned, the $(nav) is taking the stored selector, and creating a new selector out of it. It accomplishes nothing and is redundant, and is a poor programming practice, even if it is a pervasive one.
However, there is a similar syntax that makes sense:
var element = document.createElement("div");
$("body").append(element);
$(element).hide();
In the example above, $(element) is necessary, because it takes a DOM object and converts it to a jQuery selector. jQuery functions only work on jQuery selectors, so you couldn't simply do element.hide().
As I mentioned at the top, some people also use $ as a decorator on their variable names, e.g. var $selector = $("nav"). The $ on the left hand side means nothing - it's just a character in a variable name, but they use it as a convention to remind themselves that they're storing a jQuery selector. I'd avoid it, simply because it adds to the confusion, but it's out there, so I just wanted to mention it.
var is used to create any kind of variable. Could be var diceRoll = 4 or var myMessage = "Hello!", or anything else.
$ is a function that jQuery provides, which behaves in different ways depending on what you pass to it. For example, if you pass it a string (e.g. 'nav'), it will find every nav element in the document and return a set of jQuery objects (elements) - one for each DOM element it finds. When you say var nav = $('nav');, you are assigning this set of jQuery objects to your nav variable, so you can work with it later. So far so good.
Instead of passing a string to $, you technically could pass jQuery objects back into the $ function, which is what you are doing when you say $(nav).hide();. DOING THIS MAKES LITTLE SENSE - it will just return the same array of jQuery objects, nav, which you put into it in the first place!!
Personally, I like to prefix any variable which holds a jQuery object with a $ sign, i.e. var $nav = $('nav');. This is just a convention that allows me to see at a glance that this variable holds a jQuery object (element) rather than a native DOM element, or integer, or so on. If I ever see $($myVar) in my code, I know it's probably time for bed...
Update: there are other things that it DOES make sense to pass into the $() function, apart from strings. Passing in a DOM element, for example (such as saying $(document)) creates a jQuery object representation of that DOM element, which can be very useful.
All of these answers are pieces to the entire answer . . . let me add yet another piece. :)
As others have said, the $(...) notation is a JQuery function that returns a JQuery object. Depending on what "..." is, determines how that is done.
Some examples:
if you put a selector, such as "div", in there, you will get a JQuery object that contains all of the DOM elements that match the selector pattern . . . in this case, all of the <div> elements.
if you pass a string representation of an HTML element (e.g., "<div></div>"), you will get a JQuery object that points to a newly created <div> element.
if you put a DOM node reference in there (e.g., one created by using document.getElementsByTagName("div")), it will create a JQuery object that points to that node(s) in the reference.
The whole point of this is that JQuery works with JQuery objects, so these various functions help programmers create them.
Now this is where we get to your question . . .
Each time you use $("..."), you are creating a brand new object, so, for example the following code will produce two unique JQuery objects, each of which pointing to the identical DOM elements:
var $firstObject = $("div");
var $secondObject = $("div");
So, if you do a comparison of them (like this ($firstObject === $secondObject)), they will not be seen as equal, because they are not the same object.
Now, let me do a slight variation of your second example to add a little more clarity. If you create a third variable and set it equal to the second one, like this:
var $thirdObject = $secondObject;
. . . you have two elements that are actually pointing to the same JQuery object, so they ARE actually equal (i.e., ($secondObject === $thirdObject) will evaluate as true).
Now finally, what you've shown with this peice of code:
$(nav).hide();
. . . is simply another example of trying to create a JQuery object . . . this time using another JQuery object. Doing this with that third variable that I created above, however, will now break the relationship that it has with the second variable . . . ($secondObject === $($thirdObject)) . . . they are no longer equal, because the two sides of the comparison no longer point to the same object. Much like the comparison between $firstObject and $secondObject from earlier, that comparison is using two unique JQuery objects.
However . . .
Unlike some of the other answers, I would disagree that it is a completely incorrect form of coding . . . while I would never use it in the situation that you provide in your example, passing a JQuery object into the $(...) function is essentially the same thing as using .clone(). The two $bar assignments below are functionally equivalent:
var $foo = $("<div></div>");
var $bar = $($foo);
var $bar = $foo.clone();
The JQuery API even makes the same point (http://api.jquery.com/jQuery/):
Cloning jQuery Objects
When a jQuery object is passed to the $() function, a clone of the object is created. This new jQuery object references the same DOM elements as the initial one.
EDIT :
Out of curiosity, I set up a quick test at jsPerf and the $($foo) approach is pretty significantly faster than .clone() in Firefox, IE9, and Chrome: http://jsperf.com/clone-technique-test
var nav = $('nav');
$(nav).hide();
nav is already a jQuery object so $(nav) is useless.
Related
I was just wondering which is the correct or most efficient way of navigating through the Dom using variables.
For example, can I concatenate selectors
var $container = '.my-container';
$($container).addClass('hidden');
$($container + ' .button').on('click', function(){
//something here
});
or should I use the jQuery traversal functions
var $container = $('.my-container');
$container.addClass('hidden');
$container.children('.button').on('click', function(){
//something here
});
Is there a different approach, is one best, or can you use them at different times?
The $ is usually used only when working with an actual jquery object. You generally shouldn't prefix anything with that unless it's really something from jquery.
Beyond that little bit though, performance-wise, your second bit of code is going to be faster. I made an example jsperf here: http://jsperf.com/test-jquery-select
The reason the second bit of code is faster is because (if I remember correctly) jquery caches the selection, and then any actions performed on that selection are scoped. When you use .find (which is really what you meant in your code, not .children), instead of trying to find elements through the entire document, it only tries to find them within the scope of whatever my-container is.
The time when you wouldn't want to use the second pattern is when you expect the dom to change frequently. Using a previous selection of items, while efficient, is potentially a problem if more buttons are added or removed. Granted, this isn't a problem if you're simply chaining up a few actions on an item, then discarding the selection anyway.
Besides all of that, who really wants to continuously type $(...). It's awkward.
I am doing some experimentation with GSAP library and i found one pen by Jonathan
http://codepen.io/jonathan/pen/qxsfc
which is pretty much i needed. i forked that pen and made my own and now i am trying to convert the same in vanilla js but the first step it self is not working.
i have converted the anonymous function to a named one and called on window.onload and its working. but now i have to replace all the $ calls of jquery selector to native selectors and its not working
the moment i change
var animContainer = $('.animContainer'),
to var animContainer = document.querySelector('.animContainer'),
my pen is
`http://codepen.io/osricmacon/pen/HAnrt`
any more suggestion on how to go about converting jquery to vanilla js
querySelector stops at the first element it finds, and returns a reference to that one element (or null if it doesn't find it). A closer analogue to jQuery's $() is querySelectorAll, which looks for all matching elements and returns a NodeList (which will be empty if none were found).
Separately from that, the key thing about jQuery is that it's set-based, whereas the DOM API is not. That's probably going to be the biggest thing for you to deal with when converting the one to the other.
For example, in jQuery, this sets the HTML of all div elements to "hey":
$("div").html("hey");
The equivalent using the DOM API might look like this:
var list = document.querySelectorAll("div"); // Or .getElementsByTagName
var i;
for (i = 0; i < list.length; ++i) {
list[i].innerHTML = "hey";
}
A common approach to making that less verbose is to reuse Array's forEach function (which is ES5, but can be shimmed for older browsers), like this:
// You'd probably do this once and reuse it
var forEach = Array.prototype.forEach;
// Where you want to use it:
forEach.call(document.querySelectorAll("div"), function(div) {
div.innerHTML = "hey";
});
Or, of course, to have a toolbelt of utility functions that do that under the covers. Which is, of course, exactly what jQuery is.
Finally, in many cases jQuery reuses the same functions as both setters and getters. The html function, for instance, sets the HTML of the elements in the jQuery set when you give it an argument, but gets the HTML of the first element of the set if you don't:
$("div").html("hey"); // Sets the HTML of all divs
console.log($("div").html()); // Gets the HTML of the *first* div
Note the assymetry: Setting applies to all elements in the set, but getting applies only to the first element in the set (ignoring any others). This is true of all of the functions that do dual duty (html, css, val, attr, prop, ...).
I saw some code around the web that uses the following statement
if ($($(this)).hasClass("footer_default")) {
$('#abc')
.appendTo($(this))
.toolbar({position: "fixed"});
}
What is the use of $($(this)) and why is that necessary here?
Yes, $($(this)) is the same as $(this), the jQuery() or $() function is wonderfully idempotent. There is no reason for that particular construction (double wrapping of this), however, something I use as a shortcut for grabbing the first element only from a group, which involves similar double wrapping, is
$($('selector')[0])
Which amounts to, grab every element that matches selector, (which returns a jQuery object), then use [0] to grab the first one on the list (which returns a DOM object), then wrap it in $() again to turn it back into a jQuery object, which this time only contains a single element instead of a collection. It is roughly equivalent to
document.querySelectorAll('selector')[0];, which is pretty much
document.querySelector('selector');
You can wrap $ as many times as you want, it won't change anything.
If foo is a DOM element, $(foo) will return the corresponding jQuery object.
If foo is a jQuery object, $(foo) will return the same object.
That's why $($(this)) will return exactly the same as $(this).
There is no specific need for double-wrapping and $($(this)) is exactly the same as $(this).
That said, I once found this double-wrapping in one file in my project, committed by another developer. Tracking the changes through revision, turned out that it started as $($(this).find('selector').first()) - that is, the result of some selector was wrapped to create a new object. Then for whatever reasons, the selector was removed and only the double-wrapping of this remained. Needless to say, on the next commit it was changed to $(this).
As explained before me, $($(this)) and $(this) are absolutely identical. jQuery returns the same jQuery object if you try to wrap it more than once.
Additionally, for performance considerations it is a good practice to reuse jQuery objects - it is quite expensive to create jQuery objects, especially the ones with complex selectors. Example:
var $this = $(this);
if ($this.hasClass("footer_default")) {
$('#abc')
.appendTo($this)
.toolbar({position: "fixed"});
}
Just google for 'jQuery best practices' - it will take a 30 min for you to learn these basics and you will use jQuery way more effectively.
There is no meainig of doing that.
The following code return the same:
console.log($($(this)).hasClass("footer_default"))
console.log($(this).hasClass("footer_default"))
a boolean value depenging on if the selected element has or not the class footer_default:
.hasClass( className )Returns: Boolean
Demo: http://jsfiddle.net/IrvinDominin/aSzFn/
$(this) and $($(this)) both return jquery object.
There is no difference between these two.
jQuery currently uses window as its default element so any call like $('div') will look for div tags inside window.
Is there any way to change defaults on jQuery like:
$.defaultRoot = $('.anyOtherRootElement');
$('div').text("Hello");
this will select any div inside the elements containing .anyOtherRootElement class.
Thanks in advance
Upate
just an update refining the question a bit more here:
I would like to perform the actions above based on external queries coming from external script which won't know what defaultRoot is so they can still be calling what is supposed to be the current base, so in this instance, I'm afraid adding the a second parameter wouldn't be an option, unfortunately.
And at the same time creating a function which returns defaultRoot.find(el) would prevent me of using first-level methods such $.trim, $.each, etc… so unfortunately that would not be possible as well.
Ideally (for performance reasons) you'd want to use find()
$.defaultRoot.find("div");
Otherwise you can use the 2 argument form that sets a context
$("div", $.defaultRoot);
In general you don't want to do these types of things implicitly since someone else could easily end up thoroughly confused when having to work with your code later. If you want to do it consistently and make it shorter you should create your own function to do so like:
var $s = function(selector) {
return $.defaultRoot.find(selector);
}
and then you'd just be able to use
$s("div")
or you could also do a scoped higher order function with something like
var withScope = function(scope$) {
return function(selector) {
return scope$.find(selector);
}
}
var $s = withScope($.defaultRoot);
$s("div")
If for some reason you really want to screw around with the default state for client code (begging for chaos IMO), you should look at the functional practice: currying.
$('SELECTOR', 'CONTEXT')
You can use context. As in your case $('div', '.anyOtherRootElement')
For more details, visit http://api.jquery.com/jQuery/
Given that you can pass the context as a second argument, you can easily overwrite the $() operator in Javascript with a version which internally calls JQuery using jQuery.noConflict(); and always passes your new root as the second argument.
I don't think jQuery provide such method or variable. But you can pass second parameter in jQuery method to set context.
$.defaultRoot = $('.anyOtherRootElement');
$('div', $.defaultRoot ).text("Hello"); // all div inside $('.anyOtherRootElement')
$('div' ).text("Hello"); //all div inside body tag
We're considering switching our site from Prototype to jQuery. Being all-too-familiar with Prototype, I'm well aware of the things about Prototype that I find limiting or annoying.
My question for jQuery users is: After working with jQuery for a while, what do you find frustrating? Are there things about jQuery that make you think about switching (back) to Prototype?
I think the only that gets me is that when I do a selection query for a single element I have to remember that it returns an array of elements even though I know there is only one. Normally, this doesn't make any difference unless you want to interact with the element directly instead of through jQuery methods.
Probably the only real issue I've ever ran into is $(this) scope problems. For example, if you're doing a nested for loop over elements and sub elements using the built in JQuery .each() function, what does $(this) refer to? In that case it refers to the inner-most scope, as it should be, but its not always expected.
The simple solution is to just cache $(this) to a variable before drilling further into a chain:
$("li").each(function() {
// cache this
var list_item = $(this);
// get all child a tags
list_item.find("a").each(function() {
// scope of this now relates to a tags
$(this).hide("slow");
});
});
My two pain points have been the bracket hell, can get very confusing
$('.myDiv').append($('<ul />').append($('<li />').text('content')));
My other common issue has to do with the use of JSON in jQuery, I always miss the last comma,
$('.myDiv').tabs({ option1:true, options2:false(, woops)});
Finally, I've been using jQuery for about 6 months now and I don't think I'll ever go back to prototypes. I absolutely love jQuery, and a lot of the tricks they use have helped me learn a lot. one cool trick that I like is using string literals for method calls, I never really did that too much with prototypes.
$('.myDiv')[(add ? 'add' : 'remove') + 'Class']('redText');
(The only thing I can think of is that this is the element instead of a jQuery object in $("...").each(function)-calls, as $(element) is more often used then just the element. And that extremly minor thing is just about it.
Example of the above (simplified and I know that there are other much better ways to do this, I just couldn't think of a better example now):
// Make all divs that has foo=bar pink.
$("div").each(function(){
if($(this).attr("foo") == "bar"){
$(this).css("background", "pink");
}
});
each is a function that takes a function as parameter, that function is called once for each matching element. In the function passed, this refers to the actual browser DOM-element, but I find that you often will want to use some jQuery function on each element, thus having to use $(this). If this had been set to what $(this) is, you'd get shorter code, and you could still access the DOM element object using this.get(0). Now I see the reason for things being as they are, namely that writing $(this) instead of this, is hardly that cumbersome, and in case you can do what you want to do with the DOM element the way it is is faster than the way it could have been, and the other way wouldn't be faster in the case you want $(this).)
I don't think there are any real gotchas, or even any lingering annoyances. The other answers here seem to confirm this - issues are caused simply by the slightly different API and different JavaScript coding style that jQuery encourages.
I started using Prototype a couple of years ago and found it a revelation. So powerful, so elegant. After a few months I tried out jQuery and discovered what power and elegance really are. I don't remember any annoyances. Now I am back working on a project using Prototype and it feels like a step back (to be fair, we're using Prototype 1.5.1).
If you reversed the question - "What Prototype annoyances should I be aware of as a jQuery user?" - you would get a lot more answers.
Nope. Nada. Nyet.
.each:
jQuery (you need Index, even if you're not using it):
$.each(collection, function(index, item) {
item.hide();
});
Prototype (you're usually using the item, so you can omit the index):
collection.each(function(item) {
item.hide();
});
This is really only an annoyance if you're doing a lot of DOM manipulation. PrototypeJs automatically adds its API to DOM Elements, so this works in prototypejs (jQuery of course doesn't do this):
var el = document.createElement("div");
el.addClassName("hello"); // addClassName is a prototypejs method implemented on the native HTMLElement
Even without running the native element through the $() function.
PS: Should note that this doesn't work in IE.