【问题标题】:Javascript for..in looping over arguments ie.for( arg in arguments) does not work in IE8 but it works in Chrome 8Javascript for..in 循环参数 ie.for(arg in arguments) 在 IE8 中不起作用,但在 Chrome 8 中起作用
【发布时间】:2011-06-16 23:44:24
【问题描述】:

我遇到了这种奇怪的情况,即类似 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。实际上,我是从JavaScript equivalent to printf/string.format 帖子中获得此代码的。

【问题讨论】:

  • 你用的是哪个版本的IE?
  • 我使用的是 IE8、FF3.6.8 和 chrome 8.0.552

标签: javascript internet-explorer foreach arguments


【解决方案1】:

用于(i=0;i

【讨论】:

    【解决方案2】:

    一些浏览器支持 for..in 像 Chrome 和 Firefox 4 来迭代参数,但其他浏览器在这样迭代时看不到它的参数。我敢打赌,如果您在这些浏览器上执行 JSON.stringify(arguments),结果将是一个空对象。根据 JavaScript 1.1 的规范,其他参数都有一个长度参数,这意味着您可以使用 for (var i = 0; i &lt; arguments.length; i++)while(i &lt; arguments.length) 循环来迭代它们。

    当我使用for..in 进行参数迭代时,我个人为参数对象迭代编写了一个简单的函数,该函数不依赖于长度,因为参数总是按 ID 顺序标记。

    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/

    上了解更多信息

    【讨论】:

    • 如果您提供 start_from 和 end_where 它不称为迭代 en.wikipedia.org/wiki/Iterator_pattern。你正在逃避问题。我询问了差异的原因而不是解决方法,我从Ken 得到了完美的回答。当您使用for..in 被烧毁时,实际上引用您的用例实际上可能会启发我们更多。无论如何,我感谢你的努力,试图提供一个解决方案。
    【解决方案3】:

    根据我的测试,对于 Firefox 3.6.13 和 IE 8,我没有看到任何行为差异,它们都不会进入第二个循环。

    mycars 和 arguments 之间的一个区别是 mycars 是一个数组,而 arguments 是一个对象。

    为了证明这一点:

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

    但是,通过一些测试代码,我可以看到“for in”适用于数组和对象

    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 之间有任何区别。

    更新:感谢 Ken cmets,我发现,参数属性被定义为不可枚举,而在定义 Object 文字时,属性被隐式定义为可枚举。

    【讨论】:

    • 我很抱歉它在 IE8 和 FF3.6 上以同样的方式工作。我刚才又试了一次。那么在chrome中它的工作方式不同。我不知道为什么我发布了一个错误的问题,可能是我会尝试编辑问题,将 Chrome 替换为 FF。但功劳归于肯,他解决了这个谜题,论据数不胜数。
    【解决方案4】:

    首先,虽然函数中可用的 arguments 对象不是数组,但它足够“类似数组”,因此增量 for 循环 (for (var i = 0, len = arguments.length; i &lt; len; i++) { ... }) 更可取 - 不仅因为它运行得更快,而且还因为它避免了其他陷阱 - 其中一个正是您所陷入的。

    要真正回答为什么第二个循环不起作用的问题,重要的是要了解 for ... in 循环的作用:它遍历 所有可枚举 在对象中找到的属性。现在,我在该声明中加粗了两个词,因为我有目的地使用这两个词来表示一些细微差别,虽然它们可能看起来很微妙,但如果你没有意识到发生了什么,它们会极大地影响你的代码的行为.

    首先让我们关注所有 - 我的意思是说,不仅是对象本身的属性,还包括该对象从其原型或原型的原型继承的潜在属性,等等在。出于这个原因,通常建议您通过立即另外使用条件 if (obj.hasOwnProperty(p)) 限定它来“保护”任何 for ... in 循环(假设您的循环编写为 for (var p in obj))。

    但这不是你在这里遇到的。为此,让我们关注第二个词,enumerable。 JavaScript 中对象的所有属性要么是可枚举的,要么是不可枚举的,这几乎直接关系到属性是否出现在 for ... in 循环中。事实证明,在 Firefox 和 IE 等浏览器中,arguments 对象的数字属性是不可 可枚举的(它的 length 也不是),这正是您不可枚举的原因遍历任何东西!

    但实际上,最终,为了迭代任何数组或类似数组的东西,最好使用增量循环(正如 M. Kolodny 所说),并完全避免这些恶作剧(更不用说潜在的跨浏览器不一致 - 我似乎注意到在 Chrome 10 中,arguments 对象的数字属性 是可枚举的!)

    【讨论】:

    • 谢谢你,Ken,+1 有趣的答案,所以你知道为什么如果我用大括号构建对象,属性是可枚举的......那么什么样的对象是参数?或者换一种说法,我如何声明一个具有不可枚举属性的对象?我觉得有一个对象“参数”而不理解它有点奇怪,似乎是用“魔法”而不是普通语言构造构建的。但也许我错过了什么。
    • 嗯,arguments 有点特殊,因为它是 JavaScript 运行时本机实现的对象之一。如果您对对象的这些特性感兴趣,ECMAScript 5 为您提供了在您自己的自定义对象中完全控制这些功能的方法,但要意识到并非所有浏览器都支持 ES5。查看 MDN 了解更多信息,可能从 here 开始,然后从“另请参阅”链接继续。
    • 谢谢.. 我现在看到了示例中的“魔法”: Object.defineProperty(o, "b", { value: 2, enumerable: false });但是,据我了解,您建议最好不要使用此语法,因为它并非在所有浏览器中都实现。奇怪的是,他们决定将参数定义为不可枚举,这看起来像是一个疏忽。
    【解决方案5】:

    尝试将其用作格式函数:

    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 中测试和工作

    【讨论】:

    • 我知道这行得通,我想知道为什么 for..in 不起作用。
    • @samarjitsamanta 那是因为 arguments[] 并不是一个真正的数组,它只是看起来像一个。您可以将其转换为这样的数组:args = Array.prototype.slice.call(arguments) 您将获得它从原型对象继承的许多其他属性,但您可以使用 hasOwnProperty() 将其过滤掉。看看我的意思:jsfiddle.net/C3nWG。如果您不想被那个小提琴太烦,请打开控制台
    【解决方案6】:

    嗯,它应该可以工作,所以如果没有,答案很简单,就像“这是 IE 中的另一个错误”。

    但这里真正的问题是为什么要使用for ... in 来迭代数组或类似数组的对象(例如arguments)——只需使用简单的for 循环,它适用于所有主要的浏览器:

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

    【讨论】:

    • @Raynos:我非常怀疑即使是 IE 的开发人员也能回答这个问题。
    • @casablance 我想知道。您是否还可以在该示例代码中指出他在该示例代码中做错的所有其他事情。
    • 您使用的是哪个版本的 Firefox?对于 FF 3.6.13 和 IE 8,我没有注意到行为上有任何差异,它们都不会进入第二个循环。
    • @stivlo:我实际上没有测试代码。我只是提到OP不应该使用for ... in
    • 我认为未经测试就声称“这是 IE 中的另一个错误”是不正确的,尤其是当 FF 具有完全相同的行为时。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-15
    • 1970-01-01
    • 2011-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多