Jak używać zmiennej dla klucza w dosłownym obiekcie JavaScript?

406

Dlaczego poniższe działania działają?

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

Podczas gdy to nie działa:

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

Aby było jeszcze jaśniej: W tej chwili nie jestem w stanie przekazać właściwości CSS do funkcji animacji jako zmiennej.

speendo
źródło

Odpowiedzi:

667

{ thetop : 10 }jest poprawnym dosłownym obiektem. Kod utworzy obiekt o nazwie thetopo nazwie o wartości 10. Oba poniższe są takie same:

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

W ES5 i wcześniejszych nie można używać zmiennej jako nazwy właściwości wewnątrz literału obiektu. Jedyną opcją jest wykonanie następujących czynności:

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 definiuje ComputedPropertyName jako część gramatyki literałów obiektowych, co pozwala pisać kod w następujący sposób:

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

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

Możesz użyć tej nowej składni w najnowszych wersjach każdej głównej przeglądarki.

Andy E.
źródło
Rozumiem! Dziękuję Ci! Czy to też nie działa z eval? Mam na myśli, że w tej chwili nie działa w moim przykładzie, ale rozcieńczam powinien ... :-)
speendo
3
@Marcel: eval()nie działałby wewnątrz literału obiektu dla dynamicznych nazw właściwości, po prostu pojawiłby się błąd. Nie tylko to, ale eval()naprawdę nie powinno się go używać do takich rzeczy. Jest doskonały artykuł na temat poprawnego i niepoprawnego użycia eval: blogs.msdn.com/ericlippert/archive/2003/11/01/53329.aspx
Andy E
2
@AndyE rozważ aktualizację „najnowszych wersji” i „bieżącego IE TP” o bardziej konkretny czas, np. „Wersje późniejsze niż XXX” lub „po 2014-mm” (sam bym dokonał zmian, ale nie wiem, jakie dobre wartości byłoby
Aleksiej Lewenkow
1
w przypadku ES6, czy istnieje sposób, aby pominąć właściwość, jeśli klucz ma wartość null / undefined? Na przykład, {[key] : "value"}jeśli klucz byłby pusty, dałby { null: "value"}, podczas gdy chciałbym, aby wynik był{}
wasabigeek
wspaniałe rozwiązanie, ale dlaczego tak dużo wiesz, nawet czytanie całej specyfikacji nie mogło uzyskać punktu :(
hugemeow
126

Dzięki ECMAScript 2015 możesz teraz zrobić to bezpośrednio w deklaracji obiektu za pomocą notacji w nawiasach: 

var obj = {
  [key]: value
}

Gdzie keymoże być dowolne wyrażenie (np. Zmienna) zwracające wartość.

Więc twój kod wyglądałby następująco:

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

Gdzie thetopzostanie oceniony przed użyciem jako klucza.

kube
źródło
17

Cytat ES5, który mówi, że to nie powinno działać

Uwaga: zasady uległy zmianie w ES6: https://stackoverflow.com/a/2274327/895245

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

Nazwa właściwości :

  • IdentifierName
  • StringLiteral
  • NumericLiteral

[...]

Produkcja PropertyName: IdentifierName jest oceniana w następujący sposób:

  1. Zwraca wartość ciągu zawierającego tę samą sekwencję znaków, co nazwa identyfikatora.

Produkcja PropertyName: StringLiteral jest oceniana w następujący sposób:

  1. Zwraca SV [wartość ciągu] parametru StringLiteral.

Produkcja PropertyName: NumericLiteral jest oceniana w następujący sposób:

  1. Niech nbr będzie wynikiem formowania wartości NumericLiteral.
  2. Return ToString (nbr).

To znaczy że:

  • { theTop : 10 } jest dokładnie taki sam jak { 'theTop' : 10 }

    PropertyName theTopJest IdentifierName, więc zostanie przekonwertowany do 'theTop'wartości ciągu, który jest wartość ciąg 'theTop'.

  • Nie można pisać inicjatorów obiektów (literałów) ze zmiennymi kluczami.

    Jedyne trzy opcje to IdentifierName(rozwija się do literału łańcuchowego) StringLiterali NumericLiteral((rozwija się również do łańcucha).

Ciro Santilli
źródło
3
Downvoters: Byłem pierwszym, który zacytował jakikolwiek standard w tej kwestii. Cytat ES6 na górze odpowiedzi został zredagowany po tym, jak odpowiedziałem, a ten standard nie został jeszcze zaakceptowany. Jeśli zdarzyło Ci się wiedzieć, dlaczego jeszcze nie otrzymuję opinii, proszę wyjaśnij, chcę się tylko nauczyć.
Równie
Wydaje mi się, że głosowanie było głównie dlatego, że twoja odpowiedź nie oferuje rozwiązania i jest „nieużyteczna” w tym względzie. Głosowanie w kierunku presji rówieśników :-)
Bergi
3
@Bergi dziękuję za odwagę! :-) Ale myślę, że odpowiedziałem bezpośrednio na pytanie : P: „Dlaczego działa następujący?”. Odp .: ponieważ ES5 tak mówi. "Co z tym zrobić?" jest niejawny. Czy głosowałeś za najważniejszym pytaniem za powiedzenie „To niemożliwe” bez standardowego cytatu przed kimś edytowanym w rozwiązaniu ES6?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Ah, tak. Zazwyczaj cytuję konkretne pytania w cytacie blokowym, aby wyjaśnić, kiedy odpowiadam bezpośrednio na nie. Cytując standard, można poprawić dobrą odpowiedź, ale obecnie twój post nawet nie odpowiada na pytanie imo. Podanie, co może uczynić klucz w ES5, nie oznacza, jak działają. Na pewno thetopjest IdentifierName, więc dlaczego to nie działa ? To pytanie jest nadal otwarte.
Bergi,
1
@Bergi jeszcze raz dziękuję za wyjaśnienie! Zaktualizowałem go, aby był bardziej wyraźny. Nie robiłem tego wcześniej, ponieważ myślałem, że to oczywiste, ponieważ możemy pisać {a:1}.a, więc awyraźnie nie rozszerzaj wartości zmiennej w przypadku identyfikatora. Ale tak, dalsze wyjaśnienie jest poprawą w tym przypadku.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
5

Użyłem następujących elementów, aby dodać właściwość o nazwie „dynamicznej” do obiektu:

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

key to nazwa nowej właściwości.

Obiektem przekazywanych właściwości animatebędzie{left: 20, width: 100, top: 10}

Jest to po prostu użycie wymaganej []notacji zgodnie z zaleceniami innych odpowiedzi, ale z mniejszą liczbą wierszy kodu!

Phil M.
źródło
5

Dodanie nawiasu kwadratowego wokół zmiennej działa dla mnie dobrze. Spróbuj tego

var thetop = 'top';
<something>.stop().animate(
    { [thetop] : 10 }, 10
);
Vaishali Venkatesan
źródło
To nie zadziała w starszych wersjach EcmaScript, ale obecnie jest to bardzo czyste podejście.
Oliver
3

Nie mogłem znaleźć prostego przykładu na temat różnic między ES6 a ES5, więc zrobiłem taki. Oba próbki kodu tworzą dokładnie ten sam obiekt. Ale przykład ES5 działa również w starszych przeglądarkach (takich jak IE11), gdzie nie działa przykład 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));
Dieter Schmitt
źródło
2

Aktualizacja 2020 / przykład ...

Bardziej złożony przykład z użyciem nawiasów i literałów ... coś, co możesz zrobić na przykład z vue / axios. Owinąć literał w nawiasy, więc

[`... ...]

{
    [`filter[${query.key}]`]: query.value,  // 'filter[foo]' : 'bar'
}
mangonights
źródło
1

Podany kod:

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

Tłumaczenie:

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

Jak widać, { thetop : 10 }deklaracja nie korzysta ze zmiennej thetop. Zamiast tego tworzy obiekt z kluczem o nazwie thetop. Jeśli chcesz, aby klucz był wartością zmiennej thetop, musisz użyć nawiasów kwadratowych wokół thetop:

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

Składnia nawiasu kwadratowego została wprowadzona w ES6. We wcześniejszych wersjach JavaScript należy wykonać następujące czynności:

var thetop = 'top';
var config = (
  obj = {},
  obj['' + thetop] = 10,
  obj
); // config.top = 10
<something>.stop().animate(config, 10);
Benny Neugebauer
źródło
1

Nie mogę uwierzyć, że nie zostało to jeszcze opublikowane: użyj notacji ze strzałką z anonimową oceną!

Całkowicie nieinwazyjny, nie zadziera z przestrzenią nazw i zajmuje tylko jedną linię:

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

próbny:

przydatne w środowiskach, które nie obsługują {[myKey]: myValue}jeszcze nowej składni, takich jak - najwyraźniej; Właśnie to zweryfikowałem w konsoli Web Developer - Firefox 72.0.1, wydany 08.01.2020.

(Jestem pewien, że mógłbyś potencjalnie stworzyć jakieś bardziej wydajne / rozszerzalne rozwiązania lub cokolwiek obejmującego sprytne użycie reduce, ale w tym momencie prawdopodobnie lepiej byś był obsługiwany przez rozbicie stworzenia obiektu na swoją własną funkcję zamiast kompulsywnego blokowania go wszystko w linii)


nie, że jest to ważne, ponieważ PO zadał to dziesięć lat temu, ale dla kompletności boską i zademonstrować, jak to jest dokładnie odpowiedź na pytanie, jak stwierdził, pokażę to w oryginalnym kontekście:

var thetop = 'top';
<something>.stop().animate(
    ((k,v)=>{o={};o[k]=v;return o;})(thetop,10), 10
);
JamesTheAwesomeDude
źródło
0

W ten sposób można również osiągnąć pożądaną wydajność

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
źródło
0

Implementacja ES5 do przypisywania kluczy jest poniżej:

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

Object.defineProperties(obj, objArgs);

Dołączyłem fragment, którego użyłem do konwersji na nagi obiekt.

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

kochanie
źródło
0

W przypadku ES5 możesz wykonać następujące czynności:

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

Lub wypakuj do funkcji:

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

var theTop = 'top'
<something>.stop().animate(
  newObj(theTop, 10), 10
)
sh32my
źródło
0

Jeśli chcesz, aby klucz obiektu był taki sam jak nazwa zmiennej, w ES 2015 jest krótka ręka. Nowe notacje w ECMAScript 2015

var thetop = 10;
var obj = { thetop };
console.log(obj.thetop); // print 10
ROROROOROROR
źródło
0

Możesz to zrobić w ten sposób:

var thetop = 'top';
<something>.stop().animate(
    new function() {this[thetop] = 10;}, 10
);
Yury Laykov
źródło
0

Możesz także spróbować w ten sposób:

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
źródło