Javascript查找传递给函数的参数

Pet*_*son 9 javascript argument-passing

我需要找到从函数传递给函数的参数.

让我们假设我有一个叫做的函数foo:

function foo() {
  var a = 3;
  var b = "hello";
  var c = [0,4];
  bar(a - b / c);
  bar(c * a + b);
}

function bar(arg) { alert(arg) }
Run Code Online (Sandbox Code Playgroud)

当然,现在,它bar总会提醒NaN.

在函数内部bar,我想以最初传递的形式获取参数.此外,我希望能够访问的值a,b以及cbar功能.换句话说,我想要这样的东西:

bar(a - b / c);    

function bar() {
 //some magic code here
 alert(originalArg); //will alert "a - b / c"
 alert(vars.a + " " + vars.b + " " + vars.c); //will alert "3 hello 0,4"
} 
Run Code Online (Sandbox Code Playgroud)

您可能认为这不可行,但我知道您可以使用Javascript做一些奇怪的事情.例如,您可以像这样显示调用函数的代码:

function bar() {
  alert(bar.caller);
}
Run Code Online (Sandbox Code Playgroud)

我愿意赌几美元,通过某种形式,你可以获得参数的原始形式和参数中变量的值.

如果你被允许以bar这样的形式打电话,我可以很容易地看到你如何做到这一点:

bar(function(){return a - b / c}, {a: a, b: b, c: c});
Run Code Online (Sandbox Code Playgroud)

但这太复杂,因此是不可接受的.bar调用方式可能无法更改.

Nic*_*ole 6

首先 - 奇怪的问题.知道你问的原因背景会有很大帮助,因为很明显Javascript并不完全符合你的要求.(例如,它是否与数学表达式具体相关?表达式是否必须在调用函数之前执行,如示例中所示?)

Javascript没有:

  • 命名参数
  • 一流/动态表达

Javascript 确实有:

  • 动态对象
  • 一流的功能
  • 关闭
  • eval

动态对象

由于这是你最后自己声明的选项,你宣称这是不可接受的,听起来它对你没什么帮助.在任何情况下,由于您需要表达式值,仅仅传递值的对象不会对您有所帮助.

一流的功能

如你所说,你有权访问Function.caller,虽然它只输出整个函数的String表示.它也是非标准的.

你也有arguments,这是传入的参数数组,没有命名.对于现有代码,显然,它将是表达式的执行结果.一个方便的用途arguments是不在函数签名中指定任何参数,然后作为开放式列表迭代数组.

关闭

这也是最后一个不可接受的解决方案的一部分,但可能最适合您的工作解决方案,尽管您必须在路上灵活bar调用定义它.

function foo() {
  var a = 3;
  var b = "hello";
  var c = [0,4];

  var bar = function(arg) {
    alert(arg); // NaN
    alert(a + " " + b + " " + c); //will alert "3 hello 0,4"
  }

  bar(a - b / c);
  bar(c * a + b);
}
Run Code Online (Sandbox Code Playgroud)

EVAL

使用eval和闭包,您可能会接近您想要的.

要记住的主要事情是,在您的代码中,a - b / c是一个表达式.这不是参数,表达式的结果就是参数.没有什么,除了一个toString在功能上本身会提醒"A - B/C".

随着eval(免责声明:这非常hacky,不推荐!你已被警告.),你实际上可以传递一个String作为参数,并使用绑定到空间的闭包,提醒你想要的.

function foo() {
  var a = 3;
  var b = "hello";
  var c = [0,4];

  function hackyUglyEvalAndOutput(callback, expression) {
    alert(expression); //will alert "a - b / c" (duh)
    alert(a + " " + b + " " + c); //will alert "3 hello 0,4" (because of the closure)
    callback(eval(expression)); // "NaN"
  }
  hackyUglyEvalAndOutput(bar, "a - b / c");
  hackyUglyEvalAndOutput(bar, "c * a + b");
}

function bar(arg) { alert(arg); }
Run Code Online (Sandbox Code Playgroud)

您可以类似地解析caller以查找对函数的调用,并查看传递给参数列表的内容(我确实让它执行此操作)但是如果有多个调用,则无法区分哪个调用了.从您的示例来看,这对于完成您想要做的事情至关重要.

再一次 - 表达只是那样,仅此而已; 他们不是争论.

PS第二次调用bar将实际输出NaNhello:)


Joe*_*son 3

你的问题被误导了,而且很病态……我喜欢它!这是一个简短的解决方案,我将对此进行解释。

function foo() {
    var a = 3, b = "hello", c = [0, 4];
    bar(a - b / c); 
}

function bar(n) {
    alert([n, a, b, c, eval(n)].join('   '));
}

function meld(f, g) {
    f = f.toString(); g = g.toString();
    f = f.replace(/function\s+\w+/, 'function ');

    var n = g.match(/function\s+(\w+)/)[1];
    f = f.replace(new RegExp(n + '\\((.*?)\\)', 'g'), n + '("$1")');

    var i = f.indexOf('{') + 1;
    f = f.slice(0, i) + g + f.slice(i);

    eval('var ret = ' + f);
    return ret;
}

foo = meld(foo, bar);
foo();
Run Code Online (Sandbox Code Playgroud)

关键是meld(f, g)返回一个新的匿名函数的函数,该函数的作用就像f调用并将其内部暴露给g. 你看,原始版本g很难看到任何内容f——它充其量只能使用g.caller大量的正则表达式。

这是 的伪代码meld。首先创建f一个匿名函数,适合稍后评估和分配给变量;例如function foo() {变成function() {. 接下来查找g真实姓名并引用从 new 传递给它的任何参数fg接下来,在 new 内部插入一个副本f。它将屏蔽全局名称,并且可以访问 的f局部变量,就好像它们是它自己的变量一样。最后,评估这个匿名函数并返回它。

那么我们该如何使用呢meld?只需替换foomeld(foo, bar),然后foo像平常一样使用即可。

好的,现在来说说限制。我不想花费大量精力来改进内部的正则表达式meld来引用g反对所有可能性的论点。这只会分散人们对整个解决方案概念的注意力。您需要更改它以正确处理多个参数并转义任何本身带有引号或括号的参数。