【问题标题】:JS: strange result while accessing to arguments by keyJS:按键访问参数时出现奇怪的结果
【发布时间】:2016-07-23 07:24:31
【问题描述】:

我有一个带有两个处理函数参数的简单循环的函数:

var getArgs=function(){

    var keys = Object.keys(arguments);

    for(var argKey in arguments){
        console.log({argKey:argKey, argument:arguments[argKey]});
    }

    keys.forEach(function(argKey){
        console.log({argKey:argKey, argument:arguments[argKey]});
    });
};

...及其调用:

getArgs(5,3,2,11,15,7,-25);

似乎他们做的一样,所以输出也应该是一样的,但事实并非如此。 第一个工作相当可预测。输出是:

{ argKey: '0', argument: 5 }
{ argKey: '1', argument: 3 }
{ argKey: '2', argument: 2 }
{ argKey: '3', argument: 11 }
{ argKey: '4', argument: 15 }
{ argKey: '5', argument: 7 }
{ argKey: '6', argument: -25 }

但是第二个行为出乎意料:

{ argKey: '0', argument: '0' }
{ argKey: '1', argument: 1 }
{ argKey: '2', argument: [ '0', '1', '2', '3', '4', '5', '6' ] }
{ argKey: '3', argument: undefined }
{ argKey: '4', argument: undefined }
{ argKey: '5', argument: undefined }
{ argKey: '6', argument: undefined }

为什么?

【问题讨论】:

    标签: javascript object for-loop foreach arguments


    【解决方案1】:

    for 循环不是函数。因此,arguments 保留了getArgs 的上下文。

    forEach 虽然你认为它是一个循环,但实际上是一个运行循环的函数。因此,arguments 有一个新的上下文,这不是您所期望的。

    要解决此问题,请将参数设置为新变量并在 forEach 中使用该变量。

    运行此代码,您将得到预期的结果:

    var getArgs=function(){
    
        var keys = Object.keys(arguments);
        var args = arguments;
    
        for(var argKey in arguments){
            console.log({argKey:argKey, argument:arguments[argKey]});
        }
    
        keys.forEach(function(argKey){
            console.log({argKey:argKey, argument:args[argKey]});
        });
    };
    

    【讨论】:

    • 你们俩都让我大吃一惊。很好的问答!
    【解决方案2】:

    至于arguments-object?你在玩两个不同的arguments-objects。
    就像this-关键字一样,上下文很重要!

    看看这个:

    var getArgs = function(){
        var keys = Object.keys(arguments);
    
        for(var argKey in arguments){
            console.log({argKey:argKey, argument:arguments[argKey]});
        }
    
        var _args = arguments;
        keys.forEach(function(argKey){  
            console.log({
                argKey: argKey,
    
                argument: arguments[argKey], 
                argumentFunction: arguments.callee.toString(),
    
                realArgument: _args[argKey],
                realArgumentFunction: _args.callee.toString()
            });
        })
    }
    //or that:
    var getArgs = function(){
        var keys = Object.keys(arguments);
        keys.forEach((argKey) => {  
            console.log({
                argKey: argKey,
                argument: arguments[argKey]
            });
        })
    }
    

    但是,一旦你弄乱了参数对象(并将其传递给像Object.keys() 这样的函数,就被认为是弄乱了),这个函数就不能再优化了。

    var getArgs = function(){
        //you don't need for..in, you are not iterating over an Object or a (huge) sparse Array
        for(var i=0, len=arguments.length; i<len; ++i){
            console.log({
                argKey:i, 
                argument:arguments[i]
            });
        }
    }
    

    如果你想传递参数,你应该先将它们复制到一个数组中。

    for(var i = arguments.length, args = new Array(i); i--; ) args[i] = arguments[i];       
    //now you can do whatever you want to args.
    

    但是这样做的目的是什么。这种动态的参数长度很少是一个好主意,如果你想传递一个列表,然后传递一个列表(又名数组或类似的东西)

    【讨论】:

      【解决方案3】:

      foreach 不起作用的原因是您将参数带入了闭包中,因此您从参数中获取了参数。

      尝试将 console.log(arguments) 添加到 foreach 闭包中,您可以看到它发生了什么。

      我提供了一些有效的示例,这些示例基于您的代码。

      var getArgs=function(){
      
          var keys = Object.keys(arguments);
          var myargs = arguments;	// Copy arguments object (not as reference) so we can keep it into the scope when the arguments are reading from a closure or callback.
         
          console.log("var in method");
          
          for(var argKey in arguments){
              console.log({argKey:argKey, argument:arguments[argKey]});
          }
          
          console.log("foreach method by key");
          keys.forEach(function(value, key) {
          	console.log({argKey:key, argument:myargs[key]});
          });
          
          // Because we don't have foreach method for objects we can slice it as an array
          console.log("foreach method by argument array");
          Array.prototype.slice.call(arguments).forEach(function(value, key) {
          	console.log({argKey:key, argument:value});
          });
      
      };
      
      getArgs(5,3,2,11,15,7,-25);

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-01-18
        • 1970-01-01
        • 1970-01-01
        • 2018-06-27
        • 1970-01-01
        • 2016-06-24
        • 1970-01-01
        相关资源
        最近更新 更多