Javascript utilise une variable comme nom d'objet

89

Je souhaite utiliser la valeur d'une variable pour accéder à un objet.

Disons que j'ai un objet nommé myobject.

Je veux remplir une variable avec ce nom et utiliser la variable pour accéder à l'objet.

Exemple:

var objname = 'myobject';
{objname}.value = 'value';
PeeHaa
la source

Réponses:

123

Global:

myObject = { value: 0 };
anObjectName = "myObject";
this[anObjectName].value++;

console.log(this[anObjectName]);

Mondial: v2

var anObjectName = "myObject";
this[anObjectName] = "myvalue"

console.log(myObject)

Local: v1

(function() {
    var scope = this;

    if (scope != arguments.callee) {
        arguments.callee.call(arguments.callee);
        return false;
    }

    scope.myObject = { value: 0 };
    scope.anObjectName = "myObject";
    scope[scope.anObjectName].value++;

    console.log(scope.myObject.value);
})();

Local: v2

(function() {  
    var scope = this;

    scope.myObject = { value: 0 };
    scope.anObjectName = "myObject";
    scope[scope.anObjectName].value++;

    console.log(scope.myObject.value);    
}).call({});
Shaz
la source
@Shaz - tous deux font référence à la même portée en fait ;-) (en supposant qu'ils sont exécutés dans un navigateur.) alert(this === window).
Sean Vieira
1
@PeeHaa - Le local exemple définit une variable sur l' windowobjet appelé objnamequi est ensuite référencé par this... vous pouvez remplacer windowpar thisdans le second exemple et tout fonctionne encore. :-)
Sean Vieira
1
@SeanVieira: jetez un œil à l'exemple mis à jour. Espérons que cela fonctionne correctement maintenant.
Shaz
1
@Shaz - arguments.calleeest obsolète, mais c'est néanmoins une implémentation très intelligente - et cela n'empiète pas sur la portée mondiale. +1
Sean Vieira
1
Cela ne pollue peut-être pas la portée globale, mais crée un objet qui est partagé par chaque appel de la fonction. Votre fonction est considérée objnamecomme une propriété de la fonction elle-même. Il peut échouer pour les fonctions récursives. Je ne sais pas comment cela peut être utilisé dans le monde réel.
Juan Mendes
25

Utilisez un crochet autour du nom de la variable.

var objname = 'myobject';
{[objname]}.value = 'value';
Vaishali Venkatesan
la source
6
C'est parfait et simple et devrait être la meilleure réponse.
Brad
4
Cela lève une exception: SyntaxError: expression attendue, obtenu '.'. Ça ne marche pas; pourquoi tant de votes positifs?
Lovro
8

Est-ce une variable globale? Si tel est le cas, ils font en fait partie de l' windowobjet, vous pouvez donc le faire window[objname].value.

Si c'est local à une fonction, je ne pense pas qu'il y ait un bon moyen de faire ce que vous voulez.

JW.
la source
7

L'objet existe dans une certaine portée, vous pouvez donc presque toujours accéder à la variable via cette syntaxe:

var objname = "myobject";
containing_scope_reference[objname].some_property = 'some value';

Le seul endroit où cela devient délicat est lorsque vous êtes dans une portée fermée et que vous souhaitez accéder à une variable locale de niveau supérieur. Lorsque vous avez quelque chose comme ça:

(function(){
    var some_variable = {value: 25};
    var x = "some_variable";
    console.log(this[x], window[x]); // Doesn't work
})();

Vous pouvez contourner cela en utilisant à la evalplace pour accéder à la chaîne de portée actuelle ... mais je ne le recommande pas à moins que vous n'ayez fait beaucoup de tests et que vous savez que c'est la meilleure façon de faire les choses.

(function(){
    var some_variable = {value: 25};
    var x = "some_variable";
    eval(x).value = 42;
    console.log(some_variable); // Works
})();

Votre meilleur pari est d'avoir une référence à un nom dans un objet qui va toujours être là (comme thisdans la portée globale ou une variable de premier niveau privée dans une portée locale) et d'y mettre tout le reste.

Donc:

var my_outer_variable = {};
var outer_pointer = 'my_outer_variable';
// Reach my_outer_variable with this[outer_pointer]
// or window[outer_pointer]

(function(){
    var my_inner_scope = {'my_inner_variable': {} };
    var inner_pointer = 'my_inner_variable';
    // Reach my_inner_variable by using
    // my_inner_scope[inner_pointer]
})();
Sean Vieira
la source
6

Vous pouvez utiliser eval:

eval(variablename + ".value = 'value'");
Midas
la source
N'est-ce pas evalconsidéré evil? Sinon, je pourrais l'utiliser. Parce que c'est un global en ce moment mais je voulais le déplacer dans une fonction pour nettoyer les choses.
PeeHaa
1
Lol. Si le nom de la variable provient d'une entrée utilisateur, assurez-vous de le valider, afin qu'il ne contienne aucun code JS evalpouvant s'exécuter.
Midas
1
C'est l'une des rares utilisations légitimes de eval, à mon avis. Nous devons cependant nous assurer que la variable est propre.
Levi Morrison
2
Oui, ce n'est pas vraiment un problème. Mais jetez un œil à la réponse de Shaz. Je pense que c'est une solution plus propre.
Midas
2
@PeeHaa: Si vous envisagez de le déplacer, pourquoi ne pas le déplacer dans une propriété d'un objet connu, afin de pouvoir faire quelque chose comme myVar[objname].value?
JW.
5

Vous ne pouvez pas faire cela en général, sauf au niveau de la fenêtre, où vous pouvez écrire window[objname].value = 'value';

Neil
la source
3

Je pense que la réponse de Shaz pour les variables locales est difficile à comprendre, bien qu'elle fonctionne pour les fonctions non récursives. Voici une autre façon dont je pense que c'est plus clair (mais c'est toujours son idée, exactement le même comportement). Il n'accède pas non plus aux variables locales de manière dynamique, mais uniquement à la propriété de la variable locale.

Essentiellement, il utilise une variable globale (attachée à l'objet de fonction)

// Here's  a version of it that is more straight forward.
function doIt() {
    doIt.objname = {};
    var someObject = "objname";
    doIt[someObject].value = "value";    
    console.log(doIt.objname);
})();

Ce qui revient essentiellement à créer un global pour stocker la variable, afin que vous puissiez y accéder en tant que propriété. Créer un global pour ce faire est un tel hack.

Voici un hack plus propre qui ne crée pas de variables globales, il utilise une variable locale à la place.

function doIt() {
  var scope = {
     MyProp: "Hello"
  };
  var name = "MyProp";
  console.log(scope[name]);
}

Voir Javascript: interpréter la chaîne comme référence d'objet?

Juan Mendes
la source
0

Lorsque vous utilisez la fenêtre [nom_obj], veuillez vous assurer que le nom_obj est une variable globale. Sinon, cela fonctionnera parfois et échouera parfois. window [nom_obj] .valeur.

lyon819
la source
0

Si l'objet est dans un espace de noms, c'est-à-dire. Company.Module.Components.Foovous pouvez utiliser cette fonction:

CoffeeScript:

objByName: (name, context = window) ->
    ns = name.split "."
    func = context
    for n, i in ns
        func = func[n]
    return func

Résultat Js:

objByName: function(name, context) {
  var func, i, n, ns, _i, _len;
  if (context == null) {
    context = window;
  }
  ns = name.split(".");
  func = context;
  for (i = _i = 0, _len = ns.length; _i < _len; i = ++_i) {
    n = ns[i];
    func = func[n];
  }
  return func;
}

Ensuite, vous pouvez créer un nouvel objet ou faire n'importe quoi. Notez les parenthèses.

var o = new (objByName('Company.Module.Components.Foo'))
objByName('some.deeply.nested.object').value

Cette idée est empruntée à une question similaire: comment exécuter une fonction JavaScript quand j'ai son nom sous forme de chaîne

Communauté
la source
0

L'un des défis que j'ai eu avec les réponses est qu'il supposait que l'objet était un seul niveau. Par exemple,

const testObj = { testKey: 'testValue' }
const refString = 'testKey';
const refObj = testObj[refString];

fonctionne bien, mais

const testObj = { testKey:
                  { level2Key: 'level2Value' }
                }
const refString = 'testKey.level2Key';
const refObj = testObj[refString];

ne marche pas.

Ce que j'ai fini par faire, c'est créer une fonction pour accéder aux objets à plusieurs niveaux:

objVar(str) {
    let obj = this;
    const parts = str.split('.');
    for (let p of parts) {
        obj = obj[p];
    }
    return obj;
}

Dans le deuxième scénario, je peux alors passer la chaîne à cette fonction pour récupérer l'objet que je recherche:

const testObj = { testKey:
                  { level2Key: 'level2Value' }
                }
const refString = 'testObj.testKey.level2Key';
const refObj = objVar[refString];
Mitch Parker
la source
0

Vous pouvez définir une propriété d'objets de cette façon:

var obj = {};
obj.whateverVarName = 'yourVal';
console.log(obj);

ThisisFish
la source
0

Si vous connaissez déjà la liste des noms de variables possibles, essayez de créer un nouvel objet (iconObj) dont le nom des propriétés est le même que les noms d'objet, ici dans l'exemple ci-dessous, la variable iconLib contiendra deux valeurs de chaîne, soit 'ZondIcons' ou 'MaterialIcons' . propertyName est la propriété de l'objet ZondIcons ou MaterialsIcon.

   const iconObj = {
    ZondIcons,
    MaterialIcons,
  }
  const objValue = iconObj[iconLib][propertyName]
Sumer
la source
0
let players = [];
players[something] = {};
players[something].somethingElse = 'test';
console.log(players); 

-> [quelque chose: {somethingElse: 'test'}];

part1cle
la source
-1
var micro=[{'test':'hello'}];

var device = 'test';

console.log(micro[device]);
Alfonsoolavarria
la source