Accéder dynamiquement à la propriété d'objet à l'aide d'une variable


722

J'essaie d'accéder à une propriété d'un objet en utilisant un nom dynamique. Est-ce possible?

const something = { bar: "Foobar!" };
const foo = 'bar';
something.foo; // The idea is to access something.bar, getting "Foobar!"

Réponses:


960

Il existe deux façons d'accéder aux propriétés d'un objet:

  • Notation par points: something.bar
  • Notation entre parenthèses: something['bar']

La valeur entre crochets peut être n'importe quelle expression. Par conséquent, si le nom de la propriété est stocké dans une variable, vous devez utiliser la notation entre crochets:

var foo = 'bar';
something[foo];
// both x = something[foo] and something[foo] = x work as expected

34
attention à cela: les compilateurs javascript vont faire une erreur ici car ils ne renomment pas les chaînes mais ils renomment les propriétés des objets
chacham15

6
Quelques informations supplémentaires sur les raisons pour lesquelles cela est possible: les objets JS sont des tableaux associatifs, c'est pourquoi. Lectures complémentaires: quirksmode.org/js/associative.html stackoverflow.com/questions/14031368/…
Sudhanshu Mishra

@dotnetguy Non, ils ne le sont pas. Les tableaux sont des objets qui héritent du prototype d'objet JS simple et vous pouvez donc ajouter des propriétés un go-go comme n'importe quel objet ordinaire. Le comportement «associatif» ressemble plus à un objet qu'à un tableau. Vous ne pouvez pas itérer la version «associative» par un simple index afin qu'elle n'affiche pas un comportement de type tableau. Vous pouvez définir votre tableau «associatif» comme {} ou [] et le traiter de la même façon dans les deux cas en ce qui concerne l'accès aléatoire aux propriétés.
Vanquished Wombat

3
@VanquishedWombat Vous ne savez pas à quoi correspond votre objection? Je n'ai pas dit que les objets JS sont des tableaux?
Sudhanshu Mishra

1
Cette réponse est bien trop votée, elle ne clarifie rien ...
Aft3rL1f3

104

Voici ma solution:

function resolve(path, obj) {
    return path.split('.').reduce(function(prev, curr) {
        return prev ? prev[curr] : null
    }, obj || self)
}

Exemples d'utilisation:

resolve("document.body.style.width")
// or
resolve("style.width", document.body)
// or even use array indexes
// (someObject has been defined in the question)
resolve("part.0.size", someObject) 
// returns null when intermediate properties are not defined:
resolve('properties.that.do.not.exist', {hello:'world'})

Excellente réponse, voir aussi: stackoverflow.com/questions/37510640/…
Julian Knight

2
Vous m'avez inspiré pour créer une version améliorée qui permet la notation des parenthèses et les noms de propriété avec des espaces ainsi que la validation des entrées: it.knightnet.org.uk/kb/node-js/get-properties
Julian Knight

J'adore cette solution. Cependant, j'essaie de modifier les valeurs de l'objet d'origine, il semble que votre fonction renvoie une sous-copie de l'objet. Est-il possible de le changer pour que la modification de l'objet retourné modifie l'original?
Eagle1

40

En javascript, nous pouvons accéder avec:

  • notation par points - foo.bar
  • crochets - foo[someVar]oufoo["string"]

Mais seul le deuxième cas permet d'accéder dynamiquement aux propriétés:

var foo = { pName1 : 1, pName2 : [1, {foo : bar }, 3] , ...}

var name = "pName"
var num  = 1;

foo[name + num]; // 1

// -- 

var a = 2;
var b = 1;
var c = "foo";

foo[name + a][b][c]; // bar

4
Je regarde 2 000 lignes d'instructions if parce que le dev précédent n'utilisait pas de crochets et les propriétés d'objet accessibles statiquement par notation par points. C'est pour une application de processus d'approbation qui a 7 approbateurs différents et les étapes sont les mêmes. / rip
Tchad

26

Voici un exemple ES6 de la façon dont vous pouvez accéder à la propriété d'un objet à l'aide d'un nom de propriété qui a été généré dynamiquement en concaténant deux chaînes.

var suffix = " name";

var person = {
    ["first" + suffix]: "Nicholas",
    ["last" + suffix]: "Zakas"
};

console.log(person["first name"]);      // "Nicholas"
console.log(person["last name"]);       // "Zakas"

C'est ce qu'on appelle les noms de propriété calculés


16

Vous pouvez y parvenir de différentes manières.

let foo = {
    bar: 'Hello World'
};

foo.bar;
foo['bar'];

La notation entre crochets est particulièrement puissante car elle vous permet d'accéder à une propriété basée sur une variable:

let foo = {
    bar: 'Hello World'
};

let prop = 'bar';

foo[prop];

Cela peut être étendu au bouclage sur chaque propriété d'un objet. Cela peut sembler redondant en raison de nouvelles constructions JavaScript telles que pour ... de ..., mais aide à illustrer un cas d'utilisation:

let foo = {
    bar: 'Hello World',
    baz: 'How are you doing?',
    last: 'Quite alright'
};

for (let prop in foo.getOwnPropertyNames()) {
    console.log(foo[prop]);
}

La notation par points et par crochets fonctionne également comme prévu pour les objets imbriqués:

let foo = {
    bar: {
        baz: 'Hello World'
    }
};

foo.bar.baz;
foo['bar']['baz'];
foo.bar['baz'];
foo['bar'].baz;

Déstructuration d'objets

Nous pourrions également considérer la déstructuration d'objet comme un moyen d'accéder à une propriété dans un objet, mais comme suit:

let foo = {
    bar: 'Hello World',
    baz: 'How are you doing?',
    last: 'Quite alright'
};

let prop = 'last';
let { bar, baz, [prop]: customName } = foo;

// bar = 'Hello World'
// baz = 'How are you doing?'
// customName = 'Quite alright'

11

Vous pouvez le faire comme ceci en utilisant Lodash get

_.get(object, 'a[0].b.c');

Il existe de nombreuses situations, telles que les recherches d'objets imbriquées profondes, où c'est la seule option.
Jonathan Kempf

8

MISE À JOUR

J'ai pris en considération les commentaires ci-dessous et je suis d'accord. Eval est à éviter.

L'accès aux propriétés de la racine dans l'objet est facile à réaliser obj[variable], mais obtenir des emboîtements complique la chose. Ne pas écrire de code déjà écrit que je suggère d'utiliser lodash.get.

Exemple

// Accessing root property
var rootProp = 'rootPropert';
_.get(object, rootProp, defaultValue);

// Accessing nested property
var listOfNestedProperties = [var1, var2];
_.get(object, listOfNestedProperties);

Lodash get peut être utilisé de différentes manières, voici le lien vers la documentation lodash.get


4
Il est préférable d'éviter d'utiliser evalautant que possible. stackoverflow.com/questions/86513/…
Luke

8
Utiliser evalpour quelque chose d'aussi banal que d'accéder à des propriétés est tout simplement exagéré et à peine recommandé en aucune circonstance. Quel est le "problème"? obj['nested']['test']fonctionne très bien et ne vous oblige pas à incorporer du code dans des chaînes.
Kyll

3
eval est trois fois plus lent ou plus, je ne recommanderais pas cela aux débutants car cela pourrait leur apprendre de mauvaises habitudes. J'utilise obj['nested']['value']- rappelez-vous les enfants, eval est mauvais!
jaggedsoft

1
@Luke Il est maintenant le seul à vouloir amener Lodash _.getà la table. Je pense que cette réponse mérite maintenant des votes positifs plutôt que des votes négatifs. C'est peut-être exagéré, mais il est bon de savoir qu'il existe.
Emile Bergeron

1
Merci d'avoir présenté lodash pour cela. Je suis venu ici par Google à la recherche d'une méthode pour définir une valeur profonde dans un objet, et j'ai utilisé leur méthode _.set (qui est identique à ci-dessus mais avec l'argument supplémentaire pour la valeur à définir).
TPHughes

5

Chaque fois que vous devez accéder dynamiquement à une propriété, vous devez utiliser un crochet pour accéder à la propriété et non à "." opérateur
Syntaxe: objet [propriété]

const something = { bar: "Foobar!" };
const foo = 'bar';
// something.foo; -- not correct way at it is expecting foo as proprty in  something={ foo: "value"};
// correct way is  something[foo]
alert( something[foo])


4

Je suis tombé sur un cas où je pensais que je voulais passer l '"adresse" d'une propriété d'objet en tant que données à une autre fonction et remplir l'objet (avec AJAX), faire une recherche dans le tableau d'adresses et afficher dans cette autre fonction. Je ne pouvais pas utiliser la notation par points sans faire des acrobaties de chaînes, j'ai donc pensé qu'un tableau pourrait être agréable à passer à la place. J'ai fini par faire quelque chose de différent de toute façon, mais je semblais lié à ce post.

Voici un exemple d'un objet de fichier de langue comme celui dont je voulais des données:

const locs = {
  "audioPlayer": {
    "controls": {
      "start": "start",
      "stop": "stop"
    },
    "heading": "Use controls to start and stop audio."
  }
}

Je voulais pouvoir passer un tableau tel que: ["audioPlayer", "contrôles", "stop"] pour accéder au texte de la langue, "stop" dans ce cas.

J'ai créé cette petite fonction qui recherche le paramètre d'adresse (le moins) "le moins spécifique" et réaffecte l'objet renvoyé à lui-même. Il est ensuite prêt à rechercher le paramètre d'adresse suivant le plus spécifique, s'il en existe un.

function getText(selectionArray, obj) {
  selectionArray.forEach(key => {
    obj = obj[key];
  });
  return obj;
}

usage:

/* returns 'stop' */
console.log(getText(["audioPlayer", "controls", "stop"], locs)); 

/* returns 'use controls to start and stop audio.' */
console.log(getText(["audioPlayer", "heading"], locs)); 

2

Cela devient intéressant lorsque vous devez également passer des paramètres à cette fonction.

Code jsfiddle

var obj = {method:function(p1,p2,p3){console.log("method:",arguments)}}

var str = "method('p1', 'p2', 'p3');"

var match = str.match(/^\s*(\S+)\((.*)\);\s*$/);

var func = match[1]
var parameters = match[2].split(',');
for(var i = 0; i < parameters.length; ++i) {
  // clean up param begninning
    parameters[i] = parameters[i].replace(/^\s*['"]?/,'');
  // clean up param end
  parameters[i] = parameters[i].replace(/['"]?\s*$/,'');
}

obj[func](parameters); // sends parameters as array
obj[func].apply(this, parameters); // sends parameters as individual values

1

ES5 // Vérifier les variables profondément imbriquées

Ce simple morceau de code peut vérifier l'existence de variables / valeurs profondément imbriquées sans avoir à vérifier chaque variable en cours de route ...

var getValue = function( s, context ){
    return Function.call( context || null, 'return ' + s )();
}

Ex. - un tableau d'objets profondément imbriqués:

a = [ 
    {
      b : [
          {
             a : 1,
             b : [
                 {
                    c : 1,
                    d : 2   // we want to check for this
                 }
             ]
           }
      ]
    } 
]

Au lieu de :

if(a && a[0] && a[0].b && a[0].b[0] && a[0].b[0].b && a[0].b[0].b[0] && a[0].b[0].b[0].d && a[0].b[0].b[0].d == 2 )  // true

Nous pouvons maintenant:

if( getValue('a[0].b[0].b[0].d') == 2 ) // true

À votre santé!


1
Si la solution consiste à utiliser eval, vous venez de créer un million d'autres problèmes.
Rodrigo Leite

@RodrigoLeite ok, donc ce ne serait pas un problème d'en donner au moins un ...


1
@RodrigoLeite Je l'ai lu et mis à jour la solution à utiliser à la Functionplace

0

J'ai posé une question qui a un peu dupliqué sur ce sujet il y a quelque temps, et après des recherches excessives, et voyant beaucoup d'informations manquantes qui devraient être ici, je pense que j'ai quelque chose de précieux à ajouter à cet ancien article.

  • Tout d'abord, je veux dire qu'il existe plusieurs façons d'obtenir la valeur d'une propriété et de la stocker dans une variable dynamique. La première façon la plus populaire et la plus simple à mon humble avis serait:
let properyValue = element.style['enter-a-property'];

Cependant, je vais rarement dans cette voie car cela ne fonctionne pas sur les valeurs de propriété attribuées via les feuilles de style. Pour vous donner un exemple, je vais démontrer avec un peu de pseudo-code.

 let elem = document.getElementById('someDiv');
 let cssProp = elem.style['width'];

En utilisant l'exemple de code ci-dessus; si la propriété width de l'élément div qui était stocké dans la variable 'elem' était stylisée dans une feuille de style CSS, et non stylisée à l'intérieur de sa balise HTML, vous obtiendrez sans aucun doute une valeur de retour indéfinie stockée à l'intérieur de la variable cssProp. La valeur indéfinie se produit parce que pour obtenir la valeur correcte, le code écrit à l'intérieur d'une feuille de style CSS doit être calculé afin d'obtenir la valeur, par conséquent; vous devez utiliser une méthode qui calculera la valeur de la propriété dont la valeur se trouve dans la feuille de style.

  • Désormais la méthode getComputedStyle ()!
function getCssProp(){
  let ele = document.getElementById("test");
  let cssProp = window.getComputedStyle(ele,null).getPropertyValue("width");
}

W3Schools getComputedValue Doc Cela donne un bon exemple et vous permet de jouer avec, cependant, ce lien Le document Mozilla CSS getComputedValue parle de la fonction getComputedValue en détail, et devrait être lu par tout développeur en herbe qui n'est pas totalement clair sur ce sujet.

  • En remarque, la méthode getComputedValue obtient uniquement, elle ne définit pas. C'est évidemment un inconvénient majeur, mais il existe une méthode qui provient des feuilles de style CSS, ainsi que des valeurs définies, bien que ce ne soit pas du Javascript standard. La méthode JQuery ...
$(selector).css(property,value)

... obtient, et se couche. C'est ce que j'utilise, le seul inconvénient est que vous connaissez JQuery, mais c'est honnêtement l'une des très bonnes raisons pour que chaque développeur Javascript apprenne JQuery, cela rend la vie facile et propose des méthodes, comme celle-ci, qui n'est pas disponible avec Javascript standard. J'espère que cela aide quelqu'un !!!




-4
const something = { bar: "Foobar!" };
const foo = 'bar';

something[\`${foo}\`];

7
Pourquoi diable feriez-vous cela? Votre fooest déjà une chaîne, `${foo}`c'est exactement la même chose que foo. (En outre, votre code semble avoir des barres obliques inverses supplémentaires qui ne lui appartiennent pas. Mais cela serait toujours inutile même si vous
corrigiez
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.