0

I'm trying to loop through an object like you would an array. I'm struggling to append the loop counter to the variable name.

I have an object like this (output with dump(), which I found here):

object(2): {
  elem0:  array(4): {
    [0]:  string(27): "http://placehold.it/300x300"
    [1]:  string(3): "0.8"
    [2]:  string(4): "-150"
    [3]:  string(3): "200"
  }
  elem1:  array(4): {
    [0]:  string(27): "http://placehold.it/300x300"
    [1]:  string(3): "0.6"
    [2]:  string(3): "-70"
    [3]:  string(3): "458"
  }
}

Here's how I'm trying to loop through it:

jQuery(document).ready(function($) {

    // Provides object-measuring functionality
    Object.size = function(obj) {
        var size = 0, key;
        for (key in obj) {
            if (obj.hasOwnProperty(key)) size++;
        }
        return size;
    };

    // Returns the number of objects in my object
    var size = Object.size(window.depthElems);

    /*
    This is where I'm having difficulty.
    I would like to use window.depthElems.elem0,
    then window.depthElems.elem1, etc.
    */

    for (var i = 0; i < size; i++) {
        $('.wrapper').append('<img src="' + window.depthElems.elem+i+[0] + '" />'); 
    }

});
Community
  • 1
  • 1
Jezen Thomas
  • 13,619
  • 6
  • 53
  • 91
  • 2
    Why do you want to loop through it like an array and not use ``for(element in window.depthElems)`` and then ``window.depthElems[element]``? – KilZone Jul 25 '12 at 18:12
  • A better suggestion than console.log is console.dir http://stackoverflow.com/a/11656075/90648 ;) – Azder Jul 25 '12 at 18:19
  • @Azder The console isn't always available to me, so I'm quite happy with `dump()`. – Jezen Thomas Jul 25 '12 at 18:25
  • 1
    It seems you problem is with JavaScript objects, not JSON. I edited your question accordingly. – Felix Kling Jul 25 '12 at 18:36

2 Answers2

3

I will, for the sake of argument, also provide my question as answer. You can use:

for(element in window.depthElems) {
    if(window.depthElems.hasOwnProperty(element)) {
        $('.wrapper').append('<img src="' + window.depthElems[element] + '" />');
    }
}

This is not only more elegant, but also requires far less code. Of course if there is a reason to use the other code, please say so.

Note: This code is edited to also include the ability to read 'arrays', however the question was to make it work with 'objects'. If you use 'objects' the 'hasOwnProperty' check is superfluous.

Note #2: You can also use var hasOwn = Object.prototype.hasOwnProperty; like Azder said, which is a nice safeguard.

KilZone
  • 1,580
  • 9
  • 20
  • I'm unmarking this as the correct answer, because it [created problems for me](http://stackoverflow.com/questions/11657897/mystery-elements-appearing-when-appending/11657943#11657943). I still learned from it though, so it's still upvoted. – Jezen Thomas Jul 25 '12 at 20:20
  • If the solution is creating problems, then you're right unmarking it as the right answer. However, in this case the problem is not with the solution but with the use, since both answers (mine and the now 'correct' one use exactly the same code `for (... in ...) {}`). The difference is in the `hasOwnProperty(key, obj)` I forgot (sorry!), I'll update the answer. Again, without using the `Object.size` function is both faster and more elegant (you only loop through the element once). – KilZone Jul 25 '12 at 21:10
  • Also, just to be clear the question is talking about an **object** which contains arrays. In which case it's safe to use my original code, please don't 'unmark' my answer as correct because you changed usage case (my answer to your question was correct). – KilZone Jul 25 '12 at 21:21
  • @KilZone agree, OP may have jumped the gun accepting it without checking for problems, but it is OK to just let your answer be the accepted one. – Azder Jul 26 '12 at 05:17
  • @Azder Since both answers are correct, it's up for debate which one to accept. What I did want to avoid was the idea that my answer was incorrect, whereas for the original question it was not. You're right about 'jumping the gun', since I omit some things from my original answer which the OP required in the end, we'll see what the OP will do. – KilZone Jul 26 '12 at 07:05
  • That's fair. Thanks both of you, ever so much :) – Jezen Thomas Jul 26 '12 at 07:18
2

I apologize if my answer is over the top, I just like to prevent further hurt by miss-using JS (which I have experienced a lot) .

jQuery(document).ready(function($) {

    var i; // there is no block scope in JS, so better to be clear and define i here
    var $wrapper; // also

    // Changing the JS built-in objects is problematic most of the time
    // You should learn from jQuery and do wrapping instead
    // Or at least just a good namespasing like:
    // MyFramework.objectSize = function (obj) {}

    Object.size = function(obj) {
        var size = 0, key;
        var hasOwn = Object.prototype.hasOwnProperty; // will explain further down
        for (key in obj) {
            // if obj has redifined hasOwnProperty = function(){ return false; }?
            // it's better to use hasOwn like this if(hasOwn.call(obj,key)) {}
            // and please do use braces even if only 1 statement
            if(hasOwn.call(obj,key)) size++;
        }
        return size;
    };

    // Returns the number of objects in my JSON object
    var size = Object.size(window.depthElems);

    $wrapper = $('.wrapper'); // cached so jQuery doesn't search for it each iteration    

    // i is scoped to the whole function anyways
    for (i = 0; i < size; i++) {

        // $.each even guards you of the changing DOM which can cause
        // infinite loops (you don't have that problem here, but... good to know
        $.each(window['depthElems'+i],function(index,element){
            $wrapper.append('<img src="' + element + '" />');
        }); 
    }

});

Also, since you already make objects named elem1, elem2, elem3,... you might as well use a two dimensional array, like window.depthElems = [[],[],[]]

Azder
  • 4,698
  • 7
  • 37
  • 57
  • Oh by the way, I'm not manually creating those objects. [I tried to here](http://stackoverflow.com/questions/11648829/creating-js-objects-in-php-with-commas-in-between), but I've learned to use `json_encode`. – Jezen Thomas Jul 25 '12 at 18:47
  • 1
    what can I say, JS is far more elegant than PHP, you don't write array(), you just use [] :D – Azder Jul 25 '12 at 18:50