There's many JQuery functions that seem like they just return a reference to the same object(s), only to facilitate call chaining. But working on something where specific instances are significant, I noticed if I test the object equality the object returned isn't the same object. However, they reflect the same information.
What is "different" about the object that was returned from .css()? Is there a design reason for why they wouldn't just modify the instance and return the same instance?
In console I can do this and both instances reflect the updated color made to the second instance, but testing == if the objects are the same object returns false.
var blah = $('#div1');
var blah2 = $('#div1').css('color','red');
blah.css('color'); -- 'rgb(255, 0, 0)'
blah2.css('color'); -- 'rgb(255, 0, 0)'
blah === blah2
false
blah == blah2
false
I want to clarify I understand the difference between value comparisons and object comparisons. I understand that the test indicates they are two seperate objects. That doesn't confuse me, it simply surprises me. They could easily maintain the same object, modify the elements via their handle, and return that same object without creating a new one.
Typically you would see one of two patterns with object call chains. Either the same object reference is returned from each call, maintaining the same reference and simply modifying properties/children of that object. Or each call creates a new object, modifies and returns that new object without modifying the original.
The second approach is advantageous if you want to follow an immutable pattern such that each call generates a new object without modifying the prior instance.
In this case both objects refer to the same HTML element and reflect the same information, so it surprises me that JQuery is creating and returning a new object. I assume it's an explicit design choice, it just isn't apparent to me.
CodePudding user response:
The equality difference has to do with how objects are stored and referred to. Each time you make a new object, a location in memory is allocated for it. So when you go to access that object, your code will check that memory location and retrieve the object there. The issue is that your two objects are held in different locations in memory. So when you are checking if they are equal, the code sees that the two locations in memory are different. Thus because the locations are different, it returns false. Even though the contents are exactly the same, it is actually comparing the locations in memory.
Hope this helps, and let me know if I can clarify anything.
CodePudding user response:
blah will never equal blah2, they're two separate jQuery objects (albeit with the same ID).
You likely want to compare the result of css('color') instead, which correctly returns a string representation of the value:
var blah = $('#div1');
var blah2 = $('#div1').css('color','red');
console.log(blah.css('color') == blah2.css('color'));
console.log(blah.css('color') === blah2.css('color'));
#div1 {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="div1"></div>
CodePudding user response:
Each time you query an element using $('myelement'), jquery returns an object that contains a lot of data about the element. However, when using the equality operator == or === in two objects, js makes a comparison with the reference of the object, not the value. It means that although two objects in js have the same value, the comparison between them may be false if they don't have the same reference.
Let's look at some examples:
const a = {
foo: 1
};
const b = {
foo: 1
}
const c = b;
// returns false, same value but different reference
console.log(a == b);
// returns true, same value and same reference
console.log(b == c);
// returns false, same value but different reference
console.log(a == { foo: 1 });
This means that although 2 objects may have the same values, js would evaluate them as false with both the == and === operators if they don't have the same reference.
You can look at it in this jquery example:
const foo1 = $('#foo');
const foo2 = $('#foo');
console.log(foo1 == foo2);
console.log(foo1 === foo2);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<div id="foo">Hello world</div>
So how can we solve it?
Fortunately, Jquery has his own reference to the real HTML element, using the [0] index:
const foo = $("#foo");
console.log(foo[0])
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<div id="foo">Hello world</div>
So you can just make a comparison between HTML elements, which have a different behaviour when using the equality operator:
const foo1 = $('#foo');
const foo2 = $('#foo');
console.log(foo1[0] == foo2[0]);
console.log(foo1[0] === foo2[0]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<div id="foo">Hello world</div>
CodePudding user response:
As Teemu pointed out, I made an error in using the $ selector twice, which I certainly expect to generate a new JQuery type as it generates a new HTMLElement collection. So my test was invalid as css didn't generate a new object, $ did. I don't know how I missed that.
Once I adjusted to account for that, .css( does indeed return the same object as I would expect. So nothing surprising there, my test was simply invalid.
var blahA = $('#div1');
var blahB = blahA.css('color','red');
blahA == blahB
true
