【问题标题】:JavaScript: Get Argument Value and NAME of Passed Variable [duplicate]JavaScript:获取传递变量的参数值和名称[重复]
【发布时间】:2010-11-03 20:09:14
【问题描述】:

我想要做的是获取传递给函数的变量的名称​​和该变量的值,并且只需将一个变量传递给函数。所以:

var x = "anything";

function showName() {

}

showName(x);

showName("x");

这将返回:“x = 任何东西”。

现在,我必须指定变量两次:

showName("x", x);

为了获取我传入的变量的名称和值。

请注意,我对showName原型中的参数名称不感兴趣,而是调用函数中的变量名称。另外,传递的变量可能是本地的,所以无法使用window对象来查找变量。

【问题讨论】:

标签: javascript arguments


【解决方案1】:

简短的回答是你不能。

更长的,邪恶的答案是,你可以有一些真正的肮脏。它只在从另一个函数调用时才有效。

有两个有趣的属性可以帮助您

arguments.callee 来电者

让 fn 做这样的事情:

(function(){
  var showMe = function(s){
    alert(arguments.callee.caller.toString().match(/showMe\((\S)\)/)[1] + 
    ' = '+ s)
  }
  x = 1
  showMe(x)
})()

arguments.callee.caller.toString().match(..)[1] 所做的是在调用它的函数中查找被调用的 showMe 并打印它及其值。

但这仍然非常有限,因为它只会触发 showMe(x) 的第一次调用。因此,如果有两次调用它,它将不起作用。

但是,玩这些神秘的东西很有趣。

【讨论】:

  • +1,恶心又迷人。
  • callernull 时,这将在Firefox 和Safari 上出错
  • @Jhawins 是真的。如果你能以某种方式获得对源字符串的引用,那么可能有一个 hacky 方法。
  • 自 ECMAScript (ES5) 以来已弃用 :(
【解决方案2】:

策略 1:

如果您可以在函数调用期间控制数据结构,那么您可以传递一个字典,它将名称编码为键,并​​与其值配对,注意隐身花括号:

var foo = "bar";
yourfunction({foo});

其中传递了一个如下所示的 javascript 字典:

{foo : "bar"}

yourfunction(被执行时,解压名称和值:

yourfunction = function(dict) { 
    var name = Object.keys(dict)[0];
    var value = dict[name];
    console.log(name);        //prints foo
    console.log(value);       //prints bar
}

策略 2:

如果您可以在全局范围内维护一个随用随用的名称-值对列表,那么反射和自省始终可用于设置和获取,例如:

var my_global_stack = [];

yourfunction = function() { 

    //Chomp the stack
    var dict = my_global_stack.pop();

    //The name is the key at index 0
    var name = Object.keys(dict)[0];

    //Fetch the value by keyname:
    var value = dict[name];

    console.log(name);       //prints foo
    console.log(value);      //prints bar
}


foo = "bar";
my_global_stack.push({foo});
yourfunction();

策略 3:

如果用户恶意输入不是问题,您可以使用eval( 重新发现给定变量名的值,例如:

yourfunction = function(somevariable) { 
    console.log(somevariable);          //prints foo
    console.log(eval(somevariable));    //prints bar
}

foo = "bar";
yourfunction("foo");

人们在这里说eval( 是邪恶的,因为如果恶意用户能够在任何时候覆盖内存中foo 的值,那么他们就可以进行操作系统命令注入并运行他们想要的任何命令。
http://cwe.mitre.org/top25/#Guidance

【讨论】:

  • 不需要自己的全局变量也不需要eval,怎么看我的回答。
【解决方案3】:
var x = "anything";

function showName(s) {
    alert(s + " = " + eval(s));
}

showName("x");

不推荐,但是有。

【讨论】:

  • 那么 x=1;显示名称(x)?
  • @BaroqueBobcat - 上面的函数对我来说很好用。如果您正在寻找边缘情况,可以轻松修改该函数,以根据类型或值以不同方式对数据进行字符串化。例如,空数组和空字符串都显示为空。您可能希望以不同方式处理此问题,或添加有关最佳猜测类型的附加信息。该示例的重点不是防弹,而是要证明一个函数可以从一个标量参数中获取参数名称和值。
【解决方案4】:

您可以创建一个哈希并将其传入:

var x = {a: 1,b:2}
function showVars(y) {
    for (var z in y) { alert(z + " is " + y[z]); }
}
showVars(x);

这不一定显示变量的名称,但它确实允许键值对,这可能更符合您的需要。

【讨论】:

  • 这永远不会打印 x = {a: 1,b:2},所以它不是 OP“需要”的
【解决方案5】:

这是我用来调试的。没有全局变量,没有 eval,没有 arguments.callee 或 arguments.caller:

var Helpers = (function () {
    // ECMAScript 5 strict mode
    'use strict';

    var Module = {};

    Module.debug = function () {
        var i;

        for (i = 0; i < arguments.length; i++) {
            console.log(arguments[i] + ':', this[arguments[i]]);
        }
    };

    Module.SomeObject = function SomeObject() {
        this.someMember = 1;
        this.anotherMember = 'Whatever';

        Module.debug.call(this, 'someMember', 'anotherMember');

        var privateMember = {
            name: 'Rip Steakface',
            battleCry: 'Raaaaaaaaahhhhhhhhhrrrrrrrrrg!'
        };

        Module.debug.call(privateMember, 'name', 'battleCry');
    };

    return Module;
}());

对于那些想知道为什么要这样做的人来说,这只是一种有效地记录多个变量及其名称的方法。

如果您希望能够记录嵌套成员,如Module.debug.call(obj, 'hair.fluffiness'),您可以像这样修改函数:

Module.debug = function () {
    var i, j, props, tmp;

    for (i = 0; i < arguments.length; i++) {
        tmp = this;
        props = arguments[i].split('.');

        for (j = 0; j < props.length; j++) {
            tmp = tmp[props[j]];
        }

        console.log(arguments[i] + ':', tmp);
    }
};

不幸的是,我找不到任何方法来有效地记录多个不是对象成员的私有变量,例如var roll = 3, value = 4; Module.debug.call(???);

【讨论】:

    【解决方案6】:

    不确定你是否可以直接从 JavaScript 中得到你想要的,因为变量名没有与它引用的值一起携带(把变量名想象成只有编译器知道的标识符;但是在运行时被丢弃)。

    但是,您可以做一些稍微不同的事情,这允许传递命名参数。创建一个匿名对象并将其传递给您的函数:

    function showNames(o)
    {
        for( var ix in o )
        {
           alert( ix + ":" + o[ix] );
        }
    }
    
    var z = { x : "Anything" }
    showNames( z );
    // or
    showNames( { a : "ay", b : "bee", c: "see" } )
    

    对于迭代对象属性,我倾向于使用函数式,例如:

    Array.iteri = function(o, f)
    {
        for(var i in o) { f(i, o[i]) }
    }
    
    function showNames(o)
    {
        Array.iteri( o, function(i,v)
        {
            alert( i + ": " + v )
        });
    }
    showNames( { a : "ay", b : "bee", c: "see" } )
    

    【讨论】:

    • @ally - 我说的是概念性的,但大多数 javascript 引擎确实(或可以)编译为中间代码以提高性能。 AFAIK,只有 Chrome 将 javascript 直接编译为汇编语言。
    【解决方案7】:

    下面的代码是你能做的最好的。不幸的是,函数中的局部变量是隐藏调用对象的属性,因此无法从像 window[a] 这样的 Javascript 中访问它们,其中 a 是窗口对象的属性。

    x = "this is x";
    var say = function(a) {
        document.write(a + " = " + window[a]);
    }
    say("x");
    
    var wrapper = function () {
        var x = "this is x";
        document.write(x + " = " + eval("x"))
    }
    wrapper()
    

    【讨论】:

      猜你喜欢
      • 2012-04-05
      • 1970-01-01
      • 1970-01-01
      • 2010-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多