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.

Speendo
quelle

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.

Andy E.
quelle
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.

kube
quelle
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).

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
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!

Phil M.
quelle
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
);
Vaishali Venkatesan
quelle
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));
Dieter Schmitt
quelle
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'
}
Mangonights
quelle
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);
Benny Neugebauer
quelle
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
);
JamesTheAwesomeDude
quelle
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>

Deepu Reghunath
quelle
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);

Darcher
quelle
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
)
sh32my
quelle
0

Wenn der Objektschlüssel mit dem Variablennamen identisch sein soll, gibt es in ES 2015 eine kurze Hand. Neue Notationen in ECMAScript 2015

var thetop = 10;
var obj = { thetop };
console.log(obj.thetop); // print 10
ROROROOROROR
quelle
0

Sie können es so machen:

var thetop = 'top';
<something>.stop().animate(
    new function() {this[thetop] = 10;}, 10
);
Yury Laykov
quelle
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);

Saurabh Agrawal
quelle