I understand how the pushstack function works and I also understand how to use it for my plugins (I guess that's what its most used for , just for internal use and for end() to function properly and other similar methods) .
now below is the jquery source of pushstack , have a look :
pushStack: function( elems ) {
// Build a new jQuery matched element set
var ret = jQuery.merge( this.constructor(), elems );
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
ret.context = this.context;
// Return the newly-formed element set
return ret;
},
theres a lot going on in that function really and I kind of get most part of it , but I have a small problem , understanding the below lines of code :-
ret.prevObject = this;
ret.context = this.context;
what is prevObject and context ? can somebody give me a clue , it definitely does't seem to be a javascript thing ?
Basically prevObject is used to allow flexibility for the jquery selectors chaining syntax.
Most of jQuery's DOM traversal methods operate on a jQuery object instance and produce a new one, matching a different set of DOM elements. When this happens, it is as if the new set of elements is pushed onto a stack that is maintained inside the object. Each successive filtering method pushes a new element set onto the stack
Everytime you make a new filter a new jquery instance is constructed matching your selector and the previous one is stored in it to allow the .end() and the addBack() functions to work (most of the DOM transversal functions use pushStack internally). If this property were not used every selector will forget about the previous one and it will not behave like a stack. Think parent instead of prevObject and it will make it easier to understand.
The context property is deprecated in jQuery 1.10 and only used for supporting live() method but it must be added because the returning object is constructed merging an empty jQuery constructor as first parameter and a set of elements as the second.
var ret = jQuery.merge( this.constructor(), elems );
Because .merge returns the first array modified it's context property might not have the correct value so is overwritten with the correct one this.context
Check this jsfiddle and open the console. You will see that the first value of prevObject is the document as we are making a new selector and then is the ul element since we filter using find. Moreover you can go to the last filter and lookup the whole chain of selectors up to the document again.
I recommend you to use the JQuery API instead of this property as reference in production but this will allow you for example to know the result of all the selectors that have been applied to obtain a given set of DOM elements.
Say I have a map on an array of elements. The callback function takes the index and the value at that position in the array.
If I wrap the array element that the callback receives in $(), it behaves as I expect. If I use it without wrapping it in $(), it gives an error.
var nonHiddenElements = $( "form :input" ).not(':hidden');
nonHiddenElements.map(function(index, element){
input_id = $(element).attr('id'); // this works
input_id = element.attr('id') ; // this gives an error
})
Can someone explain how this works.
Is this a jQuery quirk, or a JavScript thing?
What type of objects does my nonHiddenElements array contain exactly?
What is element that gets passed to the callback?
And mainly what is the $() doing?
You need to understand how jQuery actually works. I will try to explain it briefly.
$ is nothing but a normal javascript function. jQuery === $, is just a function with a fancy name. This function does a lot of different things, depending on what you pass in it. For example if you pass a string it will be treated as CSS selector and jQuery internals will try to find corresponding DOM elements. Or if you pass a string starting with < and ending with > jQuery will create a new DOM element by provided HTML string.
Now if you pass a DOM element or NodeCollection of DOM elements, it/they will be wrapped into jQuery instances so that they can have a jQuery prototype methods. There are many prototype methods jQuery offers. For example text, css, append, attr - those are all methods of jQuery prototype. They are defined basically like this (simplified):
jQuery.prototype.text = function() { ... }
Normal DOM elements don't have those convenient methods jQuery provides. And inside of methods like map or each if you check this value or element parameter like you do, you will see that they are actually not jQuery instances:
element instanceof jQuery // => false
and of course you can't use instance methods with not an instance.
So in order to use jQuery prototype methods you need have a jQuery instance, which you can obtain if you call jQuery function with DOM element passed in it:
$(element) instanceof jQuery // true
Javascript is a programming language.
jQuery is a JavaScript Library.
With jQuery:
$("some element")
In native JavaScript you would have to do something like this.
getElementById('elementByID')
Explained in detail here: https://developer.mozilla.org/en-US/docs/Web/API/document.getElementById
MDN is a great resource for beginners. https://developer.mozilla.org/en-US/docs/Web/JavaScript
It's possible to do the following:
$(selector, context)
But how does $.fn.pluginX find out what what the given context was? For example:
$(selector, context).pluginX()
I've a case where a third party plugin assumes the window / document is the current one.
Edit:
I made the assumption that a document is meant by "context", but it's not always a document I guess. In my case, I'm doing cross-document stuff like $(sel, iframe.contentDocument).pluginX() and I want to make sure that if the plugin does $('body').append, then it should do $('body', theSameDocumentContext).append. Hope that helps.
jQuery element has a .context attribute. You can use it inside your plugin :
$.fn.pluginX = function(){
console.log(this.context);
}
But this is not reliable, there is too much variant. The value of context will always be document except if you pass an HTMLElement (like that):
$('p', document.getElementsByTagName('div')[0]);
But you can pass different context :
//All working :
$('p', document.getElementsByTagName('div'));
$('p', document.querySelector('div'));
$('p', document.querySelectorAll('div'));
$('p', document.getElementByID('id'));
$('p', 'div');
$('p', $('div'));
$('p', $('div').add('p'));
///... ran out of ideas
Now, it is important to know that passing a context is exactly the same has doing .find() :
$('p', 'div') === $('div').find('p');
Also, jQuery always store the previous jQuery object when chaining. If it is the initial call (no traversal method used), the previous object will be the document.
Knowing that information, if you want to get the "real" context, you can get that last element. jQuery have the property .prevObject. Use it :
$.fn.pluginX = function(){
console.log(this.prevObject);
}
$(selector, context) is same as $('context selector') and you can get it through this.selector, however this could be tricky for chained selectors.
for example:
$('.articles', '.section').pluginX()
//within the pluginX plugin function definition you can call this.selector
$.fn.pluginX = function(){
...
//this.selector = '.section .articles';
//this.selector.split(' ')[0] = '.section' //scope
...
}
But the above calculation will fail, if we have
$('.articles .writer', '.section').pluginX();
or
$('.writer', '.section .articles').pluginX();
If you have some presumption about either selector or context then it may help you to draft a logic. Let me know that helps you, or you could elaborate your specific requirement and we can try find a solution.
If an element doesn't exist, how do I get a string of the selector that was searched?
For example:
$( 'parent child.class' ).plugin( )
In my plugin, I want to get the string "parent child.class", but $( 'parent child.class' ) doesn't exist.
I'm going to start digging through the jQuery source code, but I figured I'd ask in case someone with more intimate knowledge knows this.
You can't.
jQuery objects have a .selector property, which you could use within your plugin (though it seems to be intended for use interally with jQuery), but - and it's a big but - not all jQuery objects are created with a selector string. Consider this example use of .yourPlugin():
$('div.someClass').add(document.getElementById("test"))
.add("<div>Hello</div>")
.filter(function() {
return $(this).attr("data-test") == "blah";
})
.parents()
.yourPlugin();
It doesn't make sense to be thinking about what selector resulted in the jQuery object eventually passed to .yourPlugin(), regardless of whether it contains any elements.
(I suppose if you know your plugin will only ever be used by you and you'll only ever pass it jQuery objects created with a selector then you could use this.selector within your plugin...)
there is selector property:
$.fn.plugin = function() {
if (this.length == 0) {
return this.selector;
}
};
Is this:
var contents = document.getElementById('contents');
The same as this:
var contents = $('#contents');
Given that jQuery is loaded?
Not exactly!!
document.getElementById('contents'); //returns a HTML DOM Object
var contents = $('#contents'); //returns a jQuery Object
In jQuery, to get the same result as document.getElementById, you can access the jQuery Object and get the first element in the object (Remember JavaScript objects act similar to associative arrays).
var contents = $('#contents')[0]; //returns a HTML DOM Object
No.
Calling document.getElementById('id') will return a raw DOM object.
Calling $('#id') will return a jQuery object that wraps the DOM object and provides jQuery methods.
Thus, you can only call jQuery methods like css() or animate() on the $() call.
You can also write $(document.getElementById('id')), which will return a jQuery object and is equivalent to $('#id').
You can get the underlying DOM object from a jQuery object by writing $('#id')[0].
Close, but not the same. They're getting the same element, but the jQuery version is wrapped in a jQuery object.
The equivalent would be this
var contents = $('#contents').get(0);
or this
var contents = $('#contents')[0];
These will pull the element out of the jQuery object.
A note on the difference in speed. Attach the following snipet to an onclick call:
function myfunc()
{
var timer = new Date();
for(var i = 0; i < 10000; i++)
{
//document.getElementById('myID');
$('#myID')[0];
}
console.log('timer: ' + (new Date() - timer));
}
Alternate commenting one out and then comment the other out. In my tests,
document.getElementbyId averaged about 35ms (fluctuating from 25ms up to 52ms on about 15 runs)
On the other hand, the
jQuery averaged about 200ms (ranging from 181ms to 222ms on about 15 runs).
From this simple test you can see that the jQuery took about 6 times as long.
Of course, that is over 10000 iterations so in a simpler situation I would probably use the jQuery for ease of use and all of the other cool things like .animate and .fadeTo. But yes, technically getElementById is quite a bit faster.
No. The first returns a DOM element, or null, whereas the second always returns a jQuery object. The jQuery object will be empty if no element with the id of contents was matched.
The DOM element returned by document.getElementById('contents') allows you to do things such as change the .innerHTML (or .value) etc, however you'll need to use jQuery methods on the jQuery Object.
var contents = $('#contents').get(0);
Is more equivilent, however if no element with the id of contents is matched, document.getElementById('contents') will return null, but $('#contents').get(0) will return undefined.
One benefit on using the jQuery object is that you won't get any errors if no elements were returned, as an object is always returned. However you will get errors if you try to perform operations on the null returned by document.getElementById
No, actually the same result would be:
$('#contents')[0]
jQuery does not know how many results would be returned from the query. What you get back is a special jQuery object which is a collection of all the controls that matched the query.
Part of what makes jQuery so convenient is that MOST methods called on this object that look like they are meant for one control, are actually in a loop called on all the members int he collection
When you use the [0] syntax you take the first element from the inner collection. At this point you get a DOM object
In case someone else hits this... Here's another difference:
If the id contains characters that are not supported by the HTML standard (see SO question here) then jQuery may not find it even if getElementById does.
This happened to me with an id containing "/" characters (ex: id="a/b/c"), using Chrome:
var contents = document.getElementById('a/b/c');
was able to find my element but:
var contents = $('#a/b/c');
did not.
Btw, the simple fix was to move that id to the name field. JQuery had no trouble finding the element using:
var contents = $('.myclass[name='a/b/c']);
var contents = document.getElementById('contents');
var contents = $('#contents');
The code snippets are not the same. first one returns a Element object (source).
The second one, jQuery equivalent will return a jQuery object containing a collection of either zero or one DOM element. (jQuery documentation). Internally jQuery uses document.getElementById() for efficiency.
In both the cases if more than one element found only the first element will be returned.
When checking the github project for jQuery I found following line snippets which seems to be using document.getElementById codes (https://github.com/jquery/jquery/blob/master/src/core/init.js line 68 onwards)
// HANDLE: $(#id)
} else {
elem = document.getElementById( match[2] );
Just like most people have said, the main difference is the fact that it is wrapped in a jQuery object with the jQuery call vs the raw DOM object using straight JavaScript. The jQuery object will be able to do other jQuery functions with it of course but, if you just need to do simple DOM manipulation like basic styling or basic event handling, the straight JavaScript method is always a tad bit faster than jQuery since you don't have to load in an external library of code built on JavaScript. It saves an extra step.
One other difference: getElementById returns the first match, while $('#...') returns a collection of matches - yes, the same ID can be repeated in an HTML doc.
Further, getElementId is called from the document, while $('#...') can be called from a selector. So, in the code below, document.getElementById('content') will return the entire body but $('form #content')[0] will return inside of the form.
<body id="content">
<h1>Header!</h1>
<form>
<div id="content"> My Form </div>
</form>
</body>
It might seem odd to use duplicate IDs, but if you are using something like Wordpress, a template or plugin might use the same id as you use in the content. The selectivity of jQuery could help you out there.
All the answers are old today as of 2019 you can directly access id keyed filds in javascript simply try it
<p id="mytext"></p>
<script>mytext.innerText = 'Yes that works!'</script>
Online Demo!
- https://codepen.io/frank-dspeed/pen/mdywbre
jQuery is built over JavaScript. This means that it's just javascript anyway.
document.getElementById()
The document.getElementById() method returns the element that has the ID attribute with the specified value and Returns null if no elements with the specified ID exists.An ID should be unique within a page.
Jquery $()
Calling jQuery() or $() with an id selector as its argument will return a jQuery object containing a collection of either zero or one DOM element.Each id value must be used only once within a document. If more than one element has been assigned the same ID, queries that use that ID will only select the first matched element in the DOM.
All the answers above are correct. In case you want to see it in action, don't forget you have Console in a browser where you can see the actual result crystal clear :
I have an HTML :
<div id="contents"></div>
Go to console (cntrl+shift+c) and use these commands to see your result clearly
document.getElementById('contents')
>>> div#contents
$('#contents')
>>> [div#contents,
context: document,
selector: "#contents",
jquery: "1.10.1",
constructor: function,
init: function …]
As we can see, in the first case we got the tag itself (that is, strictly speaking, an HTMLDivElement object). In the latter we actually don’t have a plain object, but an array of objects. And as mentioned by other answers above, you can use the following command:
$('#contents')[0]
>>> div#contents