JavaScript: automatically updating the length property - javascript

This is not actually a jQuery question, but jQuery does something I would like to be able to do with other objects.
I notice that jQuery returns the number of elements using the .length property. However, the jQuery object is not actually an array, so the number of elements is not naturally available that way.
I presume that the jQuery object uses numbered keys for the actual elements, since [n] returns one of them.
How is it possible to have a .length property of a non-array automatically updated when elements are added or removed? Or is that manually maintained when jQuery adds or removes elements?
Thanks

As you've observed, a jQuery object is not actually an array. Thus, the .length property is just maintained manually by any method that might actually change the internal contents of the array-like list of DOM objects.
This works fairly easily with a jQuery object because very few methods actually change the list of DOM objects in an existing jQuery object. Most jQuery methods such as .filter() that operate on the list of DOM element in a jQuery object actually return a new jQuery object and the original jQuery object is not modified.
Even a jQuery method like .add() or .slice() do not modify the existing jQuery object, but instead return a new jQuery object with the appropriate modification in it.
If you trace through the jQuery source and look at how a lot of jQuery objects are created, pretty much all the methods that operate on a given jQuery object go through .pushStack() which calls jQuery.merge() which manually sets the .length property on the new jQuery object.
If you look at the code for the main jQuery constructor $(someSelector), it does some sort of document query, builds the internal array-like list of DOM nodes, then manually sets the .length property.

It’s manually maintained. Compare:
var l = [];
console.log(l.length); // 0
l[0] = 0;
console.log(l.length); // 1
var l = $([]);
console.log(l.length); // 0
l[0] = 0;
console.log(l.length); // 0

Related

difference between javascript array and jquery set

I'm relatively new to javascript and very new to jquery.
I have noticed that the jquery set returned by jQuery() selector shares a lot of similarities with javascript array e.g. elements in the jquery set can be accessed by the square bracket [] syntax
So I was wondering, is there any foundamental difference between jquery set and javascript array? Or they can be thought of as two ways of representing the same thing?
From their own docs (found here):
The jQuery object itself behaves much like an array; it has a length
property and the elements in the object can be accessed by their
numeric indices [0] to [length-1]. Note that a jQuery object is not
actually a Javascript Array object, so it does not have all the
methods of a true Array object such as join().
So a jquery object is sort of array like, but it's not an array. Basically, an array will have methods the jquery object lacks, and the jquery object has methods that arrays lack. I would generally try not to treat the jquery objects as arrays, and instead try to use a jquery method whenever tempted to use an array method (ie, use .each instead of the array method .forEach).
EDIT:
After reading more about the jquery objects, they do share a lot of methods with arrays, such as .find. Moreover, it also provides a .toArray method which can be used to convert the jquery object into an actual javascript array.
As the person who was responsible for this jQuery feature, I thought I would share some historical notes.
If you study the jQuery API, you may notice something odd: the object returned by $()/jQuery() is not only an "array-like" object with a .length property and [i] access to its elements, but it also has a couple of fairly redundant methods: .get(i) and .size().
.get(i) is very similar to an array's [i]: it returns one of the elements of the jQuery array/object. And .size() is the same as .length.
In fact, if you look at the implementation of .size() you will see that it simply returns the .length property:
// The number of elements contained in the matched element set
size: function() {
return this.length;
},
There is a little more to .get(). If you don't pass an argument, it is the same as .toArray(), and if you do pass an argument it allows both positive and negative indexes. Negative indexes count backwards from the end of the array similar to Python or Ruby.
But for the simple case of a non-negative index, .get(i) boils down to:
// Get the Nth element in the matched element set
get: function( num ) {
return this[ num ];
},
Why all this redundancy? .size() and .get(i) just do the same thing as the usual .length or [i], so why have both?
In the very first jQuery release in January 2006 (long before 1.0), the object returned by $() was not an "array-like" object. It was just a JavaScript object with .get(i) and .size() methods. The actual list of DOM elements was a separate "private" property of the jQuery object, and you were supposed to use those methods to access its elements and length.
As I worked with that initial jQuery release, it seemed a bit clumsy to have to call .get(i) and .size() to access the elements of the returned jQuery object. This object seemed to be a lot like an array, but you couldn't access its elements the same way as a normal array. So I thought, why not make it act more like a real array with [i] and .length?
It was a fairly simple change to do that, so we ran with it, but we kept the old .get(i) and size() methods for compatibility with code that already used those.
Now a confession: I don't remember the reason for making the return object an array-like object instead of directly inheriting from Array. (It was 11 years ago after all!)
We would have preferred making this object an actual array, but there was a good reason why that would work. Perhaps I will remember after sleeping on it, but in the meantime, this is how we got to the place where the jQuery return object is "array-like" but not a true array.
A jQuery object is a wrapper around an array of DOM elements. So a "jQuery array" is a jQuery object.

Why can't I use reduce in an array that resulted from a jquery selector? [duplicate]

I have read the JQuery documentation, and while much attention is devoted to what you should pass the function, I don't see any information on what it actually returns.
In particular, does it always return an array, even if only one element is found? Does it return null when nothing is found? Where is this documented?
I understand that jquery methods can be applied to the return value, but what if I want to just use the return value directly?
From Rick Strahl's description:
The jQuery Object: The Wrapped Set:
Selectors return a jQuery object known
as the "wrapped set," which is an
array-like structure that contains all
the selected DOM elements. You can
iterate over the wrapped set like an
array or access individual elements
via the indexer ($(sel)[0] for
example). More importantly, you can
also apply jQuery functions against
all the selected elements.
About returning nothing:
Does it always return an array? Does it return null?
You always get the same thing back, whether or not it has any contents is the question. Typically you can check this by using .val() (e.g. $('.myElem').val())
It doesn't return an array, it returns a jQuery object. The jQuery object is what contains all the special jQuery methods.
It never returns null, or another type. If one element is found, the jQuery object will have only one child. If no elements are found, the jQuery object will be empty.
As another answerer mentioned, it always returns the jQuery object.
This object always contains an array of elements (even if it is an empty array, or an array with just one object).
If you'd like to use the returned object "directly", as in, as a plain element, you can do one of the following:
$('selector')[0] // element
$('selector').get(0) // element
$('selector').length // number of elements in the array
The jQuery function (i.e. "$") always returns a jQuery object in every instance.
From the jQuery documentation:
The jQuery object itself behaves much like an array; it has a length property and the elements in the object can be accessed by their numeric indices [0] to [length-1]. Note that a jQuery object is not actually a Javascript Array object, so it does not have all the methods of a true Array object such as join().
The fact that $() always returns the jQuery function lets you chain jQuery function calls judiciously.
Jquery selector mechnism
$("..") , the jquery selector, is used to select matched elements.
Return value
It always return an array-like jquery object, which has a length property,
Call method on returned jquery object
Methods of jquery could be called on the object, and apply to those selected elements,
Access original element by index
The selected elements, are store as property of the object, their property name are index numbers start from 0,
thus could be accessed by index, start from 0,
after get the original element, you can treat it as if get by document.getElementXxx().
Wrap an original element to a jquery object
After get the original element, you can wrap it to be a jquery object, by calling $(originalEle),
then you can call jquery methods on the wrapped object.
According to firebug, it returns an array of objects that match to your selector. But this array is a jQuery object, that more methods than a simple Array.
Their documentation lists a few of the core calls you can use with "$" and what they return

Does jQuery/JS return actual DOM nodes, or just references to them?

The reason I ask is because I'm thinking of storing a bunch of DOM nodes in this huge and multi-dimensional array I have.
Cost: takes up space in memory. The question is how much space, and that depends on whether I'm getting references or actual DOM nodes.
Benefits: 1) It'll make my code a lot simpler. 2) I could avoid traversing and instead just reference the DOM node from my array.
Thoughts?
From jQuery site:
… jQuery() — which can also be written as $() — searches through the
DOM for any elements that match the provided selector and creates a
new jQuery object that references these elements
jQuery Documentation
jQuery returns the actual DOM Node. It's why you will find yourself writing $(this) most of the time. This is because you want to wrap your node in jQuery to be able to use some jQuery methods. However, it's recommended (almost in the guidelines) to cache your DOM nodes through references. For example,
var div = $('div');
div.dosomeMethod();
div.append();
This ensures that you are not traversing the entire DOM tree (the expensive DOM part) whenever you're trying to access some element. Whenever you do updates, ensure you're doing them as a batch.
in this example I show how to clone existing DOM element to object in memory, also create object in memory without pushing it to body, created collection objects, appended elements from collection to body and keep referenced objects, removed from body.
and so many operations...
var $newElement1 = $(selector).clone(); // create new element from existing and store in memory
var $newElement2 = $('<div>blabla</div>'); // create new element from html code and store in memory
var elements = [];
elements.push($newElement1);
elements.push($newElement2);
for(var i in elements) {
elements[i].appendTo($('body'));
}
$newElement1.remove(); // will remove it from body
** but I recommend You to use frameworks like: angularjs, reactjs, emberjs to save Your time
A reference to the object is returned. See here: https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById
This answer is wrong, please see the comments below.
Document.getElementById() and methods or wrappers that rely on it return a reference.
Likewise for Document.querySelector().
This all stems from the DOM4 spec, which states that (emphasis mine):
A collection is an object that represents a lists of DOM nodes. A collection can be either live or static. Unless otherwise stated, a collection must be live.
From a programming point of view this notion is easy to understand, you waste less memory and no time is spent copying things around, leading to faster execution.
However, for Document.querySelectorAll() we have an interesting case:
The NodeList object returned by the querySelectorAll() method must be static.
This means, as MDN puts it, that Document.querySelectorAll()
Returns a non-live NodeList of all the matching element nodes.
This means that the returned set is not a set of references to the original nodes, but instead to a set of nodes that represent the nodes at the time the query was executed. This means that a copy of all the matching nodes had to be made and you're no longer working with references to the live nodes.
In short:
Some JavaScript methods return references to the DOM Node.
Some JavaScript methods return array-like objects that contain references to the DOM Nodes. These objects aren't very big(?).
jQuery returns a jQuery object that contains references to the DOM Node(s). These jQuery objects could get quite big, depending on how many chained calls are made.
The actual DOM nodes are never actually returned "by value".
The size of the references themselves are small. Typically the size of a pointer.
JavaScript:
getElementById and querySelector(?) return references to the DOM Node.
getElementsByClassName and getElementsByTagName return live HTMLCollections.
getElementsByName returns a live NodeList.
getElementsByNameNS returns a live NodeList or a live HTMLCollection, depending on the browser.
querySelectorAll returns a non-live NodeList.
HTMLCollection and NodeList contain references to DOM nodes. They don't seem to be very big objects.
Live vs. Non-Live
From MDN:
In some cases, the NodeList is a live collection, which means that
changes in the DOM are reflected in the collection. For example,
Node.childNodes is live:
var parent = document.getElementById('parent');
var child_nodes = parent.childNodes;
console.log(child_nodes.length); // let's assume "2"
parent.appendChild(document.createElement('div'));
console.log(child_nodes.length); // should output "3"
In other cases,
the NodeList is a static collection, meaning any subsequent change in
the DOM does not affect the content of the collection.
document.querySelectorAll returns a static NodeList.
jQuery
From learn.jquery.com
A jQuery object is an array-like wrapper around one or more DOM elements. To get a reference to the actual DOM elements (instead of the jQuery object), you have two options. The first (and fastest) method is to use array notation:
$( "#foo" )[ 0 ]; // Equivalent to document.getElementById( "foo" )
The second method is to use the .get() function:
$( "#foo" ).get( 0 ); // Identical to above, only slower.
You can also call .get() without any arguments to retrieve a true array of DOM elements.

What is the actual type of the object jQuery is returning [duplicate]

This question already has answers here:
Why is it possible to query jQuery('div') like an array?
(5 answers)
Closed 9 years ago.
Just like $ itself is not simply a user defined object (it is, at its base, a function and that is why you can use the () operator on it and it inherits all the functions from Function.prototype) what is the actual Javascript type of the so-called jQuery object?
It has to be one of the standard array-like objects because you can use the [] operator on it, something you can't even do on strings in IE8 (and no, you can't, not on the Object String. You can on string literals before they're boxed).
So again, its not a user defined object (NB there's no such thing as a jQuery object, its written in raw javascript somewhere along the line). I have a feeling its a NodeList (or equivalent in browsers that don't have NodeList).
A reason you might have noticed this is you've added methods to the Array prototype, and you discover the function doesn't exist on a set of nodes found by jQuery!
So is anyone intimate with jQuery enough to share this lower level info with me? Or is there a short, exhaustive list of array-like objects in Javascript that I can test the jQuery object against till I find out which one it is myself?
The reason I ask this, instead of assume that jQuery is just adding elements to the object, using indexes as property names (I.e. obj[0] = x;) is because of how the Chrome dev tools and Firebug display them.
This shows dev tools displaying Array, jQuery and Array-like objects, and that there is at least some magic behind what jQuery is doing.
EDIT
It's not a NodeList. If it helps; inspecting it in Chrome shows that it is of type jQuery.fn.jQuery.init[0] with a __proto__ describing itself as Object[0] (which has all the jquery methods). Anyone explaining what and how jQuery is doing would be greatly thanked. I'm going to look at jQuery's source now.
And as for the image, it isn't simply an overridden .toString().
$('').toString == Object.prototype.toString //true
$('').toString == Array.prototype.toString //false
What is a jQuery object?
The $() or jQuery() function returns a jQuery object. It is not an Array and not a NodeList, and not in any way derived from either of those. It is an Object created with the jQuery constructor (which is actually the jQuery.fn.init() function). This object is very much like any other Object created with new SomeConstructor(), or even a plain object literal.
When you call $() or jQuery() without a new operator, it automatically does a new for you:
jQuery = function( selector, context ) {
// The jQuery object is actually just the init
// constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
},
The jQuery object is somewhat "array-like" in that it has properties with numeric indexes and a .length property, but these are just properties set directly in the object in the jQuery code. It also has a number of properties and methods that come from its prototype, which is jQuery.fn or jQuery.prototype (jQuery.fn is merely a reference to jQuery.prototype; they are the same object.)
You can see an example of this in the jQuery code that wraps a DOM element when you use $(element):
// HANDLE: $(DOMElement)
} else if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
} ...
In this bit of code, selector is actually a DOM element, and the code stores that element in this[0] and sets this.length to 1. This is why you can use [0] and .length, simply because the object has these properties that were explicitly set.
Why does a jQuery object display like an Array?
There is some magic involved here, but the magic is in Firebug and the Chrome Developer Tools. They both look for two specific properties to decide to display an object as if it were an array:
A length property which is either a number or a string containing a number.
A splice property which is a function.
If the object has both those properties, it is displayed as an array.
You can test this by pasting the following line into either the Chrome DevTools or Firebug:
({ splice:function(){}, length:0 })
Chrome displays:
[]
Firebug displays:
Object[ ]
Remove either property and it will display as an object.
It doesn't matter if these properties are in the object itself or its prototype. You can paste this code into either console and it will display the same array-like notation as the code above:
function A(){}; A.prototype = { splice:function(){}, length:0 }; new A;
You can add an element to your "array":
({ splice:function(){}, length:1, 0:'test' })
Now Chrome displays:
["test"]
and Firebug displays:
Object[ "test" ]
Note that the Firebug display is not exactly the same as what it displays for an actual Array. Firebug puts that Object prefix in front of the array-like display to let you know that it's not an actual Array.
It does that on jQuery objects too. If you enter:
$(document.body)
Firebug displays:
Object[ body ]
You can click the word Object to get the full object-style display of the jQuery object instead of the array-like display.
Chrome doesn't make this distinction; it displays an Array or an array-like Object the same way.
So there's the magic. It's really nothing special in jQuery, except that the object it returns does have the length and splice properties. The splice() method is on the prototype and the length property may come from the prototype (for an empty "array") or more often from the jQuery object itself.
Those two properties trigger the real magic: a hack in the DevTools and Firebug to try to provide a more useful display for objects like these.
Bragging rights :-)
A bit of historical trivia: I was actually responsible for this part of jQuery's architecture. The very first version of jQuery in early 2006 didn't work like this. The jQuery object didn't have a .length and [0], [1], etc. properties. Instead it had a "private" array of its own, and you had to use .get(n) to fetch values from that array.
I thought it would be more convenient to have direct array-like access to the elements and came up with the idea of setting the .length, [0], [1], etc. properties so it would work like a read-only array.
my understanding is a sub class of Array, which inherited from Array Class and has its own method
changes above:
it's not sub class of Array. But it made from Array, but after Array object created, jQuery alter the object prototype with jQuery its own prototype,then finally it become jQuery object which is Array-like object.

What does $([]) mean in jQuery?

var username = $("#username"),
password = $("#password"),
allFields = $([]).add(username).add(password);
What is allFields? What is $([])?
Being a newbie to Javascript/jQuery, I've never seen this $([]) notation before and I'm interested in its associated methods.
Given that its "$([])", it's tricky to search for. And a Google search of arrays in Javascript (guessing that thing is an array of some sort) yields the typical arrays I'm familiar seeing.
So what is $([])? Can anyone point me to some documentation? I'm interested in learning how to use this strange thing.
The jQuery function accepts an array of DOM nodes.
$([document.body]) for example which will return a jQuery object by wrapping all the DOM elements passed in that array. However, since in your example there is no DOM object to begin with and it's just an empty array, there is not need to even pass an empty array.
Calling the jQuery function without any arguments returns an empty set. Taken from jQuery docs,
Returning an Empty Set
As of jQuery 1.4, calling the jQuery() method with no arguments returns an empty jQuery set. In previous versions of jQuery, this would return a set containing the document node.
So, your example would work the same if you had instead called
$().add(username).add(password);
As other answers have mentioned and the docs say, passing an empty array was required before v 1.4.
[] it's an empty array. Wrapping it with $() overcharges it with jQuery's functions.
In javascript you can create an array this way:
var foo = [];
It is an empty array being passed in the creation of a jQuery object. Presumably to initialize something.
Shouldn't be necessary, at least not in the latest versions of jQuery.
Here's an example without the Array: http://jsfiddle.net/MAzLN/
Works fine, as the alert() shows one element in the object.
jQuery initializes the length property to 0 when the object is created, so I'm not sure what the purpose is, unless it was required in the past.
I believe it creates an empty jQuery collection object.

Categories

Resources