views:

1735

answers:

5

What I want to do is get the NAME of a variable passed to a function and the VALUE of that variable and only have to pass in one variable to the function. So:

var x = "anything";

function showName() {

}

showName(x);

or

showName("x");

Which will return: "x = anything".

Right now, I have to do:

showName("x", x);

in order to get the name and value of the variable I am passing in. Note that I am not interested in the name of argument in the prototype of showName, but the name of the variable in the calling function. Also, the variable may be local, so I can't use the window object to find the variable.

+2  A: 
var x = "anything";

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

showName("x");

Not recommended, but there it is.

RedFilter
What about x=1; showName(x) ?
BaroqueBobcat
@BaroqueBobcat - the above function works fine for me. If you are looking for edge cases, the function can easily be modified to stringify the data in different ways based on type or value. E.g., an empty array and empty string both display as empty. You may want to handle this differently, or add additional info about a best guess as to type. The point of the example is not to be bulletproof but to demonstrate that a function can obtain both parameter name and value from one scalar parameter.
RedFilter
A: 

The short answer is that you can't.

The longer, evil answer is that you sort of can with some real nastiness. And it only works when called from another function.

there are two interesting attributes available to you that could help

arguments.callee caller

for fn to do something like this:

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

What arguments.callee.caller.toString().match(..)[1] does is look for the showMe being called in the function calling it and prints it and its value.

But this is still pretty limited because it will only hit the first call of showMe(x). So if there is two calls to it, it won't work.

But, it was fun to play with these arcane things.

BaroqueBobcat
A: 

Not sure you can directly get what you want from JavaScript, since the variable name is not carried around with the value it references (think of variable names as identifiers only the compiler knows about; but which get thrown away at runtime).

You can, however, do something slightly different which allows for passing around named arguments. Create an anonymous object and pass that to your function:

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" } )

For iterating object properties, I tend to prefer a functional-style, as in:

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" } )
James Hugard
+1  A: 

You could create a hash and pass that in:

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

This doesn't necessarily show the name of the variable, but it does allow for key-value pairs, which may be more to the point of what you need.

DGM
A: 

I already knew that I could pass in a object:

{a:"this is a"}

where a is name of the variable but I really want to just pass in a variable or the name of a variable (a or "a") and let the function somehow find the name of the variable and its value.

The reason I want to do this somewhat weird thing is that I am writing a debug print routine. If I call it like this:

var x = "some string";
say(x);

or

say("x");

I want it to print something like:

X (string) = some string

I can pretty reliably find the type of a variable passed, and so I know how to print it, but I really want to try to avoid the redunancy of having to call it like this:

say("x", x);

which is what I have to do now.

What seems to almost work is OrbMan's answer. Sure, eval is evil, but I think it's OK here because it's only for a debug utility and won't be in the published code. I've made a little test routine of my own using that solution:

var x = "this is x";

function say(a) {
   alert(a + " = " + eval(a));

}

say("x");

and it works but ONLY IF X IS GLOBAL. This doesn't work:

function wrapper() {

   var x = "this is x";
   say("x");

}

So, this solution is close, but since I use almost no Global variables, this isn't going to work. Darn, it is soooo close. What I think I need is "call by name" instead of "by value" or "by reference". And I need a function that will work whether it is being called from another function or not.

Since I've put in a good many hours on this myself, asking the question here was an act of desperation, I've got to conclude that there really isn't any way to do this. Shucks.

To everyone who responded, thanks for all your help.