为什么这个方法修改函数的参数数组会在省略param时失败?

时间:2018-03-17 18:48:23

标签: javascript function arguments

我正在修改某些"核心"的几个功能。 JS软件使用"劫持":

var orig_func = func; // initially function(a,b,c,d)

func = function(a,b,c,d) {
    // modify arguments
    d = someCustomization(c,d);
    // do additional stuff
    doSomethingCustom(a);
    // apply the original "core" function
    return orig_func.apply(this,arguments);
}

除非修改后的参数是可选的,否则可以正常工作:调用

func(a,b);

dundefined的方式工作,即使someCustomization在其参数均为undefined时返回其他内容。

这是一个在cosole中使用的MVCE:

var f = function(optionalParam){ if(optionalParam) console.log(optionalParam); };
var orig_f = f;
f = function(optionalParam){
    optionalParam = optionalParam ? 'custom: '+optionalParam : 'default';
    orig_f.apply(this, arguments);
};
f(); // shows undefined
f('test'); // shows 'custom: test'

"预期"行为是在第一种情况下在控制台中查看"default",但我得到的是undefined

经过一些实验并使用this thread,我总结了在corresponding answer中添加定位参数的问题,我提出了以下MCVE方案:

var f = function(some,optionalParam){
    console.log('some:',some);
    console.log('optionalParam:',optionalParam);
};
var orig_f = f;
f = function(some,optionalParam){
    if(optionalParam)
        optionalParam = 'custom: '+optionalParam;
    else {
        var argPosition = 2;
        while(arguments.length < argPosition)
            [].push.call(arguments,undefined);
        arguments[argPosition-1] = 'default';
    }
    orig_f.apply(this, arguments);
};
f(); // shows 'some: undefined' and 'optionalParam: default'

或就初始任务而言:

var orig_func = func; // initially function(a,b,c,d)

func = function(a,b,c,d) {
    // modify arguments
    while(arguments.length < 4)
        [].push.call(arguments,undefined);
    arguments[3] = someCustomization(c,d);
    // do additional stuff
    doSomethingCustom(a);
    // apply the original "core" function
    return orig_func.apply(this,arguments);
}

但我真的无法解释初始方法的问题是什么:为什么它适用于所需(使用过的)参数并且对于可选(未使用)参数失败?它与闭合有什么关系吗?为什么d是&#34;没有连接&#34;在第二种情况下使用arguments

2 个答案:

答案 0 :(得分:3)

arguments&#34;魔法绑定&#34;是通过迭代实际参数创建的,因此如果不存在arg,则不会创建任何绑定:

&#13;
&#13;
function a(x, y) {
    y = 42;
    console.log(arguments)
}

a(10, 20)
a(10)
&#13;
&#13;
&#13;

也就是说,使用魔术绑定是一个坏主意,他们无论如何都不会在严格模式下工作。如果事先知道参数的数量,只需执行

orig_func.call(this, a, b, c, d);

否则使用splat ...args并操纵它。

答案 1 :(得分:0)

是的,在georg(“魔术绑定”关键字)和更多研究的帮助下,我得出了一个几乎足够的解释:

    标准中的
  • (未找到哪一个)参数变量(a,b,c,d)和arguments[i]指向相同的值(不知道如何在JS 中完成这项工作,但是)

    • new 标准中并非如此(如Bergi所说,已弃用):更改arguments[0]不会影响a,反之亦然;就像乔治所说的那样,严格模式是这样的:

      function f(x) {
          "use strict";
          arguments[0] = 5;
          console.log( x );
      }
      f(1); // logs 1
      
  • 现在当所有变量都存在时,a,b,c,d(作为作用于函数的变量)和arguments[1-4]都被定义并成对连接,指向相同的值。当段落cd被省略时,arguments[3]arguments[4]未定义,即使我们定义它们,它们与变量之间也没有“连接”(同样,我不确定是否可以手动创建此类连接

  • 基本推荐是如果我们需要修改参数,我们应该只使用arguments(和.apply它们)或仅使用局部变量(并使用.call)或混合使用但不要不依赖于他们之间的联系