Wie verwende ich eine Variable für einen Schlüssel in einem JavaScript-Objektliteral?


406

Warum funktioniert folgendes?

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

Während dies nicht funktioniert:

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

Um es noch deutlicher zu machen: Im Moment kann ich keine CSS-Eigenschaft als Variable an die Animationsfunktion übergeben.



Antworten:


667

{ thetop : 10 }ist ein gültiges Objektliteral. Der Code erstellt ein Objekt mit einer Eigenschaft mit thetopdem Wert 10. Beide sind identisch:

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

In ES5 und früheren Versionen können Sie eine Variable nicht als Eigenschaftsnamen in einem Objektliteral verwenden. Sie können nur Folgendes tun:

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 definiert ComputedPropertyName als Teil der Grammatik für Objektliterale, mit der Sie den Code wie folgt schreiben können:

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

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

Sie können diese neue Syntax in den neuesten Versionen jedes Mainstream-Browsers verwenden.


Ich verstehe! Vielen Dank! Soll das nicht auch mit eval funktionieren? Ich meine, es funktioniert im Moment in meinem Beispiel nicht, aber ich
denke,

3
@Marcel: eval()würde in einem Objektliteral für dynamische Eigenschaftsnamen nicht funktionieren, es würde nur eine Fehlermeldung angezeigt . Nicht nur das, sondern eval()sollte wirklich nicht für solche Dinge verwendet werden. Es gibt einen ausgezeichneten Artikel über die korrekte und falsche Verwendung von eval: blogs.msdn.com/ericlippert/archive/2003/11/01/53329.aspx
Andy E

2
@AndyE erwägt, "aktuelle Versionen" und "aktuelle IE-TP" mit einer genaueren Zeit wie "Versionen später als XXX" oder "nach 2014-mm" zu aktualisieren (ich würde mich selbst ändern, aber ich weiß nicht, welche guten Werte wäre.
Alexei Levenkov

1
Gibt es für ES6 eine Möglichkeit, die Eigenschaft wegzulassen, wenn der Schlüssel null / undefiniert ist? Wenn zum Beispiel der {[key] : "value"}Schlüssel null wäre, würde er geben { null: "value"}, während ich das Ergebnis gerne hätte{}
wasabigeek

wunderbare Lösung, aber warum Sie so viel wissen, selbst das Lesen der gesamten Spezifikation konnte keinen Punkt bekommen :(
hugemeow

126

Mit ECMAScript 2015 können Sie dies jetzt direkt in der Objektdeklaration mit der Klammernotation tun: 

var obj = {
  [key]: value
}

Wo keykann eine beliebige Art von Ausdruck (z. B. eine Variable) sein, der einen Wert zurückgibt.

Hier würde Ihr Code also so aussehen:

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

Wo thetopwird ausgewertet, bevor es als Schlüssel verwendet wird.


17

ES5-Zitat, das besagt, dass es nicht funktionieren sollte

Hinweis: Die Regeln für ES6 wurden geändert: https://stackoverflow.com/a/2274327/895245

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

Name des Anwesens :

  • IdentifierName
  • StringLiteral
  • NumericLiteral

[...]

Die Produktion PropertyName: IdentifierName wird wie folgt ausgewertet:

  1. Gibt den String-Wert zurück, der dieselbe Zeichenfolge wie der IdentifierName enthält.

Die Produktion PropertyName: StringLiteral wird wie folgt ausgewertet:

  1. Gibt den SV [String value] des StringLiteral zurück.

Die Produktion PropertyName: NumericLiteral wird wie folgt ausgewertet:

  1. Sei nbr das Ergebnis der Bildung des Wertes des NumericLiteral.
  2. Kehren Sie zu ToString (nbr) zurück.

Das bedeutet, dass:

  • { theTop : 10 } ist genau das gleiche wie { 'theTop' : 10 }

    Das PropertyName theTopist ein IdentifierName, also wird es in den 'theTop'Zeichenfolgenwert konvertiert, der der Zeichenfolgenwert von ist 'theTop'.

  • Es ist nicht möglich, Objektinitialisierer (Literale) mit variablen Schlüsseln zu schreiben.

    Die einzigen drei Optionen sind IdentifierName(wird zu einem Zeichenfolgenliteral erweitert) StringLiteralund NumericLiteral(wird auch zu einer Zeichenfolge erweitert).


3
Downvoters: Ich war der erste, der zu dieser Frage einen Standard zitierte. Das ES6-Zitat in der oberen Antwort wurde bearbeitet, nachdem ich geantwortet hatte, und dieser Standard wurde zu diesem Zeitpunkt noch nicht akzeptiert. Wenn Sie zufällig wissen, warum ich sonst Downvotes bekomme, erklären Sie bitte, ich möchte nur lernen. Ich könnte genauso gut das
Gruppenzwangsabzeichen bekommen

Ich denke, die Ablehnung war hauptsächlich darauf zurückzuführen, dass Ihre Antwort keine Lösung bietet und in dieser Hinsicht "nicht nützlich" ist. Abstimmung gegen
Gruppenzwang

3
@Bergi danke für den Mut! :-) Aber ich glaube ich habe die Frage direkt beantwortet : F: "Warum funktioniert folgendes?". A: weil ES5 das sagt. "Was tun?" ist implizit. Haben Sie die oberste Frage für "Es ist unmöglich" ohne ein Standardzitat abgelehnt, bevor jemand die ES6-Lösung bearbeitet hat?
Ciro Santilli 法轮功 冠状 病 六四 事件 3

Ah richtig. Normalerweise zitiere ich die spezifischen Fragen in einem Blockzitat, um deutlich zu machen, wenn ich sie direkt beantworte. Das Zitieren des Standards kann eine gute Antwort noch besser machen, aber derzeit beantwortet Ihr Beitrag nicht einmal die Frage imo. Die Angabe, was einen Schlüssel in ES5 ausmachen kann, bedeutet nicht, wie sie funktionieren. Sicher thetopist ein IdentifierName, warum funktioniert es nicht ? Diese Frage ist noch offen.
Bergi

1
@Bergi nochmals vielen Dank für die Erklärung! Ich habe es aktualisiert, um es expliziter zu machen. Ich hatte es vorher noch nicht gemacht, weil ich dachte, es sei offensichtlich, weil wir schreiben können {a:1}.a, also aden Variablenwert im Bezeichnerfall eindeutig nicht erweitern. Aber ja, weiter zu erklären ist in diesem Fall eine Verbesserung.
Ciro Santilli 3 冠状 病 六四 事件 3

5

Ich habe Folgendes verwendet, um einem Objekt eine Eigenschaft mit einem "dynamischen" Namen hinzuzufügen:

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

key ist der Name der neuen Eigenschaft.

Das Objekt der Eigenschaften, an die übergeben animatewird, ist{left: 20, width: 100, top: 10}

Hierbei wird nur die erforderliche []Notation verwendet, wie in den anderen Antworten empfohlen, jedoch mit weniger Codezeilen!


5

Das Hinzufügen einer eckigen Klammer um die Variable funktioniert gut für mich. Versuche dies

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

Dies funktioniert in älteren Versionen von EcmaScript nicht, aber heutzutage ist dies ein sehr sauberer Ansatz.
Oliver

3

Ich konnte kein einfaches Beispiel für die Unterschiede zwischen ES6 und ES5 finden, also habe ich eines gemacht. Beide Codebeispiele erstellen genau das gleiche Objekt. Das ES5-Beispiel funktioniert jedoch auch in älteren Browsern (wie IE11), während das ES6-Beispiel dies nicht tut.

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

2020 Update / Beispiel ...

Ein komplexeres Beispiel mit Klammern und Literalen ... etwas, das Sie möglicherweise zum Beispiel mit vue / axios tun müssen. Wickeln Sie das Literal also in die Klammern

[`...`]

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

1

Gegebener Code:

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

Übersetzung:

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

Wie Sie sehen können, verwendet die { thetop : 10 }Deklaration die Variable nicht thetop. Stattdessen wird ein Objekt mit einem Schlüssel namens erstellt thetop. Wenn der Schlüssel der Wert der Variablen sein soll thetop, müssen Sie eckige Klammern verwenden thetop:

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

Die eckige Klammer-Syntax wurde mit ES6 eingeführt. In früheren Versionen von JavaScript müssten Sie Folgendes tun:

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

1

Ich kann es nicht glauben dies noch nicht veröffentlicht wurde: Verwenden Sie einfach die Pfeilnotation mit anonymer Bewertung!

Völlig nicht invasiv, spielt nicht mit dem Namespace und benötigt nur eine Zeile:

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

Demo:

nützlich in Umgebungen, die die neue {[myKey]: myValue}Syntax noch nicht unterstützen , wie z. Ich habe es gerade auf meiner Web Developer Console überprüft - Firefox 72.0.1, veröffentlicht am 08.01.2020.

(Ich bin sicher, Sie könnten möglicherweise leistungsfähigere / erweiterbarere Lösungen oder was auch immer mit cleverem Einsatz entwickeln reduce, aber an diesem Punkt wäre es wahrscheinlich besser, wenn Sie die Objekterstellung einfach in ihre eigene Funktion aufteilen, anstatt sie zwanghaft zu blockieren alle inline)


Nicht, dass es wichtig wäre, seit OP dies vor zehn Jahren gefragt hat, aber der Vollständigkeit halber und um zu demonstrieren, wie es genau die Antwort auf die angegebene Frage ist, werde ich dies im ursprünglichen Kontext zeigen:

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

0

Auf diese Weise können Sie auch die gewünschte Ausgabe erzielen

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

Die ES5-Implementierung zum Zuweisen von Schlüsseln ist unten aufgeführt:

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

Object.defineProperties(obj, objArgs);

Ich habe ein Snippet angehängt, das ich zum Konvertieren in ein nacktes Objekt verwendet habe.

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

Für ES5 können Sie Folgendes tun:

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

Oder extrahieren Sie zu einer Funktion:

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

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


0

Sie können es so machen:

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

0

Sie können auch Folgendes versuchen:

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.