• For…In and the Array prototype

    by  • 2011-09-06 • jQuery • 0 Comments

    I just ran into an… “interresting” problem with Javascript.
    Extending an Array prototype and a naïve For…In iteration over an array spells trouble in FireFox.
    I’ve only seen this issue in FireFox and I suspect it’s a bug. No doubt it’ll soon enough be fixed but in the meantime this post may help you fix it.

    The situation

    1. Add a function to Array.prototype. In my case this was handily provided by a third party plug-in in the form of an Array.prototype.contains() function.
    2. Use jQuery to load some JSON array. (Haven’t tested it, but I think any array will do, not just ones created using jQuery, JSON, AJAX or any other specific method).
    3. Iterate over the array using the For…In loop.

    Seems innocent enough, but FireFox will also iterate over the contains() function, causing all sorts of weird problems.

    An example

    (Actual buggy code!)

    $.post('fields.php'
    	,	{	'action': 'get_fields'
    		,	'listid': listid
    		}
    	,	function(json) {
    			for (fieldid in json.fields) {
    				$('#fields').append(getFieldHTML(fieldid, json.fields[fieldid]));
    			}
    		}
    );

    So… how to fix it?

    Since I was using jQuery, the obvious fix was to just use $.each, which is a usually more convenient anyway. Here’s the same bit of code as before, but using $.each:

    $.post('fields.php'
    	,	{	'action': 'get_fields'
    		,	'listid': listid
    		}
    	,	function(json) {
    			$.each(json.fields, function(fieldid, name) {
    				$('#fields').append(getFieldHTML(fieldid, name));
    			});
    		}
    );

    For a pure Javascript solution (but why bother if we’re already using jQuery?), the following should work as well:

    $.post('fields.php'
    	,	{	'action': 'get_fields'
    		,	'listid': listid
    		}
    	,	function(json) {
    			for (var fieldid = 0; fieldid < json.fields.length; ++fieldid) {
    				$('#fields').append(getFieldHTML(fieldid, json.fields[fieldid]));
    			}
    		}
    );

    The benefit of this last solution is that only the line with the for(…) statement changes, but I think a similar problem to the one we were trying to fix might occur when iterating over an Object. I’d rather stick with jQuery and let the collective hivemind of developers prevent my bugs ;)

    Leave a Reply

    Your email address will not be published. Required fields are marked *