web-dev-qa-db-fra.com

clés dynamiques pour les littéraux d'objets en Javascript

Ok donc je travaille sur un projet dans Nodes, et je suis tombé sur un petit problème avec les clés dans les littéraux d'objet, j'ai la configuration suivante:

var required = {
    directories : {
        this.applicationPath                    : "Application " + this.application + " does not exists",
        this.applicationPath + "/configs"       : "Application config folder does not exists",
        this.applicationPath + "/controllers"   : "Application controllers folder does not exists",
        this.applicationPath + "/public"        : "Application public folder does not exists",
        this.applicationPath + "/views"         : "Application views folder does not exists"
    },
    files : {
        this.applicationPath + "/init.js"               : "Application init.js file does not exists",
        this.applicationPath + "/controllers/index.js"  : "Application index.js controller file does not exists",
        this.applicationPath + "/configs/application.js": "Application configs/application.js file does not exists",
        this.applicationPath + "/configs/server.js"     : "Application configs/server.js file does not exists"
    }
}

Ok, beaucoup d'entre vous vont regarder ça et penser que ça va, mais le compilateur continue de me dire que je manque un : (deux points), ce qui n'est pas le cas, il semble que le + ou et le . affectent tous deux le compilateur.

Maintenant, je crois (pas sûr) que les littéraux d'objet sont créés au moment de la compilation et non au moment de l'exécution, ce qui signifie que des variables dynamiques telles que this.applicationPath et la concaténation ne seront pas disponibles :( :(

Quelle est la meilleure façon de surmonter un obstacle comme celui-ci sans avoir à réécrire de gros morceaux de code.

76
RobertPitt

La seule façon de définir des clés dynamiques est avec la notation entre crochets:

required.directories[this.applicationPath + "/configs"] = "Application config folder does not exists";

(bien sûr, où que vous fassiez cette définition, this.applicationPath doit exister)

Mais avez-vous besoin de this.applicationPath dans les clés? Comment accédez-vous à ces valeurs? Vous pouvez peut-être simplement supprimer this.applicationPath à partir de la valeur que vous utilisez pour accéder aux propriétés.


Mais au cas où vous en auriez besoin:

Vous pouvez utiliser un tableau pour initialiser les clés si vous voulez éviter de répéter beaucoup de code:

var dirs = ['configs', 'controllers', ...];
var files = ['init.js', 'controllers/index.js', ...];

var required = { directories: {}, files: {} };
required.directories[this.applicationPath] = "Application " + this.application + " does not exists";

for(var i = dirs.length; i--;) {
    required.directories[this.applicationPath + '/' + dirs[i]] = "Application " + dirs[i] + " folder does not exists";
}

for(var i = files.length; i--;) {
    // same here
}
40
Felix Kling

Dans un littéral objet (ECMA-262 §11.1.5 l'appelle un "initialiseur d'objet"), la clé doit être l'une des suivantes:

  1. IdentifierName
  2. StringLiteral
  3. NumericLiteral

Vous ne pouvez donc pas utiliser une expression comme clé dans un initialiseur. Vous pouvez utiliser une expression avec une notation entre crochets pour accéder à une propriété. Donc, pour définir les propriétés avec une expression, vous devez faire:

var required = { directories : {}};
required.directories[this.applicationPath] = "Application " + this.application + " does not exists";
required.directories[this.applicationPath + "/configs"] = "Application config folder does not exists";
...

etc. Puisque this.applicationPath est beaucoup réutilisé, mieux vaut stocker une référence pour améliorer les performances et réduire la quantité de code:

var a = this.applicationPath;
var required = { directories : {}};
var rd = required.directories;
rd[a] = "Application " + this.application + " does not exists";
rd[a + "/configs"] = "Application config folder does not exists";
...

Modifier

Depuis ECMAScript ed 6, les initialiseurs d'objets peuvent avoir des clés calculées en utilisant:

[expression]: value

Il existe également une syntaxe abrégée pour les noms de propriété et de méthode.

Voir MDN: Object Initializer ou ECMAScript §12.2.6 .

91
RobG

Les noms de propriété calculés sont pris en charge dans ECMAScript2015:

var name = 'key';
var value = 'value';
var o = {
  [name]: value
};
alert("o as json : " + JSON.stringify(o));

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer

85
Rich Apodaca

Inspiré par la façon dont babel couvre la nouvelle syntaxe ES6 ({[expression]: value}) à l'ancien Javascript, j'ai appris que vous pouvez le faire avec un seul revêtement:

var obj = (_obj = {}, _obj[expression] = value, _obj);

Exemple:

var dynamic_key = "hello";
var value = "world";
var obj = (_obj = {}, _obj[dynamic_key] = value, _obj);

console.log(obj);
// Object {hello: "world"}

(Testé sur le dernier Chrome)

5
Dan Barzilay

Si vous avez une structure d'objet profonde (telle que la configuration de Grunt), il est parfois pratique de pouvoir retourner des clés d'objet générées dynamiquement en utilisant la notation entre crochets décrite par Felix , mais en ligne dans la structure d'objet. Ceci peut être réalisé en utilisant une fonction pour retourner dynamiquement un objet dans le contexte de l'objet profond; dans le cas du code de cette question, quelque chose comme ceci:

var required = {
    directories : function() {
        var o = {};
        o[this.applicationPath] = "Application " + this.application + " does not exists";
        o[this.applicationPath + "/configs"] = "Application config folder does not exists";
        o[this.applicationPath + "/controllers"] = "Application controllers folder does not exists";
        o[this.applicationPath + "/public"] = "Application public folder does not exists";
        o[this.applicationPath + "/views"] = "Application views folder does not exists";
        return o;
    }(),
    files : function() {
        var o = {};
        o[this.applicationPath + "/init.js"] = "Application init.js file does not exists";
        o[this.applicationPath + "/controllers/index.js"]  = "Application index.js controller file does not exists";
        o[this.applicationPath + "/configs/application.js"] ="Application configs/application.js file does not exists";
        o[this.applicationPath + "/configs/server.js"]     ="Application configs/server.js file does not exists";
        return o;
    }()
}

Ce violon valide cette approche.

2
DaveAlden

Pour les littéraux d'objet, le script Javascript/ECMAScript spécifie que les clés doivent être un IdentifierName valide, un littéral de chaîne ou un nombre RobG crédit (même hex). Pas une expression, c'est ce que required.applicationPath + "/configs" est.

2
MooGoo

Une vieille question, et les réponses étaient correctes à l'époque, mais les temps changent. Dans le cas où quelqu'un le déterrerait dans une recherche google, les nouvelles versions de javascript (ES6) permettent d'utiliser des expressions comme clés pour les littéraux d'objet, si elles sont entourées de crochets: var obj={["a"+Math.PI]:42}

2
user6451670

le problème vient de l'utilisation de "ceci" car il ne fait référence à rien d'intelligent *. créer le littéral statique avec l'applicationPath dedans.

 var required = {
 "applicationPath": "someWhereOverTheRainboW" 
}; 

Ensuite, utilisez

 required.directories = {}; 
 required.directories [required.applicationPath + "/ configs"] = "Le dossier de configuration de l'application n'existe pas"; 
 .... 

pour le remplir dynamiquement

Modifier; Je me suis précipité avec ma première idée, ça n'a pas marché. Ce qui précède fonctionne maintenant - désolé pour cela!

* le mot-clé 'this' est très intelligent:) mais il se réfère souvent à l'objet fenêtre ou à l'élément, l'événement a été déclenché ou l'objet appelé 'actif'. Ainsi, créant beaucoup de confusion;)

0
japrescott