6

Analyzing the code showed by this SO question, I just noticed the way it's using jQuery to iterate a JSON array:

$(data).each(function() {

while in my mind an array should rather be iterated this way:

$.each(data, function() {

Indeed, the jQuery.each() manual page states:

The $.each() function is not the same as $(selector).each(), which is used to iterate, exclusively, over a jQuery object.

But since the OP seemed to have his code at least partially working I was curious to test, and discovered that it works!
Here is the proof:

var data = [
  {"key": "value-1"},
  {"key": "value-2"},
  {"key": "value-3"}
];

$(data).each(function() {
  document.write('<br />' + this.key);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

So if $(data).each() works when data is a JSON array, it seems to mean that this array is an acceptable content for $(data) to return a jQuery object.

Then pursuing the investigation I checked the jQuery(elementArray) manual page and looked at the jQuery( elementArray ) section, which states:

elementArray
Type: Array
An array containing a set of DOM elements to wrap in a jQuery object.

According with the above, an array of objects (instead of DOM elements) should fail.
So I tested to compare the objects returned by either this $(data) and a simple $('body'). Here is the result:

var data = [
  {"key": "value-1"},
  {"key": "value-2"},
  {"key": "value-3"}
];

function log(obj, init) {
  for (var prop in obj) {
    if (obj.hasOwnProperty(prop)) {
      var $row = $('tr[data-prop=' + prop + ']');
      if (!$row.length) {
        $row =
          $('<tr data-prop="' + prop + '"><th>' + prop + '</th></tr>')
          .appendTo($('table'));
        if (!init) {
          $row.append('<td></td>');
        }
      }
      $row.append('<td>' + JSON.stringify(obj[prop]).substr(0,25) + '</td>');
    }
  }
}

log($('body'), true);
log($(data), false);
table {
  border-collapse: collapse;
  border: 1px solid #000;
}
th, td {
  border: 1px solid #000;
  padding: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
  <tr>
    <th>Property</th>
    <th>$('body')</th>
    <th>$(data)</th>
  </tr>
</table>

Actually it appears that everything can be converted to a jQuery object.
I'm puzzled: am I reinventing the wheel!?

Community
  • 1
  • 1
cFreed
  • 4,404
  • 1
  • 23
  • 33
  • the jQuery function accepts plain objects as well. The page you linked mentions it. http://api.jquery.com/jQuery/#jQuery-object. You can perform limited jQuery functions on plain objects. In your case, i assume jquery detects the argument was iterable, so the each function worked correctly. – Eric Guan Mar 17 '16 at 02:19
  • @EricGuan Seemed an interesting elucidation, thanks. But looking at your link and then following the http://api.jquery.com/jQuery/#jQuery-object one, I read that "The PlainObject type is a JavaScript object containing zero or more key-value pairs.", and the example below enforces the fact that an array is not a PlainObject. So the oddity still exists... – cFreed Mar 17 '16 at 09:36

2 Answers2

1

You're reading into the documentation too much.

Yes, normally jQuery(elementArray) would be used in an array of elements. But, it can be an array of anything.

The intent is for you to use $.each() and possibly other convenience methods on arrays with normal elements. You'll find that other jQuery methods won't match anything in your array if your array doesn't have elements of some kind.

Brad
  • 159,648
  • 54
  • 349
  • 530
  • "_You're reading into the documentation too much_": this way, I'm pretty sure to avoid getting "_RTFM!_" comments :) More seriously, it's quite true that, based on an initially limited knowledge about this or that (here jQuery internals), I try to understand them in order to isolate what I could retain as best practices. To achieve that, I currently don't know a better way than checking documentation... and claim for advices from SO guys! – cFreed Jul 10 '16 at 10:30
  • @cFreed To be clear, you can never read the documentation too much. I'm saying that you're reading **into** the documentation too much, trying to imply meaning or documentation err where there is none. The documentation is almost always written from the perspective of intended usage, and in this case, both intended usages are documented. For a more thorough guide on *implementation*, you should read jQuery's source code. – Brad Jul 10 '16 at 16:15
  • Uh... now I understand what you meant. As a non-native English speaker, I didn't realize the difference between _into_ and _in_. Thanks for that clarification. – cFreed Jul 10 '16 at 16:37
1

Yes, jQuery constructor accepts an array and you can iterate through the returned jQuery collection using $.fn.each method and this within the handler refers to each element. A jQuery collection is an array-like object.

But, no, this doesn't mean that you can call all DOM related methods on the collection successfully. Just try $(data).html() as an example and you will get an error as it expects to see a DOM node and not a plain object or a string in the collection.

As another example try $(['foo']).text()and it throws Uncaught RangeError: Maximum call stack size exceeded error in jQuery 2.2.2.

And now try:

/**
 * `text` reads textContent of DOM elements (nodeType = 1)
 * and `nodeValue` of textNodes (nodeType = 3) 
 * and returns the concatenated text
 */
$([
  { "nodeType": 1, "textContent": "value-1" },
  { "nodeType": 3, "nodeValue": "value-2" },
  { "textContent": "I'm a rebel" }
]).text()

and it returns "value-1value-2"!

Community
  • 1
  • 1
Ram
  • 143,282
  • 16
  • 168
  • 197
  • "_no, this doesn't mean that you can call all DOM related methods_": I totally agree, and I never wanted to say something like that. My question only came from: 1) I was surprised to see the successfull use of `$(x).each()` when `x` is not a selector (contrary to jQuery.each() documentation, note it says "_excusively_"); 2) from that and deeper, to notice that in fact `$(x)` accepts anything as `x` (again contrary to jQuery(elementArray) documentation). But I found your final analytic sample much rewarding, thanks for that. – cFreed Jul 10 '16 at 11:21