Search code examples
javascriptfor-loopfor-in-loop

Javascript for-in loop bizarre behavior


Suddenly, I am seeing a strange behavior. Here is a snippet:

// attributesList is an object with properties 0, 1, 2.
for (var j in attributesList) {
   // this loop should run 3 times.
   var attribute = attributesList[j];
}

As you can see from above, the loop should run 3 times. But for some very strange reason it is being run 4 times. For the last iteration the value of j == "seek".

Even stranger, this same code base works on another git branch (no changes). This only seems to happen when I run this from a particular git branch.

Is there any logical explanation for this mysterious "seek" property? One thing I tried looking into is perhaps javascript version and any other versioning differences... but no luck here.

* Updated *

attributesList is an array of object type.


Solution

  • The object in question has four enumerable properties. It probably inherits seek from its prototype object, which is why you think it only has three properties.

    Your comment to MikeC adds weight to that:

    when I evaluate the attributesList during run/debug time I do not see any property called "seek"

    As does your update:

    attributesList is an array of object type.

    That tells us that somewhere in your codebase (probably in a plugin), someone has been very naughty and added an enumerable property to Array.prototype. They can do that with various different syntaxes; if it's just the one property (seek), it's probably like this:

    Array.prototype.seek = function() {
        // ...
    };
    

    That's poor practice, they should have made it non-enumerable:

    Object.defineProperty(Array.prototype, "seek", {
        value: function() {
            // ...
        }
    });
    

    But fundamentally, for-in is not for looping through arrays. See my other answer here for how to loop through arrays.

    Two excerpts from that long answer:

    Use forEach:

    attributesList.forEach(function(attribute) {
       // ...
    });
    

    or if you really want to use for-in, add a hasOwnProperty check:

    for (var j in attributesList) {
       if (attributesList.hasOwnProperty(j)) {
          // this loop should run 3 times.
          var attribute = attributesList[j];
       }
    }
    

    or of course use a for loop. See the answer for details.