Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript for..in looping over arguments ie.for( arg in arguments) does not work in IE8 but it works in Chrome 8

I faced this strange situation where foreach like construct of javascript does not work in IE but it works in FF. Well not all for..in just this special funciton does not work. I will post the code. Tested in IE8. Tested also with XHTML DTD.

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
 <HTML>
  <HEAD>
   <TITLE> Test </TITLE>
   <META NAME="Generator" CONTENT="EditPlus">
   <META NAME="Author" CONTENT="">
   <META NAME="Keywords" CONTENT="">
   <META NAME="Description" CONTENT="">
  </HEAD>
 <script type="text/javascript">
 <!--
  String.prototype.format = function() {         
   var formatted = this;       
   var mycars = new Array(); //some 
   mycars[0] = "Saab";
   mycars[1] = "Volvo";
   mycars[2] = "BMW";
    var arg;
     for (arg in mycars) {        alert('it comes here');     
      formatted = formatted.replace("{" + arg + "}", arguments[arg]);         }         
      return formatted;
     };

  String.prototype.format2 = function() {         
  var formatted = this;       
  var arg;
     for (arg in arguments) {        alert('it does not come here');     
      formatted = formatted.replace("{" + arg + "}", arguments[arg]);         }         
      return formatted;    
  };

 function fn() {
  var s = 'The {0} is dead. Don\'t code {0}. Code {1} that is open source!'.format('ASP', 'PHP'); 
  alert('format:'+s);
   var s2 = 'The {0} is dead. Don\'t code {0}. Code {1} that is open source!'.format2('ASP', 'PHP'); 
 alert('format2:'+s2); //does not replace {0}s and {1}s
 } 
 //-->
 </script>
  <BODY>
  <input type="button" value="click " onclick="fn();" />

  </BODY>
 </HTML>

Update I posted a wrong question that it works in FireFox but not in IE8 which was wrong. It does not work in FireFox too. Actually I got this code from post JavaScript equivalent to printf/string.format.

like image 328
samarjit samanta Avatar asked Jan 28 '11 02:01

samarjit samanta


People also ask

How do I iterate over an object in JavaScript?

There are two methods to iterate over an object which are discussed below: Method 1: Using for…in loop: The properties of the object can be iterated over using a for..in loop. This loop is used to iterate over all non-Symbol iterable properties of an object.

What property of the array can be used when looping?

If we want to loop through an array, we can use the length property to specify that the loop should continue until we reach the last element of our array. In the loop above, we first initialized the index number so that it begins with 0 .

Is JavaScript supported by all browsers?

All the modern browsers come with built-in support for JavaScript. Frequently, you may need to enable or disable this support manually. This chapter explains the procedure of enabling and disabling JavaScript support in your browsers: Internet Explorer, Firefox, chrome, and Opera.


2 Answers

First of all, while the arguments object available within a function is not an array, it is "array-like" enough such that an incremental for loop (for (var i = 0, len = arguments.length; i < len; i++) { ... }) is preferable - not only because it runs faster, but also because it avoids other pitfalls - one of which is exactly what you're falling into.

To actually answer the question of why the second loop doesn't work, it's important to realize just what for ... in loop does: it iterates through all enumerable properties found in an object. Now, I've bolded 2 words in that statement, because I used these two words purposefully to indicate a couple of nuances that, while they may seem subtle, can drastically affect the behavior of your code if you don't realize what's going on.

First let's focus on all - by which I mean to say, not just properties of the object itself, but also potentially properties said object has inherited from its prototype, or its prototype's prototype, or so on. For this reason, it is very often recommended that you "guard" any for ... in loop by immediately additionally qualifying it with the condition if (obj.hasOwnProperty(p)) (assuming your loop were written for (var p in obj)).

But that's not what you're running into here. For that, let's focus on that second word, enumerable. All properties of objects in JavaScript are either enumerable or non-enumerable, which pretty much directly relates to whether the property shows up in a for ... in loop or not. In browsers such as Firefox and IE, as it turns out, the arguments object's numeric properties are not enumerable (nor is its length as it were), which is precisely why you're not iterating through anything!

But really, in the end, for iterating through anything that is an Array or array-like, you are better off using an incremental loop (as M. Kolodny also stated), and avoiding these shenanigans altogether (not to mention potential cross-browser inconsistencies - I seem to be noticing that in Chrome 10, the numeric properties of arguments objects are enumerable!)

like image 142
Ken Franqueiro Avatar answered Oct 17 '22 08:10

Ken Franqueiro


Try using this as a format function:

String.prototype.format = function() {
    var me = this;
    for (var i = 0; i < arguments.length; i++)
        me = me.replace(new RegExp('\\{' + i + '\\}', 'g'), arguments[i]);
    return me;
}

Now this should work:

alert('The {0} is dead. Don\'t code {0}. Code {1} that is open source!'.format('ASP', 'PHP'))

DEMO

Tested and working in IE

like image 20
Moshe K. Avatar answered Oct 17 '22 07:10

Moshe K.