14

If I try something such as this:

$(".foo") === $(".foo") // = false

... I get false. If I instead try this query,

$(".foo").get(0) === $(".foo").get(0) // = true

... I get true.

That's because:

{a:myObject} !== {a:myObject};
[myObject]   !== [myObject];
myObject     === myObject;

I'm wondering if there is any succinct way to test for this equality, preferably built into jQuery. The 2nd method I wrote only works correctly if there is at most one element which matches .foo. The solution should work for any amount of elements.

Obviously I don't want to just check ".foo" === ".foo" since the actual selections I'm using are more complicated. I just simplified them for this example. (E.g. I may want to check that $(this) is selecting the same thing as $(".foo").)

Senseful
  • 86,719
  • 67
  • 308
  • 465
  • You should check out benekastah's answer, here's a demo that reflects his answer: http://jsfiddle.net/kAv4X/ – MacMac Feb 22 '12 at 18:52
  • @lolwut: that doesn't work since `is()` only checks that *at least one* of the elements matches the other selector (i.e. it's a subset). Take a look at: http://jsfiddle.net/dYAH3/ (it should say false in the first alert, but it says true). – Senseful Feb 22 '12 at 19:01
  • This [answer](http://stackoverflow.com/a/3856290/989121) appears to be the most accurate. – georg Feb 22 '12 at 19:30

5 Answers5

14

I think you are looking for $().is. Docs here.

var foo, bar;

foo = $('foo');
bar = $('.bar');

// This will check to see foo and bar contain the same elements
foo.is(bar); // true | false

Edit: @lolwut provided a jsfiddle for this answer. After reading the comments, I updated it and determined that this answer isn't reliable for the OP's case.

benekastah
  • 5,651
  • 1
  • 35
  • 50
  • 3
    @lolwut, nope, `is()` will return `true` if *at least one of the elements matches the given arguments*. – Frédéric Hamidi Feb 22 '12 at 18:54
  • Take a look at [T.J. Crowder's comment](http://stackoverflow.com/questions/9400500/how-do-i-check-if-2-jquery-selectors-are-pointing-to-the-same-elements/9401119#comment11878467_9400543) for an explanation as to why this doesn't work. – Senseful Feb 22 '12 at 18:55
  • Added jsfiddle and showed how my answer is wrong. Thanks @FrédéricHamidi for explaining the problem. – benekastah Feb 22 '12 at 19:41
  • This answer is correct when you're sure both objects contain **at most one element**. – Bob Stein Dec 12 '17 at 16:05
8

There is nothing in the core library to check sequence equality of jQuery objects, however the following should do the trick:

$.fn.sequenceEqual = function(compareTo) {
  if (!compareTo || !compareTo.length || this.length !== compareTo.length) {
    return false;
  }
  for (var i = 0, length = this.length; i < length; i++) {
    if (this[i] !== compareTo[i]) {
      return false;
    }
  }
  return true;
} 

Which would be useable like so:

$(".foo").sequenceEqual($(".bar"))

For completeness, a contents equal method could be written like so:

$.fn.contentsEqual = function(compareTo) {
  return compareTo && this.length === compareTo.length && this.length === this.filter(compareTo).length;
}

Which would be useable like so:

$(".foo").contentsEqual($(".bar"))
Web_Designer
  • 72,308
  • 93
  • 206
  • 262
Rich O'Kelly
  • 41,274
  • 9
  • 83
  • 114
4

If you want to check whether both sets contain exactly the same elements (possibly in a different order), then Array#every in combination with $.fn.index could do the job:

var $this  = $("p"),
    $other = $("p");


// same length and $other contains each element of $this

var equal = $this.length === $other.length
              && Array.prototype.every.call($this, function(elem) {
                   return $other.index(elem) > -1;
                 });
pimvdb
  • 151,816
  • 78
  • 307
  • 352
3

As an alternative to pimvdb's answer (which is very nice, I'm only providing this for completeness), you can leverage the fact that add() will not add elements that are already present in the jQuery object. Therefore, you can write:

$.fn.containsSameElements = function(other) {
    var len = this.length;
    return other.length == len && this.add(other).length == len;
};
Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
-1

Ok, using only jquery builtins, this seems to be the right one

$(oneSelector).filter($(anotherSelector)).length == 1

if ($(oneSelector).is($(anotherSelector)))... they are equal

georg
  • 211,518
  • 52
  • 313
  • 390
  • 6
    No. From [the docs](http://api.jquery.com/is/): *"Check the current matched set of elements against a selector, element, or jQuery object and return true if **at least one** of these elements matches the given arguments."* (my emphasis). – T.J. Crowder Feb 22 '12 at 18:15
  • 1
    Your updated answer with `filter` still isn't right, although it's a big step forward. You'd need to check `length` against the length of the original set of matched elements, not `1`. – T.J. Crowder Feb 22 '12 at 19:17
  • @T.J.Crowder: as long as they compare one single element (see the question), that's fine. Anyways, filter() is the correct way, this is how jQuery implements is() internally. – georg Feb 22 '12 at 19:24
  • 1
    `@thg435`: Yes, look at the question: *"The 2nd method I wrote only works correctly if there is at most one element which matches `.foo`."* Clearly the OP wants a solution that **isn't** just for one element. – T.J. Crowder Feb 22 '12 at 21:45