【问题标题】:Javascript add extra argumentJavascript添加额外的参数
【发布时间】:2012-11-16 15:40:42
【问题描述】:

让我们看看这段代码:

var mainFunction = function() {
  altFunction.apply(null, arguments);
}

传递给mainFunction 的参数是动态的——它们可以是4 或10,没关系。但是,我必须将它们传递给 altFunction 并且我必须在参数列表中添加一个 EXTRA 参数。

我试过这个:

var mainFunction = function() {
  var mainArguments = arguments;
  mainArguments[mainArguments.length] = 'extra data'; // not +1 since length returns "human" count.

  altFunction.apply(null, mainArguments);
}

但这似乎不起作用。我该怎么做?

【问题讨论】:

  • not +1 since length returns "human" count 是什么意思?
  • .length 返回 4 如果数组是 0, 1, 2, 3 它不返回 3,希望你现在明白了。这就是我的意思:P
  • 好吧,但这是.length 的预期行为。当您使用arr[arr.length] = "whatever" 时,它与使用.push() 的行为相同,只是将项目添加到数组的末尾。您的问题是 arguments 不是数组,因此您需要使用提供的许多类似解决方案之一。
  • 实际上,您几乎拥有它。如果您在调用 apply 之前也执行arguments.length++,您的代码将照常运行。

标签: javascript


【解决方案1】:

使用Array.prototype.push

[].push.call(arguments, "new value");

没有必要对arguments 对象进行浅层克隆,因为它及其.length 是可变的。

(function() {
    console.log(arguments[arguments.length - 1]); // foo

    [].push.call(arguments, "bar");

    console.log(arguments[arguments.length - 1]); // bar
})("foo");

来自 ECMAScript 5,10.6 Arguments Object

  1. 在 obj 上调用 [[DefineOwnProperty]] 内部方法,传递 "length"、属性描述符 {[[Value]]: len, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true} 和 false 作为参数。

所以你可以看到.length 是可写的,所以它会用数组方法更新。

【讨论】:

  • 是的,我可以发誓 arguments 是只读的,但后来我重新阅读了 MDN 规范并意识到了这一点
  • [].splice.call(arguments,0,0,NEW_VAR) 把它放在第一个参数,当你有一个函数首先需要一个特定的值时非常方便。
  • 我认为这是在“严格模式”中引发错误。如果遇到问题,请改用Array.prototype.push.call(arguments, 'bar')
  • 我认为这是一个 hack,但事实并非如此。来自文档:“push 是有意通用的。此方法可以与 call() 或 apply() 一起用于类似数组的对象。push 方法依赖于长度属性来确定从哪里开始插入给定值。”
  • 奇怪的是,简单地分配给arguments,就像arguments[arguments.length] = "bar";,看起来它可以工作,但是如果你通过apply()arguments 值传递给另一个函数,添加的arg 不是传递给该函数。它只接收原始参数。
【解决方案2】:

arguments 不是纯数组。您需要从中制作一个普通数组:

var mainArguments = Array.prototype.slice.call(arguments);
mainArguments.push("extra data");

【讨论】:

【解决方案3】:

arguments 对象不是数组; 就像一个数组,但它是不同的。但是你可以把它变成一个数组:

var mainArguments = [].slice.call(arguments, 0);

然后你可以将另一个值推到末尾:

mainArguments.push("whatever");

【讨论】:

    【解决方案4】:

    2016 年更新:您必须在添加元素之前将参数转换为数组。除了很多帖子中提到的切片方法:

    var args = Array.prototype.slice.call(arguments);
    

    您还可以使用 Array.from() 方法或扩展运算符将参数转换为真正的数组:

    var args = Array.from(arguments);
    

    var args = [...arguments];
    

    您的javascript引擎可能未优化以上内容,MDN已建议以下可能进行优化:

    var args = (arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments));
    

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments

    【讨论】:

      【解决方案5】:
      var mainFunction = function() {
          var args = [].slice.call( arguments ); //Convert to array
          args.push( "extra data");
          return altFunction.apply( this, args );
      }
      

      【讨论】:

        【解决方案6】:

        arguments“数组”不是数组(根据 Crockford 的说法,它是 JavaScript 中的一个设计错误),所以你不能这样做。不过你可以把它变成一个数组:

        var mainFunction = function() {
          var mainArguments = Array.prototype.slice.call(arguments);
          mainArguments.push('extra data');
        
          altFunction.apply(null, mainArguments);
        }
        

        【讨论】:

        • 为什么是错误?因为不喜欢?
        • 因为道格拉斯·克罗克福德是这么说的
        • @CallumMacrae:这不是 IMO 的原因。
        • 也许这是糟糕的设计,但这与错误不同。 IMO,错误是指某些事情无法按预期工作。我假设arguments 被制作成一个类似数组的对象,而不是一个数组故意,无论是否明智。
        • 为了节省内存,arguments 原型缺少通用的数组功能,只有基础。想一想,有多少个数组?让我们猜猜,与函数调用的数量相同吗?如果你可以节省空间,不是吗?如果需要,可以使用 apply 函数来处理将参数提升为完整功能数组的情况。其他一切都取决于用户。
        【解决方案7】:

        一个用于添加额外参数并返回新数组的衬线:

        [].slice.call(arguments).concat(['new value']));
        

        【讨论】:

          【解决方案8】:
          //
          //    var
          //        altFn  = function () {}, 
          //        mainFn = prefilled( altFn  /* ...params */ );
          //
          //    mainFn(  /* ...params */  );
          //  
          //        
          function prefilled ( fn /* ...params */ ) { 
               return ( function ( args1 ) { 
          
                    var orfn = this;
          
                    return function () { 
          
                        return orfn.apply( this, args1.concat( cslc( arguments ) ) );
          
                    };
          
               } ).call( fn, cslc( arguments, 1 ) );
          }
          
          // helper fn
          function cslc( args, i, j ) { 
             return Array.prototype.slice.call( args, i, j );
          }
          
          
          // example
          
          var
              f1 = function () { console.log( cslc( arguments ) ); }, 
              F1 = prefilled( f1, 98, 99, 100 );
          
          F1( 'a', 'b', 'c' );
          
          //
          //   logs: [98, 99, 100, "a", "b", "c"]
          //
          //
          

          【讨论】:

            【解决方案9】:

            在这种情况下,使用call() 而不是apply() 会更舒服:

            function first(parameter1, parameter2) {
            
              var parameter3 = "123";
            
              secondFunction.call(
                this,
                parameter1,
                parameter2,
                parameter3);
            },
            

            【讨论】:

              【解决方案10】:

              var myABC = '12321'; someFunction(result, error, myCallback.bind(this, myABC));

              参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

              【讨论】:

                【解决方案11】:

                对于那些像我一样正在寻找一种方法来添加可选参数并且可能不是唯一省略的参数的人(myFunc = function(reqiured,optional_1,optional_2,targetOptional)myFunc(justThisOne) 类似的调用),可以按如下方式完成:

                // first we make sure arguments is long enough
                // argumentPosition is supposed to be 1,2,3... (4 in the example above)
                while(arguments.length < argumentPosition)
                    [].push.call(arguments,undefined);
                // next we assign it
                arguments[argumentPosition-1] = arguments[argumentPosition-1] || defaultValue;
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多