3

我正在为一组函数编写一些脚本,这些函数都通过一个调用进行操作,并采用大量参数来返回一个值。主要功能需要使用需要使用相同参数的其他 11 个功能。我的结构有点像这样:

function mainfunction(param1, param2, ..., param16)
{
    //do a bunch of stuff with the parameters
    return output;
}

function secondaryfunction1()
{
    //gets called by mainfunction
    //does a bunch of stuff with the parameters from mainfunction
}

我可以做些什么来使传递给 mainfunction 的参数可用于所有辅助函数而不传递它们或使它们成为全局变量?如果没有,那很好,我会将它们作为参数传递 - 我很好奇我是否可以更优雅地做到这一点。

4

5 回答 5

8

您可以将secondaryfunction1inside的定义mainfunction

function mainfunction(param1, param2, ..., param16){
    function secondaryfunction1() {
     // use param1, param2, ..., param16
    }
    secondaryfunction1();
}

更新:

正如@dystroy 指出的那样,如果您不需要在secondaryfunction1其他地方打电话,这是可行的。在这种情况下,参数列表来自哪里——我不知道。

于 2013-05-31T19:08:24.830 回答
5

您可以使用arguments传递给 的secondaryFunction1所有参数mainfunction。但那将是愚蠢的。

您可能应该做的以及通常做的是将所有参数嵌入“选项”对象中:

function mainfunction(options){
    secondaryfunction1(options);
}

function secondaryfunction1(options) {
     // use options.param1, etc.
}

// let's call it
mainfunction({param1: 0, param2: "yes?"});

这带来了其他优势,例如

  • 给你传递的参数命名,非得统计参数才能知道改哪一个,这对维护来说可不是什么好事。没有一个理智的库会让你将 16 个参数作为直接的未命名参数传递给函数
  • 使您可以仅传递所需的参数(其他参数为默认参数)
于 2013-05-31T19:05:39.637 回答
0

@Igor 的答案(或一些变体)是要走的路。但是,如果您必须在其他地方使用这些功能(正如@dystroy 指出的那样),那么还有另一种可能性。将您的参数组合成一个对象,并将该对象传递给辅助函数。

function combineEm() {
    // Get all parameters into an array.
    var args = [].slice.call(arguments, 0),
        output = {},
        i;
    // Now put them in an object
    for (i = 0; i < args.length; i++) {
        output["param" + i] = args[i];
    }
    return output;
}

在您的主要功能中,您可以执行以下操作:

function mainfunction(param1, param2, ..., param16) {
    var params = combineEm(param1, param2, ..., param16);
    var output = secondaryfunction(params);
    // etc.
    return output;
}
于 2013-05-31T19:45:55.140 回答
0

编辑:我只是想澄清到目前为止所有提出的建议都有效。他们只是每个人都有自己的权衡/好处。

我尝试只是建议对其他答案进行一些更改,但最终我觉得我需要发布我的解决方案。

var externalFn = function(options) {
  var str = options.str || 'hello world';

  alert(str);
};

var main = function(options) {
  var privateMethod = function() {
    var str = options.str || "foobar";

    alert("str: " + str);
  };

  // Bind a private version of an external function
        var privateMethodFromExternal = externalFn.bind(this, options);

  privateMethod();
  privateMethodFromExternal();
};

main({ str: "abc123"});
// alerts 'str: abc123'
// alerts 'abc123'
main({});
// alerts 'str: foobar'
// alerts 'hello world'
  • 问题的要点似乎是“主函数”使用的函数不应该继续将选项/上下文传递给它们。
  • 这个例子展示了如何在函数中使用 privateMethods
  • 它还展示了如何获取外部函数(您可能在外部使用main)并绑定它们的私有方法版本以在内部使用main
  • 我更喜欢使用某种“选项”对象,但是对于 OP 真正询问的范围界定问题,这方面并不那么重要。您也可以使用“常规”参数。

这个例子可以在 codepen 上找到

于 2013-05-31T20:02:47.677 回答
0

如果您对这类事情感兴趣,这是一个非常顽皮的解决方案。

var f1 = function() {
  var a = 1;
  var _f2 = f2.toString().replace(/^function[^{}]+{/, '');
  _f2 = _f2.substr(0, _f2.length - 2);
  eval(_f2);
}

var f2 = function(a) {
  var a = a || 0;
  console.log(a);
}

f2();   // logs 0
f1();   // logs 1

它完全在当前范围内执行某些外部函数的内容。

但是,这种诡计几乎肯定表明您的项目组织错误。调用外部函数通常应该不比传递一个对象更困难,正如dystroy的回答所暗示的那样,在范围内定义函数,正如Igor的回答所暗示的那样,或者通过附加一些外部函数this并主要针对this. 像这样:

var FunLib = {
  a : 0,
  do : function() {
    console.log(this.a);
  }
}

var Class = function() {
  this.a = 1;
  this.do = FunLib.do;
  this.somethingThatDependsOnDo = function() {
    this.a++;
    this.do();
  }
}

var o = new Class();

FunLib.do()                     // 0
o.do()                          // 1
o.somethingThatDependsOnDo();   // 2
o.do()                          // 2 now

类似地,并且可能通过类层次结构更好地解决。

function BasicShoe {
  this.steps_taken = 0;
  this.max_steps = 100000;

  this.doStep = function() {
    this.steps_taken++;
    if (this.steps_taken > this.max_steps) {
      throw new Exception("Broken Shoe!");
    }
  }
}

function Boot {
  this.max_steps = 150000;
  this.kick_step_equivalent = 10;

  this.doKick = function() {
    for (var i = 0; i < this.kick_step_equivalent; i++) {
      this.doStep();
    }
  }
}
Boot.prototype = new BasicShoe();

function SteelTippedBoot {
  this.max_steps = 175000;
  this.kick_step_equivalent = 0;
}
SteelTippedBoot.prototype = new Boot();
于 2013-05-31T20:07:13.340 回答