1

I just want to share an experience with you all. So my problem was, that I came across the problem of binding javascript back-end objects to HTML front-end elements. Now, i have searched through google and read some stackoverflow articles about this problem, and many posts answer to this is to use jQuery.data(), however in my first attempts I did not succeed because there was something I did not know about jQuery's object creation method. My problem was that, I wanted to retrieve the stored data outside of the scope where i stored this, and jQuery always(i think) returns a new object reference when i write jQuery('selectorID'). So for example:

var ref1 = $('#myID');
var ref2 = $('#myID');

if(ref1 == ref2)
{
   alert(true);
}
else
{
   alert(false);
}

Will always alert false. However replacing the jQuery method with javascript's built-in getElementById() we will get the same reference! Hence the following code will always alert true!

var ref1 = document.getElementById("myID");
var ref2 = document.getElementById("myID");

if(ref1 == ref2)
{
   alert(true);
}
else
{
   alert(false);
}

The little morale of my story is that if you want to globally bind javascript objects to HTML elements and are thinking about using jQuery's data() method, store the data on the reference returned by javascript's built-in getElementById(). That way, whereever you retrieve the reference with getElementByID, you will always get the same reference and can get the data from it using jQuery's data() method.

My Questions:

  1. Is my logic of thinking ok?
  2. Is there a better way to globally bind javascript objects to HTML elements?
Fazi
  • 3,909
  • 4
  • 27
  • 23
  • 1
    Your logic is patently false. While multiple calls to `$()` return different selector objects, jQuery methods usually operate on the selected objects themselves. Calls to `.data()` will thus always operate on the same DOM element you'd get using `getElementById()`. (As you could've determined by actually trying this out instead of investigating reference equality.) – millimoose Mar 10 '13 at 13:22

4 Answers4

2

Whatever the reason behind the code you mention not working was, it was decidedly not the fact that jQuery gives you a new collection for every query. Given the HTML:

<div id="somediv"> foo bar </div>

the following Javascript works as expected:

var $ref1 = $('#somediv');
var $ref2 = $('#somediv');

console.log("$ref1:", $ref1);
console.log("$ref2:", $ref2);

// compare the collections / references
console.log("$ref1 == $ref2:", $ref1 == $ref2); // => false
console.log("$ref1 === $ref2", $ref1 === $ref2); // => false

// compare the referred DOM elements themselves
console.log("$ref1[0] == $ref2[0]:", $ref1[0] == $ref2[0]); // => true
console.log("$ref1[0] === $ref2[0]", $ref1[0] === $ref2[0]); // => true


$ref1.data('somedata', 'SOMEDATA');
console.log('$ref1->somedata:', $ref1.data('somedata')); // => SOMEDATA
console.log('$ref2->somedata:', $ref2.data('somedata')); // => SOMEDATA
millimoose
  • 39,073
  • 9
  • 82
  • 134
  • I never said that jQuery returns a new collection for the same query, what I said was that jQuery return a new REFERENCE to the same objects(from the perspective of content) returned! – Fazi Mar 11 '13 at 12:05
  • Also, what I wanted to do is to store some data on the references to those DOM elements – Fazi Mar 11 '13 at 12:08
  • @Fazi Your question says "binding javascript back-end objects to HTML front-end elements". `.data()` will bind arbitrary objects to the DOM elements. When I said that jQuery (i.e. the function `$()`) returns collections of DOM elements, it's because that's what it does. `ref1` and `ref1` in your code are "smart" arrays of DOM elements, not references. In jQuery, you can usually treat such an array that only has one item as a reference to said item, but it's still an array. – millimoose Mar 11 '13 at 12:46
  • @Fazi Now, if you want to bind objects to said array/reference, just use your own custom properties, although it'd be best to namespace them somehow to avoid clobbering jQuery methods. If you want to bind to the DOM elements, use `.data()`, which will in fact bind to the DOM elements themselves, not to the references, as my code sample shows. If you want to do something else entirely, maybe you should post a question asking how to do that - you've never actually provided any example of what you're trying to accomplish. – millimoose Mar 11 '13 at 12:48
  • From my understanding, and related to this post(http://stackoverflow.com/questions/3691125/objects-in-javascript), all variables in Javascript are stored in a heap. So basically a query with jQuery(even if it seemingly returns the same object) returns a reference to a totally new object. So for example, ref1 and ref2 in my code are references to different "smart" arrays. Although, you are right in the sense that this was, truly beside the point of my my post. – Fazi Mar 11 '13 at 15:32
  • @Fazi No. Two queries with jQuery will return a different collection / reference. However, this is done mostly because it would be much more complicated to do otherwise - you'd have to cache selected collections and maintain the caches as the DOM is updated, and generally be too much bother considering jQuery internally operates on the selected objects themselves anyway. The DOM element(s) that's inside the collection / that the reference points to will be the same every time. I'll update my answer and the CodePen to demonstrate this. – millimoose Mar 11 '13 at 16:49
  • @Fazi To put this another way, what jQuery does at its core when you do `$('#somediv')` is ultimately call `document.getElementById('somediv')`, put this object into a new "jQuery array", and return that array. – millimoose Mar 11 '13 at 16:56
0

The way I do it is something like this.

var ref1 = $('a');
var ref2 = $('div');

var equal = ref1.length === ref2.length;
if (equal) {
    $.each(ref1, function(i) {
        equal = equal && ref1[i] === ref2[i];

        if (!equal) {
            return false;
        }
    });
}

if (equal) {
    alert(true);
} else {
    alert(false);
}
Nate Higgins
  • 2,104
  • 16
  • 21
  • I don't believe "how to compare jQuery objects for identity" is the OP's question, just an observation he made. – millimoose Mar 10 '13 at 13:24
0
ref1[0] === ref2[0] // Should return true

I think jQuery's instances are unique, so you can compare its matched items, which should be just one element when you reference an ID.

You could do something like this:

var ref1 = $('#myID')[0];
var ref2 = $('#myID')[0];
headacheCoder
  • 4,503
  • 8
  • 30
  • 33
  • As I commented elsewhere, "how to compare jQuery objects for identity" doesn't seem to be the thrust of the OP's question – millimoose Mar 10 '13 at 13:25
-1

I dive into jQuery's source code, and find the constructor of jQuery. As follow:

// Define a local copy of jQuery
jQuery = function( selector, context ) {
    // The jQuery object is actually just the init constructor 'enhanced'
    return new jQuery.fn.init( selector, context, rootjQuery );
}

Whenever you use ref2 = $('#myID') to retrive a corresponding jQuery element, jQuery will create a new object to you. So the == will return false to you coz' the two element is completely different to js object engine.

Seems getElementById method is more fit your need. But I don't know how js engine perform its getElementById method.

alsotang
  • 1,520
  • 1
  • 13
  • 15