|
| 1 | +--- |
| 2 | +level : beginner |
| 3 | +title : The jQuery Object |
| 4 | +attribution: Mike Pennisi |
| 5 | +github : jugglinmike |
| 6 | +--- |
| 7 | +Presumably, if you're reading this, you are curious about the thing that jQuery returns when you create new elements (or select existing ones). |
| 8 | +This curiosity is a great first step, because a first glance, the jQuery object may seem to be an array of DOM elements. |
| 9 | +It has a collection of DOM elements, some familiar array functions, and a `length` property, after all. |
| 10 | +Actually, the jQuery object is more complicated than that. |
| 11 | + |
| 12 | +### What is a DOM element, anyway? |
| 13 | + |
| 14 | +A DOM element is a "piece" of a web page. |
| 15 | +It can contain text and/or other DOM elements. |
| 16 | +It is described by a type (i.e. "div", "a", "p", etc.) and any number of attributes (i.e. "src", "href", "class", etc.). |
| 17 | +For a more thorough description, please refer to [the office specification from the W3C](http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-745549614). |
| 18 | + |
| 19 | +Elements have properties like any JavaScript object. |
| 20 | +Among these properties are attributes like `tagName` and methods like `appendChild`. |
| 21 | +These properties are the only way to interact with the web page via JavaScript. |
| 22 | + |
| 23 | +### So why not just put the elements in an array? |
| 24 | + |
| 25 | +It turns out that working directly with DOM elements can be quite awkward. |
| 26 | +The jQuery object defines [a ton](http://api.jquery.com/) of methods to smooth out the experience for developers. |
| 27 | +For example: |
| 28 | + |
| 29 | +*Compatability* |
| 30 | +The implementation of element methods varies across browser vendors and versions. |
| 31 | +Imagine that you wanted to set the inner HTML of a `tr` element stored in `target`. You might write: |
| 32 | + |
| 33 | +<javascript caption="Setting the inner HTML with the native DOM API"> |
| 34 | +var target = document.getElementById("target"); |
| 35 | +target.innerHTML = "<td>Hello <b>World</b>!</td>"; |
| 36 | +</javascript> |
| 37 | + |
| 38 | +This works in most cases, but it will fail in most versions of Internet Explorer. |
| 39 | +In that case, the [recommended approach](http://www.quirksmode.org/dom/w3c_html.html) is to use pure DOM methods instead. |
| 40 | +By wrapping the `target` element in a jQuery object, these edge cases are taken care of, and the expected result is acheived in all supported browsers: |
| 41 | + |
| 42 | +<javascript caption="Setting the inner HTML with jQuery"> |
| 43 | +var target = document.getElementById("target"); |
| 44 | +$( target ).html( "<td>Hello <b>World</b>!</td>"); |
| 45 | +</javascript> |
| 46 | + |
| 47 | +*Convenience* |
| 48 | +There are also a lot of common DOM manipulation use cases that are awkward to accomplish with pure DOM methods. |
| 49 | +For instance, if you want to insert the element stored in `newElement` after the element stored in `target`, you have to write: |
| 50 | + |
| 51 | +<javascript caption="Inserting a new element after another with the native DOM API"> |
| 52 | +var target = document.getElementById("target"); |
| 53 | +var newElement = document.createElement("div"); |
| 54 | +target.parentNode.insertBefore( target.nextSibling, newElement ) |
| 55 | +</javascript> |
| 56 | + |
| 57 | +By wrapping the `target` element in a jQuery object, you can accomplish the same task in a much simpler manner: |
| 58 | + |
| 59 | +<javascript caption="Inserting a new element after another with jQuery"> |
| 60 | +var target = document.getElementById("target"); |
| 61 | +var newElement = document.createElement("div"); |
| 62 | +$( target ).after( newElement ); |
| 63 | +</javascript> |
| 64 | + |
| 65 | +If you're in the business of getting things done (and I suspect that you are), then these details are simply "gotchas" that stand between you and your goals. |
| 66 | + |
| 67 | +### Sounds good. Now how do I get stuff in there? |
| 68 | + |
| 69 | +If you pass a CSS selector to the jQuery function, the result will be a jQuery object wrapping any element(s) that match this selector. |
| 70 | +For instance, by writing |
| 71 | + |
| 72 | +<javascript caption="Selecting all 'h1' tags"> |
| 73 | +var allHeaders = $("h1"); |
| 74 | +</javascript> |
| 75 | + |
| 76 | +`headers` is now a jQuery element containing *all* the `<h1>` tags already on the page. |
| 77 | +You can convince yourself by checking the `length` property of `headers`: |
| 78 | + |
| 79 | +<javascript caption="Viewing the number of 'h1' tags on the page"> |
| 80 | +var allHeaders = $("h1"); |
| 81 | +alert( allHeaders.length ); |
| 82 | +</javascript> |
| 83 | + |
| 84 | +If the page has more than one `<h1>` tag, this number will be greater than one. |
| 85 | +Likewise, if the page has no `<h1>` tags, the `length` property will be zero. |
| 86 | +Checking the `length` property is a common way to ensure that the selector described something on the page. |
| 87 | + |
| 88 | +To make sure we only have the first header element, we have to take one more step. |
| 89 | +There are a number of ways to accomplish that, the most straight-forward may be the `eq()` function. |
| 90 | + |
| 91 | +<javascript caption="Selecting only the first 'h1' element on the page (in a jQuery object)"> |
| 92 | +var headers = $("h1"); |
| 93 | +var firstHeader = headers.eq(0); |
| 94 | +</javascript> |
| 95 | + |
| 96 | +Now we can be assured that `firstHeader` is a jQuery object containing only the first `<h1>` element on the page. |
| 97 | +And because `firstHeader` is a jQuery object, you can use methods like `html()` or `after()`. |
| 98 | +jQuery also has a method named `get()` which provides a related function. |
| 99 | +Instead of returning a jQuery-wrapped DOM element, it returns the DOM element itself. |
| 100 | + |
| 101 | +<javascript caption="Selecting only the first 'h1' element on the page"> |
| 102 | +var firstHeaderElem = $("h1").get(0); |
| 103 | +</javascript> |
| 104 | + |
| 105 | +You can also treat the jQuery object like a true JavaScript array and use brackets to retrieve the DOM element you want, like so: |
| 106 | + |
| 107 | +<javascript caption="Selecting only the first 'h1' element on the page (alternate approach)"> |
| 108 | +var firstHeaderElem = $("h1")[0]; |
| 109 | +</javascript> |
| 110 | + |
| 111 | +In either case, `firstHeaderElem` contains the "native" DOM element. |
| 112 | +This means it has DOM properties like `innerHTML` and methods like `appendChild()`, but *not* jQuery methods like `html()` or `after()`. |
| 113 | +As discussed earlier, the element is more difficult to work with, but there are certain instances where you will need it. |
| 114 | +One such instance is making comparisons. |
| 115 | + |
| 116 | +### Not all jQuery objects are created `===` |
| 117 | + |
| 118 | +An important detail regarding this "wrapping" behavior is that each wrapped object is unique. |
| 119 | +This is true *even if the object was created with the same selector*. |
| 120 | + |
| 121 | +<javascript caption="Creating two jQuery objects for the same element"> |
| 122 | +var logo1 = $("#logo"); |
| 123 | +var logo2 = $("#logo"); |
| 124 | +</javascript> |
| 125 | + |
| 126 | +Although `logo1` and `logo2` are created in the same way (and wrap the same DOM element), they are not the same object. |
| 127 | +For example: |
| 128 | + |
| 129 | +<javascript caption="Comparing jQuery object"> |
| 130 | +alert( $("#logo") === $("#logo") ); // alerts 'false' |
| 131 | +</javascript> |
| 132 | + |
| 133 | +However, both objects contain the same DOM element. |
| 134 | +The `get` method is useful for testing if two jQuery objects have the same DOM element. |
| 135 | + |
| 136 | +<javascript caption="Comparing DOM elements"> |
| 137 | +var logo1 = $("$logo"); |
| 138 | +var logo1Elem = logo1.get(0); |
| 139 | + |
| 140 | +var logo2 = $("#logo"); |
| 141 | +var logo2Elem = logo2.get(0); |
| 142 | + |
| 143 | +alert( logo1Elem === logo2Elem ); // alerts 'true' |
| 144 | +</javascript> |
| 145 | + |
| 146 | +Many developers prefix a `$` to the name of variables that contain jQuery objects in order to help differentiate. |
| 147 | +There is nothing magic about this practice--it just helps some people to keep track of what different variables contain. |
| 148 | +We could re-write the previous example to follow this convention: |
| 149 | + |
| 150 | +<javascript caption="Comparing DOM elements (with more readable variable names)"> |
| 151 | +var $logo1 = $("$logo"); |
| 152 | +var logo1 = $logo1.get(0); |
| 153 | + |
| 154 | +var $logo2 = $("#logo"); |
| 155 | +var logo2 = $logo2.get(0); |
| 156 | + |
| 157 | +alert( logo1 === logo2 ); // alerts 'true' |
| 158 | +</javascript> |
| 159 | + |
| 160 | +This code functions identically to the example above, but it is a little more clear to read. |
| 161 | + |
| 162 | +### jQuery objects are not "live" |
| 163 | + |
| 164 | +Given a jQuery object with all the paragraph elements on the page: |
| 165 | + |
| 166 | +<javascript caption="Selecting all 'p' elements on the page"> |
| 167 | +var allParagraphs = $("p"); |
| 168 | +</javascript> |
| 169 | + |
| 170 | +...you might expect that the contents will grow and shrink over time as `<p>` elements are added and removed from the document. |
| 171 | +This is *not* actually the case. |
| 172 | +The set of elements contained within a jQuery object will not change unless you modify it in your code. |
| 173 | +This means that the collection is not "live"--it does not automatically update as the document changes. |
| 174 | +If you expect the document may have changed from when you created the jQuery object, then update your collection by creating a new one! |
| 175 | +It can be as easy as re-running the same selector: |
| 176 | + |
| 177 | +<javascript caption="Updating the selection"> |
| 178 | +allParagraphs = $("p"); |
| 179 | +</javascript> |
| 180 | + |
| 181 | +### Wrapping up |
| 182 | + |
| 183 | +Although DOM elements provide all the functionality one needs to create interactive web pages, they can be a hassle to work with. |
| 184 | +The jQuery object wraps these elements to smooth out this experience and make common tasks easy. |
| 185 | +When creating or selecting elements with jQuery, the result will always be wrapped in a new jQuery object. |
| 186 | +If you do need the native DOM elements, you can always use the `get()` method and/or array-style subscripting to get at them. |
| 187 | + |
| 188 | +These dinstinctions may not be immediately obvious, but understanding them is an important step in fully utilizing jQuery as it was intended. |
0 commit comments