Javascript для ... в цикле по аргументам ie.for (аргументы в аргументах) не работает в IE8, но работает в Chrome 8 - PullRequest
8 голосов
/ 28 января 2011

Я столкнулся с этой странной ситуацией, когда foreach, как конструкция javascript, не работает в IE, но работает в FF.Ну не все for..in просто эта специальная функция не работает.Я выложу код.Проверено в IE8.Протестировано также с 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>

Обновление Я разместил неправильный вопрос, что он работает в FireFox, но не в IE8, что было неправильно.Это не работает в FireFox тоже.На самом деле я получил этот код из post JavaScript, эквивалентного printf / string.format .

Ответы [ 5 ]

23 голосов
/ 28 января 2011

Прежде всего, хотя объект arguments, доступный внутри функции, не является массивом, он достаточно «похож на массив», так что предпочтительным является инкрементный цикл (for (var i = 0, len = arguments.length; i < len; i++) { ... }) - не только потому, что он работает быстрее, но также потому, что он избегает других ловушек - одна из которых является именно той, в которую вы попадаете.

Чтобы на самом деле ответить на вопрос почему второй цикл не работает, это важночтобы понять, что делает цикл for ... in: он перебирает все перечисляемые свойства, найденные в объекте.Теперь я выделил 2 слова в этом утверждении, потому что я использовал эти два слова целенаправленно, чтобы указать на пару нюансов, которые, хотя они могут показаться тонкими, могут кардинально повлиять на поведение вашего кода, если вы не понимаете, что происходит.

Сначала давайте сосредоточимся на all - под этим я подразумеваю не только свойства самого объекта, но и потенциально свойства, которые указанный объект унаследовал от своего прототипа или прототипа своего прототипа.или так далее.По этой причине очень часто рекомендуется «защищать» любой цикл for ... in, немедленно дополнительно дополнительно квалифицируя его с условием if (obj.hasOwnProperty(p)) (при условии, что ваш цикл записан for (var p in obj)).

Ноэто не то, что вы сталкиваетесь здесь.Для этого давайте сосредоточимся на втором слове: enumerable .Все свойства объектов в JavaScript являются перечисляемыми или не перечисляемыми, что напрямую связано с тем, отображается ли свойство в цикле for ... in или нет.В браузерах, таких как Firefox и IE, оказывается, что числовые свойства объекта arguments являются не перечисляемыми (как и его length, как это было бы), именно поэтому вы не выполняете итерациичерез что-нибудь!

Но на самом деле, в конце концов, для итерации по всему, что является массивом или массивом, вам лучше использовать инкрементный цикл (как сказал также М. Колодный) и избежать этих махинацийв целом (не говоря уже о потенциальных кросс-браузерных несоответствиях - мне кажется, я заметил, что в Chrome 10 числовые свойства arguments объектов являются перечисляемыми!)

2 голосов
/ 28 января 2011

Попробуйте использовать это как функцию форматирования:

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;
}

Теперь это должно работать:

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

DEMO

Протестировано и работает в IE

1 голос
/ 28 января 2011

Из моего теста с Firefox 3.6.13 и IE 8 я не вижу никакой разницы в поведении, они оба не идут во второй цикл.

Одно отличие между mycars и аргументами состоит в том, чтоmycars - это массив, а аргументы - объект.

Чтобы продемонстрировать это:

alert(mycars.constructor);    //shows: "function Array() { [native code] }"
alert(arguments.constructor); //shows: "function Object() { [native code] }"

Однако, с некоторым тестовым кодом, я вижу, что for for работает для Array и Object

var showWithForIn = function (myArgument) {
    for (i in myArgument) {
        alert(myArgument[i]);
    }
};

var testArray = function() {
    var mycars = new Array(); //some 
    mycars[0] = "Saab";
    mycars[1] = "Volvo";
    mycars[2] = "BMW";
    showWithForIn(mycars);
};

var testObject = function() {
    var myFriends = {
        0: 'John',
        1: 'Aileen'
    };
    showWithForIn(myFriends);
};

function testAll() {
    testArray();
    testObject();
}

Итак, я не уверен, чем аргументы Object отличаются от Object, который вы создаете сами с помощью литерала фигурных скобок.Я думаю, что это сбивает с толку, потому что в этом тесте для работает как для массива и объекта.Хотя «for in» не работает с аргументами.

Опять же, во всех тестах я не заметил никакой разницы между FF 3.6 и IE 8.

UPDATE : Как я выяснил благодаря комментариям Кена, свойства аргументов определены как не перечисляемые, в то время как при определении литерала свойства объекта неявно определяются как перечислимые.

0 голосов
/ 20 декабря 2013

Некоторые браузеры поддерживают for..in, такие как Chrome и Firefox 4, для итерации аргументов, но другие браузеры не видят его параметры при такой итерации. Могу поспорить, что в этих браузерах, если вы сделаете JSON.stringify (arguments), результатом будет пустой объект. По спецификации JavaScript 1.1 и дальнейшие аргументы имеют параметр длины, что означает, что вы можете повторять их, используя циклы for (var i = 0; i < arguments.length; i++) и while(i < arguments.length).

Лично, когда я сгорел, используя for..in для итерации аргумента, я написал простую функцию для итерации объекта аргумента, которая не зависит от длины, потому что аргументы всегда помечаются в порядке по идентификаторам.

var eachArg = function(args, fn, start_from, end_where) {
    var i = start_from || 0;
    while (args.hasOwnProperty(i)) {
        if (end_where !== undefined && i === end_where)
            return i;
        if (fn !== undefined)
            fn(i, args[i]);
        i++;
    }
    return i;
};

Я использую его с тех пор, когда перебираю аргументы, и это меня не подводит. Подробнее об этом в моем блоге http://stamat.wordpress.com/iterating-arguments-in-javascript/

0 голосов
/ 28 января 2011

Ну, это должно сработать, поэтому, если это не так, ответ так же прост, как «это еще одна ошибка в IE».

Но реальный вопрос здесь в том, почему вы используете1003 * для перебора массивов или массивоподобных объектов (таких как arguments) - просто используйте вместо этого простой цикл for, который работает во всех основных браузерах:

for (var i = 0; i < arguments.length; i++) {
  // do something with arguments[i]
}
...