web-dev-qa-db-fra.com

JavaScript: obtenir la valeur de l'argument et le nom de la variable transmise

Ce que je veux faire, c'est faire passer le NOM d'une variable à une fonction et la VALEUR de cette variable, et je n'ai qu'à passer une variable à la fonction. Donc:

var x = "anything";

function showName() {

}

showName(x);

ou

showName("x");

Qui retournera: "x = n'importe quoi".

À l'heure actuelle, je dois spécifier la variable deux fois:

showName("x", x);

Afin d'obtenir le nom et la valeur de la variable que je transmets.

Notez que je ne m'intéresse pas au nom de l'argument dans le prototype de showName, mais au nom de la variable dans la fonction appelante. De plus, la variable transmise peut être locale, donc je ne peux pas utiliser l'objet window pour trouver la variable.

46
Peleg

La réponse courte est que vous ne pouvez pas.

La réponse plus longue et mauvaise est que vous pouvez en quelque sorte avec une réelle méchanceté. Et cela ne fonctionne que lorsqu'il est appelé à partir d'une autre fonction.

il y a deux attributs intéressants à votre disposition qui pourraient vous aider

appelant arguments.callee

pour que fn fasse quelque chose comme ceci:

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

Ce que fait arguments.callee.caller.toString (). Match (..) [1], c'est que le showMe est appelé dans la fonction qui l'appelle et l'affiche ainsi que sa valeur.

Mais cela reste assez limité car il ne frappera que le premier appel de showMe (x). Donc, s'il y a deux appels, cela ne fonctionnera pas.

Mais c'était amusant de jouer avec ces choses mystérieuses.

59
BaroqueBobcat
var x = "anything";

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

showName("x");

Pas recommandé, mais ça y est.

8
RedFilter

Stratégie 1:

Si vous pouvez contrôler la structure des données pendant l'appel de la fonction, vous pouvez passer un dictionnaire qui encodera le nom sous forme de clé, associé à sa valeur, notez les accolades furtives:

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

Qui passe un dictionnaire javascript qui ressemble à ceci:

{foo : "bar"}

Quand yourfunction( est exécuté, décompressez soigneusement le nom et la valeur:

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

Stratégie 2:

Si vous pouvez conserver une liste au fur et à mesure des paires nom-valeur dans une portée globale, la réflexion et l'introspection sont toujours disponibles pour définir et obtenir, par exemple:

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();

Stratégie 3:

Si l'entrée hostile à l'utilisateur n'est pas un problème, vous pouvez utiliser eval( pour redécouvrir la valeur en fonction du nom de variable, par exemple:

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

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

Les gens disent eval( est mauvais ici, car si un utilisateur hostile est capable d'écraser la valeur de foo en mémoire à tout moment, il peut alors faire l'injection de commande du système d'exploitation et exécuter la commande de son choix.
http://cwe.mitre.org/top25/#Guidance

6
Peleg

Vous pouvez créer un hachage et le transmettre dans:

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

Cela ne montre pas nécessairement le nom de la variable, mais cela permet des paires clé-valeur, ce qui peut être plus au point de ce dont vous avez besoin.

2
DGM

C'est ce que j'utilise pour le débogage. Aucune variable globale, aucun eval, aucun argument.callee ou 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;
}());

Pour ceux qui se demandent pourquoi vous voudriez faire cela, c'est juste un moyen d'enregistrer efficacement plusieurs variables avec leurs noms.

Si vous voulez pouvoir journaliser les membres imbriqués, comme dans Module.debug.call(obj, 'hair.fluffiness'), vous pouvez modifier la fonction comme suit:

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

Malheureusement, je ne trouve aucun moyen de consigner efficacement plusieurs variables privées qui ne sont pas membres d'un objet, par exemple var roll = 3, value = 4; Module.debug.call(???);

2
David Kennedy

Pas sûr que vous puissiez directement obtenir ce que vous voulez de JavaScript, car le nom de la variable n'est pas transporté avec la valeur qu'il référence (pensez aux noms de variables comme des identificateurs que seul le compilateur connaît; mais qui sont jetés lors de l'exécution).

Vous pouvez, cependant, faites quelque chose légèrement différent qui permet de passer des arguments nommés. Créez un objet anonyme et transmettez-le à votre fonction:

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

Pour itérer les propriétés des objets, j'ai tendance à préférer un style fonctionnel, comme dans:

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

Le code ci-dessous est le meilleur que vous puissiez faire. Malheureusement, les variables locales dans une fonction sont des propriétés de l'objet d'appel caché, elles ne sont donc pas accessibles à partir de Javascript comme window [a] où a est une propriété de l'objet window.

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()
1
Anon