Bagaimana cara menggunakan variabel untuk kunci dalam objek JavaScript?


407

Mengapa cara berikut ini berfungsi?

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

Padahal ini tidak berhasil:

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

Untuk membuatnya lebih jelas: Saat ini saya tidak dapat meneruskan properti CSS ke fungsi animasi sebagai variabel.



Jawaban:


668

{ thetop : 10 }adalah objek literal yang valid. Kode akan membuat objek dengan properti bernama thetopyang memiliki nilai 10. Keduanya berikut ini sama:

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

Di ES5 dan sebelumnya, Anda tidak bisa menggunakan variabel sebagai nama properti di dalam objek literal. Satu-satunya pilihan Anda adalah melakukan hal berikut:

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 mendefinisikan ComputedPropertyName sebagai bagian dari tata bahasa untuk objek literal, yang memungkinkan Anda untuk menulis kode seperti ini:

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

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

Anda dapat menggunakan sintaks baru ini di versi terbaru dari setiap browser utama.


Saya mengerti! Terima kasih! Tidakkah ini juga bekerja dengan eval? Maksud saya itu tidak berfungsi dalam contoh saya saat ini, tapi saya
pikir

3
@Marcel: eval()tidak akan berfungsi di dalam objek literal untuk nama properti dinamis, Anda hanya akan mendapatkan kesalahan. Bukan hanya itu, tetapi eval()benar-benar tidak boleh digunakan untuk hal-hal seperti itu. Ada artikel yang bagus tentang penggunaan yang benar dan salah eval: blogs.msdn.com/ericlippert/archive/2003/11/01/53329.aspx
Andy E

2
@AndyE mempertimbangkan untuk memperbarui "versi terbaru" dan "TP IE saat ini" dengan waktu yang lebih spesifik seperti "Versi lebih lambat dari XXX" atau "setelah 2014-mm" (Saya akan mengubahnya sendiri, tetapi saya tidak tahu apa nilai yang baik akan
Alexei Levenkov

1
untuk ES6, apakah ada cara untuk meninggalkan properti jika kuncinya adalah null / tidak terdefinisi? Misalnya, dalam {[key] : "value"}, jika kunci nol, itu akan memberikan { null: "value"}, sedangkan saya ingin hasilnya{}
wasabigeek

solusi luar biasa, tetapi mengapa Anda tahu begitu banyak, bahkan membaca seluruh spesifikasi tidak bisa mendapatkan poin :(
hugemeow

126

Dengan ECMAScript 2015 Anda sekarang dapat melakukannya secara langsung dalam deklarasi objek dengan notasi tanda kurung: 

var obj = {
  [key]: value
}

Di mana keybisa segala jenis ekspresi (misalnya variabel) mengembalikan nilai.

Jadi di sini kode Anda akan terlihat seperti:

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

Di mana thetopakan dievaluasi sebelum digunakan sebagai kunci.


17

Kutipan ES5 yang mengatakan itu seharusnya tidak bekerja

Catatan: aturan telah berubah untuk ES6: https://stackoverflow.com/a/2274327/895245

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

Nama properti :

  • IdentifierName
  • StringLiteral
  • NumericLiteral

[...]

Properti PropertyName: IdentifierName dievaluasi sebagai berikut:

  1. Kembalikan nilai String yang berisi urutan karakter yang sama dengan IdentifierName.

Properti PropertyName: StringLiteral dievaluasi sebagai berikut:

  1. Kembalikan SV [Nilai string] dari StringLiteral.

Properti PropertyName produksi: NumericLiteral dievaluasi sebagai berikut:

  1. Biarkan nbr menjadi hasil pembentukan nilai NumericLiteral.
  2. Kembali ToString (nbr).

Ini berarti:

  • { theTop : 10 } sama persis dengan { 'theTop' : 10 }

    The PropertyName theTopadalah IdentifierName, sehingga akan dikonversi ke 'theTop'nilai string, yang merupakan nilai string 'theTop'.

  • Tidak mungkin menulis inisialisasi objek (literal) dengan kunci variabel.

    Tiga opsi hanya IdentifierName(memperluas string string) StringLiteral,, dan NumericLiteral(juga memperluas string).


3
Downvoters: Saya adalah orang pertama yang mengutip standar apa pun tentang pertanyaan ini. Kutipan ES6 pada jawaban atas diedit setelah saya menjawab, dan standar itu belum diterima pada saat itu. Jika Anda tahu mengapa saya mendapatkan downvote, mohon jelaskan, saya hanya ingin belajar. Saya mungkin juga mendapatkan lencana tekanan teman sebaya ...
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Saya kira downvote kebanyakan karena jawaban Anda tidak menawarkan solusi, dan "tidak berguna" dalam hal itu. Voting menuju tekanan rekan :-)
Bergi

3
@Bergi terima kasih atas keberaniannya! :-) Tapi saya pikir saya telah menjawab pertanyaan secara langsung : T: "Mengapa cara berikut ini berhasil?". A: karena ES5 mengatakan demikian. "Apa yang harus dilakukan tentang hal itu?" tersirat. Apakah Anda menurunkan pertanyaan atas untuk mengatakan "Tidak mungkin" tanpa kutipan standar sebelum seseorang diedit dalam solusi ES6?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Ah benar Saya biasanya mengutip pertanyaan spesifik dalam blockquote untuk memperjelas ketika saya menjawabnya secara langsung. Mengutip standar dapat membuat jawaban yang lebih baik, tetapi saat ini posting Anda bahkan tidak menjawab pertanyaan imo. Menyatakan apa yang bisa membuat kunci dalam ES5 tidak menyiratkan cara kerjanya. Tentunya thetopadalah IdentifierName, jadi mengapa itu tidak berhasil ? Pertanyaan itu masih terbuka.
Bergi

1
@Bergi terima kasih lagi untuk menjelaskannya padaku! Saya telah memperbaruinya untuk membuatnya lebih eksplisit. Saya belum pernah melakukannya sebelumnya karena saya pikir itu sudah jelas, karena kita bisa menulis {a:1}.a, jadi ajelas tidak memperluas nilai variabel dalam kasus pengenal. Tapi ya, menjelaskan lebih lanjut adalah perbaikan dalam kasus ini.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

5

Saya telah menggunakan yang berikut ini untuk menambahkan properti dengan nama "dinamis" ke objek:

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

key adalah nama properti baru.

Objek properti yang diteruskan animateadalah{left: 20, width: 100, top: 10}

Ini hanya menggunakan yang diperlukan [] notasi yang seperti yang direkomendasikan oleh jawaban lain, tetapi dengan lebih sedikit baris kode!


5

Menambahkan braket persegi di sekitar variabel berfungsi baik untuk saya. Coba ini

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

Ini tidak akan berfungsi di versi yang lebih lama dari EcmaScript, tetapi saat ini ini adalah pendekatan yang sangat bersih.
Oliver

3

Saya tidak dapat menemukan contoh sederhana tentang perbedaan antara ES6 dan ES5, jadi saya membuatnya. Kedua sampel kode membuat objek yang persis sama. Tetapi contoh ES5 juga bekerja di browser lama (seperti IE11), di mana contoh ES6 tidak.

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

Pembaruan 2020 / contoh ...

Contoh yang lebih kompleks, menggunakan tanda kurung dan literal ... sesuatu yang mungkin harus Anda lakukan misalnya dengan vue / axios. Bungkus literal dalam tanda kurung, jadi

[`...`]

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

1

Kode yang diberikan:

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

Terjemahan:

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

Seperti yang Anda lihat, { thetop : 10 }deklarasi tidak menggunakan variabel thetop. Sebaliknya itu menciptakan objek dengan nama kunci thetop. Jika Anda ingin kunci menjadi nilai variabel thetop, maka Anda harus menggunakan tanda kurung siku sekitar thetop:

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

Sintaks braket persegi telah diperkenalkan dengan ES6. Di versi JavaScript yang lebih lama, Anda harus melakukan hal berikut:

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

1

Saya tidak bisa percaya ini belum diposting: cukup gunakan panah-notasi dengan evaluasi anonim!

Sepenuhnya non-invasif, tidak mengacaukan namespace, dan hanya membutuhkan satu baris:

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

demo:

berguna dalam lingkungan yang belum mendukung {[myKey]: myValue}sintaks baru , seperti — tampaknya; Saya baru saja memverifikasi di Konsol Pengembang Web saya — Firefox 72.0.1, dirilis 2020-01-08.

(Saya yakin Anda berpotensi membuat beberapa solusi yang lebih kuat / dapat diperluas atau apa pun yang melibatkan penggunaan yang cerdas reduce, tetapi pada saat itu Anda mungkin akan lebih baik dilayani dengan hanya membagi Obyek-penciptaan ke dalam fungsinya sendiri daripada secara kompulsif mengganggunya semua sebaris)


bukan hal itu penting karena OP bertanya ini sepuluh tahun yang lalu, tapi untuk kelengkapan demi dan untuk menunjukkan bagaimana hal ini persis dengan jawaban atas pertanyaan seperti yang dinyatakan, saya akan menunjukkan ini dalam konteks aslinya:

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

0

Dengan cara ini Anda juga dapat mencapai hasil yang diinginkan

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

Implementasi ES5 untuk menetapkan kunci di bawah ini:

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

Object.defineProperties(obj, objArgs);

Saya telah melampirkan cuplikan yang saya gunakan untuk mengonversi ke objek kosong.

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

Anda dapat melakukan hal berikut untuk ES5:

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

Atau ekstrak ke suatu fungsi:

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

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


0

Anda dapat melakukannya dengan cara ini:

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

0

Anda juga dapat mencoba seperti ini:

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.