Why does $('#id') return true if id doesn't exist?

Viewed 14065

I always wondered why jQuery returns true if I'm trying to find elements by id selector that doesnt exist in the DOM structure.

Like this:

<div id="one">one</div>

<script>
    console.log( !!$('#one') ) // prints true
    console.log( !!$('#two') ) // is also true! (empty jQuery object)
    console.log( !!document.getElementById('two') ) // prints false
</script>

I know I can use !!$('#two').length since length === 0 if the object is empty, but it seems logical to me that a selector would return the element if found, otherwise null (like the native document.getElementById does).

F.ex, this logic can't be done in jQuery:

var div = $('#two') || $('<div id="two"></div>');

Wouldnt it be more logical if the ID selector returned null if not found?

anyone?

6 Answers

This behaviour was chosen because otherwise jQuery would regularly throw NullReference Exceptions

Almost all jQuery functions return a jQuery object as a wrapper around the Dom elements in question, so you can use dot notation.

$("#balloon").css({"color":"red"});

Now imagine $("#balloon") returned null. That means that $("#balloon").css({"color":"red"}); would throw an error, rather than silently doing nothing as you would expect.

Hence, you just gotta use .length or .size().

This is just how jQuery works.

$("#something")

Object 0=div#something length=1 jquery=1.2.6

$("#nothing")

Object length=0 jquery=1.2.6

You can come close to doing what you want by accessing the length the element, and combine with the ternary operator:

console.log(!!$('#notfound').length);  // false
console.log(!!$('#exists').length);    // true
var element= $('#notfound').length ? $('#notfound') : $('#exists');
console.log(element.attr('id'));  // outputs 'exists'

As to the heart of the question:

Wouldnt it be more logical if the ID selector returned null if not found?

No, not for the JQuery way of doing things - namely, to support chaining of JQuery statements:

    $('#notfound').hide("slow", function(){
      jQuery(this)
        .addClass("done")
        .find("span")
          .addClass("done")
        .end()
        .show("slow", function(){
          jQuery(this).removeClass("done");
        });
    });

Even though notfound doesn't exist this code will run without stopping script execution. If the initial selector returns null, you'll have to add in an if/then block to check for the null. If the addClass, find, end and show methods return null, you'll have to add an if/then block to check the return status of each. Chaining is an excellent way to handle program flow in a dynamically typed language like Javascript.

It returns true because to Javascript it is a defined object therefore not false, and jQuery will always give you a new object regardless of whether the element is found or not - however the array length will be zero, e.g.

$("span").length

If you have no <span>, this will be zero, but it could be 1 or more.

You can write your own plugin to avoid repeated if statements as a Jquery plugin, like I did for this one. It's fairly easy to do:

(function($)
{
        /* Checks if a jQuery object exists in the DOM, by checking the length of its child elements. */
        $.fn.elementExists = function()
        {
                ///     <summary>
                ///     Checks if a jQuery object exists in the DOM, by checking the length of its child elements.
                ///     </summary>
                ///     <returns type="Boolean" />
                return jQuery(this).length > 0;
        };
})(jQuery);

Usage:

if ($("#someid").elementExists())
{

}

You could check the .length property of the jQuery object. Like this:

if($("#two").length > 0) { // exists...

} else { // doesn't exist

}

In short, you could think of the jQuery selector return value as a group containing 0..n elements, but never being null.

What you're probably really interested in is $("#two")[0], which will give you the first actual element returned by the selector.

Related