Comment utiliser une variable pour une clé dans un littéral objet JavaScript?


407

Pourquoi fonctionne ce qui suit?

<something>.stop().animate(
    { 'top' : 10 }, 10
);

Alors que cela ne fonctionne pas:

var thetop = 'top';
<something>.stop().animate(
    { thetop : 10 }, 10
);

Pour le rendre encore plus clair: Pour le moment, je ne suis pas en mesure de transmettre une propriété CSS à la fonction d'animation en tant que variable.



Réponses:


668

{ thetop : 10 }est un littéral d'objet valide. Le code créera un objet avec une propriété nommée thetopqui a une valeur de 10. Les deux éléments suivants sont identiques:

obj = { thetop : 10 };
obj = { "thetop" : 10 };

Dans ES5 et versions antérieures, vous ne pouvez pas utiliser une variable comme nom de propriété dans un littéral d'objet. Votre seule option est de procéder comme suit:

var thetop = "top";

// create the object literal
var aniArgs = {};

// Assign the variable property name with a value of 10
aniArgs[thetop] = 10; 

// Pass the resulting object to the animate method
<something>.stop().animate(
    aniArgs, 10  
);  

ES6 définit ComputedPropertyName dans le cadre de la grammaire des littéraux d'objet, ce qui vous permet d'écrire le code comme ceci:

var thetop = "top",
    obj = { [thetop]: 10 };

console.log(obj.top); // -> 10

Vous pouvez utiliser cette nouvelle syntaxe dans les dernières versions de chaque navigateur grand public.


Je comprends! Je vous remercie! Cela ne devrait-il pas fonctionner avec eval? Je veux dire que cela ne fonctionne pas dans mon exemple pour le moment, mais je pense que cela devrait ... :-)
speendo

3
@Marcel: eval()ne fonctionnerait pas dans un littéral d'objet pour les noms de propriétés dynamiques, vous obtiendriez simplement une erreur. Non seulement cela, mais eval()ne devrait vraiment pas être utilisé pour de telles choses. Il y a un excellent article sur l'utilisation correcte et incorrecte de eval: blogs.msdn.com/ericlippert/archive/2003/11/01/53329.aspx
Andy E

2
@AndyE envisage de mettre à jour les "versions récentes" et "IE IE TP" en cours avec un temps plus spécifique comme "Versions postérieures à XXX" ou "après 2014-mm" (je changerais moi-même, mais je ne sais pas quelles bonnes valeurs serait
Alexei Levenkov

1
pour ES6, existe-t-il un moyen de supprimer la propriété si la clé est nulle / non définie? Par exemple, dans {[key] : "value"}, si la clé était nulle, cela donnerait { null: "value"}, alors que j'aimerais que le résultat soit{}
wasabigeek

merveilleuse solution, mais pourquoi vous en savez tant, même la lecture de toutes les spécifications n'a pas pu obtenir le point :(
hugemeow

126

Avec ECMAScript 2015, vous pouvez maintenant le faire directement dans la déclaration d'objet avec la notation des crochets: 

var obj = {
  [key]: value
}

keypeut être n'importe quelle sorte d'expression (par exemple une variable) renvoyant une valeur.

Voici donc à quoi ressemblerait votre code:

<something>.stop().animate({
  [thetop]: 10
}, 10)

thetopsera évalué avant d'être utilisé comme clé.


17

Citation ES5 qui dit que cela ne devrait pas fonctionner

Remarque: les règles ont changé pour ES6: https://stackoverflow.com/a/2274327/895245

Spec: http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.5

Nom de la propriété :

  • IdentifierName
  • StringLiteral
  • NumericLiteral

[...]

Le PropertyName de production: IdentifierName est évalué comme suit:

  1. Renvoie la valeur String contenant la même séquence de caractères que IdentifierName.

La propriété PropertyName: StringLiteral de production est évaluée comme suit:

  1. Renvoie la SV [valeur de chaîne] de StringLiteral.

La propriété PropertyName: NumericLiteral est évaluée comme suit:

  1. Soit nbr le résultat de la formation de la valeur de NumericLiteral.
  2. Retournez à Strings (nbr).

Cela signifie que:

  • { theTop : 10 } est exactement le même que { 'theTop' : 10 }

    Le PropertyName theTopest un IdentifierName, il est donc converti en la 'theTop'valeur de chaîne, qui est la valeur de chaîne de 'theTop'.

  • Il n'est pas possible d'écrire des initialiseurs d'objets (littéraux) avec des clés variables.

    Les trois seules options sont IdentifierName(se développe en littéral de chaîne) StringLiteralet NumericLiteral(se développe également en chaîne).


3
Downvoters: J'ai été le premier à citer une norme sur cette question. La citation ES6 sur la réponse du haut a été modifiée après que j'ai répondu, et cette norme n'était pas encore acceptée à l'époque. Si vous savez pourquoi je reçois des votes négatifs, expliquez-moi, je veux juste apprendre. Je pourrais aussi bien obtenir l'insigne de pression des pairs ...
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Je suppose que le downvote était principalement dû au fait que votre réponse n'offre pas de solution et n'est "pas utile" à cet égard. Voter pour la pression des pairs :-)
Bergi

3
@Bergi merci d'avoir eu le courage! :-) Mais je pense avoir répondu directement à la question : Q: "Pourquoi ça marche?". R: parce que ES5 le dit. "Que faire à ce sujet?" est implicite. Avez-vous dévalorisé la question principale pour avoir dit "C'est impossible" sans un devis standard avant que quelqu'un n'édite dans la solution ES6?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Ah, c'est vrai. Je cite généralement les questions spécifiques dans une citation pour être clair lorsque je réponds directement. Citer la norme peut améliorer encore une bonne réponse, mais actuellement votre message ne répond même pas à la question imo. Dire ce qui peut faire une clé dans ES5 n'implique pas comment ils fonctionnent. C'est sûrement thetopun IdentifierName, alors pourquoi ça ne marche pas ? Cette question est toujours ouverte.
Bergi

1
@Bergi merci encore de m'expliquer! Je l'ai mis à jour pour le rendre plus explicite. Je ne l'avais pas fait auparavant parce que je pensais que c'était évident, parce que nous pouvons écrire {a:1}.a, donc aclairement ne pas étendre la valeur de la variable dans le cas de l'identifiant. Mais oui, expliquer davantage est une amélioration dans ce cas.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

5

J'ai utilisé ce qui suit pour ajouter une propriété avec un nom "dynamique" à un objet:

var key = 'top';
$('#myElement').animate(
   (function(o) { o[key]=10; return o;})({left: 20, width: 100}),
   10
);

key est le nom de la nouvelle propriété.

L'objet des propriétés transmises animatesera{left: 20, width: 100, top: 10}

Ceci utilise simplement la []notation requise comme recommandé par les autres réponses, mais avec moins de lignes de code!


5

L'ajout d'un crochet carré autour de la variable me convient. Essaye ça

var thetop = 'top';
<something>.stop().animate(
    { [thetop] : 10 }, 10
);

Cela ne fonctionnera pas dans les anciennes versions d'EcmaScript, mais de nos jours c'est une approche très propre.
Oliver

3

Je n'ai pas pu trouver d' exemple simple sur les différences entre ES6 et ES5, alors j'en ai fait un. Les deux exemples de code créent exactement le même objet. Mais l'exemple ES5 fonctionne également dans les navigateurs plus anciens (comme IE11), contrairement à l'exemple ES6.

ES6

var matrix = {};
var a = 'one';
var b = 'two';
var c = 'three';
var d = 'four';

matrix[a] = {[b]: {[c]: d}};

ES5

var matrix = {};
var a = 'one';
var b = 'two';
var c = 'three';
var d = 'four';

function addObj(obj, key, value) {
  obj[key] = value;
  return obj;
}

matrix[a] = addObj({}, b, addObj({}, c, d));

2

Mise à jour 2020 / exemple ...

Un exemple plus complexe, en utilisant des crochets et des littéraux ... quelque chose que vous pourriez avoir à faire par exemple avec vue / axios. Enveloppez le littéral dans les crochets, donc

[`...`]

{
    [`filter[${query.key}]`]: query.value,  // 'filter[foo]' : 'bar'
}

1

Code donné:

var thetop = 'top';
<something>.stop().animate(
    { thetop : 10 }, 10
);

Traduction:

var thetop = 'top';
var config = { thetop : 10 }; // config.thetop = 10
<something>.stop().animate(config, 10);

Comme vous pouvez le voir, la { thetop : 10 }déclaration n'utilise pas la variable thetop. Au lieu de cela, il crée un objet avec une clé nommée thetop. Si vous voulez que la clé soit la valeur de la variable thetop, vous devrez utiliser des crochets autour thetop:

var thetop = 'top';
var config = { [thetop] : 10 }; // config.top = 10
<something>.stop().animate(config, 10);

La syntaxe entre crochets a été introduite avec ES6. Dans les versions antérieures de JavaScript, vous devez effectuer les opérations suivantes:

var thetop = 'top';
var config = (
  obj = {},
  obj['' + thetop] = 10,
  obj
); // config.top = 10
<something>.stop().animate(config, 10);

1

Je ne peux pas croire que cela n'ait pas encore été posté: utilisez simplement la notation fléchée avec une évaluation anonyme!

Complètement non invasif, ne dérange pas l'espace de noms et ne prend qu'une seule ligne:

myNewObj = ((k,v)=>{o={};o[k]=v;return o;})(myKey,myValue);

démo:

utile dans les environnements qui ne prennent pas encore en charge la nouvelle {[myKey]: myValue}syntaxe, comme - apparemment; Je viens de le vérifier sur ma console Web Developer - Firefox 72.0.1, publiée le 2020-01-08.

(Je suis sûr que vous pourriez potentiellement créer des solutions plus puissantes / extensibles ou tout ce qui implique une utilisation intelligente de reduce, mais à ce stade, vous seriez probablement mieux servi en décomposant simplement la création d'objet dans sa propre fonction au lieu de la bloquer compulsivement. tous en ligne)


non pas que cela soit important depuis que OP l'a demandé il y a dix ans, mais pour être complet et pour montrer comment c'est exactement la réponse à la question telle qu'elle est énoncée, je vais montrer cela dans le contexte d'origine:

var thetop = 'top';
<something>.stop().animate(
    ((k,v)=>{o={};o[k]=v;return o;})(thetop,10), 10
);

0

De cette façon, vous pouvez également obtenir la sortie souhaitée

var jsonobj={};
var count=0;
$(document).on('click','#btnadd', function() {
    jsonobj[count]=new Array({ "1"  : $("#txtone").val()},{ "2"  : $("#txttwo").val()});
    count++;
    console.clear();
    console.log(jsonobj);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span>value 1</span><input id="txtone" type="text"/>
<span>value 2</span><input id="txttwo" type="text"/>
<button id="btnadd">Add</button>


0

L'implémentation d'ES5 pour attribuer des clés est ci-dessous:

var obj = Object.create(null),
    objArgs = (
      (objArgs = {}),
      (objArgs.someKey = {
        value: 'someValue'
      }), objArgs);

Object.defineProperties(obj, objArgs);

J'ai joint un extrait que j'ai utilisé pour convertir en objet nu.

var obj = {
  'key1': 'value1',
  'key2': 'value2',
  'key3': [
    'value3',
    'value4',
  ],
  'key4': {
    'key5': 'value5'
  }
}

var bareObj = function(obj) {

  var objArgs,
    bareObj = Object.create(null);

  Object.entries(obj).forEach(function([key, value]) {

    var objArgs = (
      (objArgs = {}),
      (objArgs[key] = {
        value: value
      }), objArgs);

    Object.defineProperties(bareObj, objArgs);

  });

  return {
    input: obj,
    output: bareObj
  };

}(obj);

if (!Object.entries) {
  Object.entries = function(obj){
    var arr = [];
    Object.keys(obj).forEach(function(key){
      arr.push([key, obj[key]]);
    });
    return arr;
  }
}

console(bareObj);


0

Vous pouvez effectuer les opérations suivantes pour ES5:

var theTop = 'top'
<something>.stop().animate(
  JSON.parse('{"' + theTop + '":' + JSON.stringify(10) + '}'), 10
)

Ou extrayez vers une fonction:

function newObj (key, value) {
  return JSON.parse('{"' + key + '":' + JSON.stringify(value) + '}')
}

var theTop = 'top'
<something>.stop().animate(
  newObj(theTop, 10), 10
)


0

Vous pouvez le faire de cette façon:

var thetop = 'top';
<something>.stop().animate(
    new function() {this[thetop] = 10;}, 10
);

0

Vous pouvez également essayer comme ceci:

let array1 = [{
    "description": "THURSDAY",
    "count": "1",
    "date": "2019-12-05"
},
{
    "description": "WEDNESDAY",
    "count": "0",
    "date": "2019-12-04"
}]
let res = array1.map((value, index) => {
    return { [value.description]: { count: value.count, date: value.date } }
})
console.log(res);

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.