Apakah mungkin menambahkan properti yang dinamai secara dinamis ke objek JavaScript?

746

Dalam JavaScript, saya telah membuat objek seperti ini:

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};

Apakah mungkin untuk menambahkan properti lebih lanjut ke objek ini setelah pembuatan awal jika nama properti tidak ditentukan sampai waktu berjalan? yaitu

var propName = 'Property' + someUserInput
//imagine someUserInput was 'Z', how can I now add a 'PropertyZ' property to 
//my object?
Lee D
sumber

Jawaban:

1212

Iya.

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};

data["PropertyD"] = 4;

// dialog box with 4 in it
alert(data.PropertyD);
alert(data["PropertyD"]);

Georg Schölly
sumber
142
@thedz: data.PropertyD perlu tahu nama properti, yang tidak cukup dinamis.
Georg Schölly
6
+1 karena ini membantu saya. Tapi saya tidak mengerti mengapa properti obyek ditangani seperti array.
Ron van der Heijden
9
@Bondye: Itu bagian dari desain javascript yang aneh. Dalam hal object["property"]ini tidak persis sama dengan array[4], yang pertama tidak dibuat sebagai array yang benar.
Georg Schölly
5
Apakah hanya saya atau posting ini tidak menjawab pertanyaan saat mendapatkan 195 upvotes? Saya pikir itu bertanya bagaimana mendefinisikan properti di mana namanya tidak diketahui sampai dihasilkan dalam kode JavaScript.
Qantas 94 Heavy
20
@Qantas: Katakanlah itu tidak menjawabnya secara langsung. Tetapi beralih dari data["PropertyD"]ke data[function_to_get_property_name()]tampaknya sepele.
Georg Schölly
154

ES6 untuk kemenangan!

const b = 'b';
const c = 'c';

const data = {
    a: true,
    [b]: true, // dynamic property
    [`interpolated-${c}`]: true, // dynamic property + interpolation
    [`${b}-${c}`]: true
}

Jika Anda log dataAnda mendapatkan ini:

{
  a: true,
  b: true,
  interpolated-c: true,
  b-c: true
}

Ini menggunakan sintaksis Properti Hitung dan Templat Literal baru .

Mauricio Soares
sumber
1
Inilah yang saya butuhkan dalam kasus di mana saya ingin kode saya berfungsi penuh (seperti, tidak ada pernyataan penting yang dikatakan obj[propname]). Sebaliknya, saya bisa menggunakan ini dengan sintaks penyebaran objek.
intcreator
2
Tidak segera jelas apa yang dilakukan cuplikan kode ini kepada seseorang yang belum melihat atau memahami sintaks baru. Saya akan menyarankan suntingan untuk menampilkan output / ekspektasi yang diharapkan dengan konst 'a'.
Secara pribadi, saya pikir cara ES5 jauh lebih bersih dan lebih mudah dipahami:var a = {}; a["dynamic-" + prop] = true;
Jack Giffin
1
@JackGiffin dalam beberapa kasus ya, tetapi ketika bekerja dengan struktur yang tidak dapat diubah, sintaks ini bisa sangat berguna, karena pendekatan yang Anda tunjukkan bermutasi a. (Khususnya ketika menggunakan paket seperti redux)
Mauricio Soares
3
Ini hanya {... keadaan, [prop]: val}
Xipo
87

Ya itu mungkin. Asumsi:

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};
var propertyName = "someProperty";
var propertyValue = "someValue";

Antara:

data[propertyName] = propertyValue;

atau

eval("data." + propertyName + " = '" + propertyValue + "'");

Metode pertama lebih disukai. eval () memiliki masalah keamanan yang jelas jika Anda menggunakan nilai yang disediakan oleh pengguna, jadi jangan menggunakannya jika Anda dapat menghindarinya, tetapi perlu diketahui bahwa ada dan apa yang dapat dilakukan.

Anda dapat merujuk ini dengan:

alert(data.someProperty);

atau

data(data["someProperty"]);

atau

alert(data[propertyName]);
cletus
sumber
40
Menggunakan eval benar-benar berbahaya.
Georg Schölly
10
Belum lagi lambat.
Eamon Nerbonne
@ GeorgSchölly Benar.
Obinna Nwakwue
1
Catatan (jika seseorang mengalami masalah yang sama dengan saya): Untuk objek normal ini berfungsi dengan baik. Tapi saya harus menambahkan beberapa properti ke objek UI jQuery untuk melacak daftar item. Dalam hal ini, properti itu hilang jika ditambahkan dengan cara ini karena jQuery selalu membuat salinan. Di sini Anda perlu menggunakan jQuery.extend () .
Matt
Saya suka menambahkan komentar saya sebelumnya - bahkan itu tidak berfungsi dalam kasus saya. Jadi saya akhirnya menggunakan $("#mySelector").data("propertyname", myvalue);to set, dan var myValue=$("#mySelector").data("propertyname");untuk mendapatkan kembali nilainya. Bahkan objek kompleks (daftar, array ...) dapat ditambahkan dengan cara ini.
Matt
61

Saya tahu bahwa pertanyaannya dijawab dengan sempurna, tetapi saya juga menemukan cara lain untuk menambahkan properti baru dan ingin membaginya dengan Anda:

Anda dapat menggunakan fungsi ini Object.defineProperty()

Ditemukan di Jaringan Pengembang Mozilla

Contoh:

var o = {}; // Creates a new object

// Example of an object property added with defineProperty with a data property descriptor
Object.defineProperty(o, "a", {value : 37,
                               writable : true,
                               enumerable : true,
                               configurable : true});
// 'a' property exists in the o object and its value is 37

// Example of an object property added with defineProperty with an accessor property descriptor
var bValue;
Object.defineProperty(o, "b", {get : function(){ return bValue; },
                               set : function(newValue){ bValue = newValue; },
                               enumerable : true,
                               configurable : true});
o.b = 38;
// 'b' property exists in the o object and its value is 38
// The value of o.b is now always identical to bValue, unless o.b is redefined

// You cannot try to mix both :
Object.defineProperty(o, "conflict", { value: 0x9f91102, 
                                       get: function() { return 0xdeadbeef; } });
// throws a TypeError: value appears only in data descriptors, get appears only in accessor descriptors
artgrohe
sumber
4
Pro dan kontra dari metode ini?
Trevor
6
@ Trevor: Total konfigurasi dan kemampuan untuk menambahkan getter dan setter; juga, kemampuan untuk menambahkan beberapa properti sekaligus dengan defineProperties(jamak).
rvighne
@Thielicious Object.definePropertytidak dimaksudkan sebagai alat kenyamanan yang mudah, tetapi alat yang memiliki kontrol yang baik. Jika Anda tidak memerlukan kontrol tambahan itu, itu bukan alat yang tepat untuk memilih.
kleinfreund
Object.defineProperty(obj, prop, valueDescriptor)jauh lebih lambat dan sulit bagi V8 untuk mengoptimalkan daripada sekadar melakukan obj[prop] = value;
Jack Giffin
27

ES6 memperkenalkan nama properti yang dihitung, yang memungkinkan Anda melakukannya

let a = 'key'
let myObj = {[a]: 10};
// output will be {key:10}
Berkarat
sumber
23

Di sini, menggunakan notasi Anda:

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};
var propName = 'Property' + someUserInput
//imagine someUserInput was 'Z', how can I now add a 'PropertyZ' property to 
//my object?
data[propName] = 'Some New Property value'
Maxim Sloyko
sumber
18

Anda dapat menambahkan lebih banyak properti yang Anda inginkan hanya dengan menggunakan notasi titik:

var data = {
    var1:'somevalue'
}
data.newAttribute = 'newvalue'

atau :

data[newattribute] = somevalue

untuk tombol dinamis.

Gabriel Hurley
sumber
4
jika nama properti tidak ditentukan sampai waktu run" - sehingga tidak akan bekerja kecuali jika Anda menggunakan eval, yang bukan merupakan pilihan yang baik
Marc Gravell
1
atau gunakan sintaks [] ... data [somevar] = somevalue
Gabriel Hurley
17

selain semua jawaban sebelumnya, dan jika Anda bertanya-tanya bagaimana kita akan menulis nama properti dinamis di Masa Depan menggunakan Nama Properti yang Dikomputasi (ECMAScript 6), berikut caranya:

var person = "John Doe";
var personId = "person_" + new Date().getTime();
var personIndex = {
    [ personId ]: person
//  ^ computed property name
};

personIndex[ personId ]; // "John Doe"

referensi: Memahami ECMAScript 6 - Nickolas Zakas

Anas Nakawa
sumber
11

Hanya tambahan jawaban abeing di atas. Anda dapat mendefinisikan fungsi untuk merangkum kompleksitas defineProperty seperti yang disebutkan di bawah ini.

var defineProp = function ( obj, key, value ){
  var config = {
    value: value,
    writable: true,
    enumerable: true,
    configurable: true
  };
  Object.defineProperty( obj, key, config );
};

//Call the method to add properties to any object
defineProp( data, "PropertyA",  1 );
defineProp( data, "PropertyB",  2 );
defineProp( data, "PropertyC",  3 );

referensi: http://addyosmani.com/resources/essentialjsdesignpatterns/book/#constructorpatternjavascript

Sarvesh
sumber
9

Anda dapat menambahkan properti secara dinamis menggunakan beberapa opsi di bawah:

Dalam contoh Anda:

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};

Anda bisa mendefinisikan properti dengan nilai dinamis dalam dua cara berikut:

data.key = value;

atau

data['key'] = value;

Terlebih lagi .. jika kunci Anda juga dinamis, Anda dapat mendefinisikan menggunakan kelas Object dengan:

Object.defineProperty(data, key, withValue(value));

di mana data adalah objek Anda, kunci adalah variabel untuk menyimpan nama dan nilai kunci adalah variabel untuk menyimpan nilai.

Saya harap ini membantu!

Fabricio
sumber
8

Saya tahu ada beberapa jawaban untuk posting ini, tapi saya belum melihat satu di mana ada beberapa properti dan mereka berada dalam array. Dan solusi ini adalah untuk ES6.

Sebagai ilustrasi, katakanlah kita memiliki array bernama orang dengan objek di dalamnya:

 let Person = [{id:1, Name: "John"}, {id:2, Name: "Susan"}, {id:3, Name: "Jet"}]

Jadi, Anda bisa menambahkan properti dengan nilai yang sesuai. Katakanlah kita ingin menambahkan Bahasa dengan nilai default EN .

Person.map((obj)=>({...obj,['Language']:"EN"}))

Susunan Person sekarang akan menjadi seperti ini:

Person = [{id:1, Name: "John", Language:"EN"}, 
{id:2, Name: "Susan", Language:"EN"}, {id:3, Name: "Jet", Language:"EN"}]
Edper
sumber
Anda sebenarnya tidak menambahkan properti ke objek, Anda membuat objek baru dengan properti objek lama (melalui operator spread) dan properti baru juga.
Ed Orsi
3
Anda benar bahwa seharusnya Person = Person.map(code here). Tetapi intinya adalah Anda dapat menambahkan properti ke objek yang ada dengan mudah ES6.
Edper
5

Cara paling sederhana dan paling portabel adalah.

var varFieldName = "good";
var ob = {};
Object.defineProperty(ob, varFieldName , { value: "Fresh Value" });

Berdasarkan jawaban #abeing!

Sydwell
sumber
3

Hati-hati saat menambahkan properti ke objek yang ada menggunakan metode. (Dot) .

(dot) metode menambahkan properti ke objek hanya boleh digunakan jika Anda tahu yang 'kunci' terlebih dahulu jika menggunakan [braket] metode.

Contoh:

   var data = {
        'Property1': 1
    };
    
    // Two methods of adding a new property [ key (Property4), value (4) ] to the
    // existing object (data)
    data['Property2'] = 2; // bracket method
    data.Property3 = 3;    // dot method
    console.log(data);     // { Property1: 1, Property2: 2, Property3: 3 }
    
    // But if 'key' of a property is unknown and will be found / calculated
    // dynamically then use only [bracket] method not a dot method    
    var key;
    for(var i = 4; i < 6; ++i) {
    	key = 'Property' + i;     // Key - dynamically calculated
    	data[key] = i; // CORRECT !!!!
    }
    console.log(data); 
    // { Property1: 1, Property2: 2, Property3: 3, Property4: 4, Property5: 5 }
    
    for(var i = 6; i < 2000; ++i) {
    	key = 'Property' + i; // Key - dynamically calculated
    	data.key = i;         // WRONG !!!!!
    }
    console.log(data); 
    // { Property1: 1, Property2: 2, Property3: 3, 
    //   Property4: 4, Property5: 5, key: 1999 }

Catat masalah di akhir log konsol - 'kunci: 1999' alih-alih Properti6: 6, Properti7: 7, ........., Property1999: 1999 . Jadi cara terbaik untuk menambahkan properti yang dibuat secara dinamis adalah metode [braket].

SridharKritha
sumber
1

Cara yang bagus untuk mengakses dari nama string dinamis yang berisi objek (misalnya object.subobject.property)

function ReadValue(varname)
{
    var v=varname.split(".");
    var o=window;
    if(!v.length)
        return undefined;
    for(var i=0;i<v.length-1;i++)
        o=o[v[i]];
    return o[v[v.length-1]];
}

function AssignValue(varname,value)
{
    var v=varname.split(".");
    var o=window;
    if(!v.length)
        return;
    for(var i=0;i<v.length-1;i++)
        o=o[v[i]];
    o[v[v.length-1]]=value;
}

Contoh:

ReadValue("object.subobject.property");
WriteValue("object.subobject.property",5);

eval bekerja untuk nilai baca, tetapi nilai tulis sedikit lebih sulit.

Versi yang lebih maju (Buat subclass jika tidak ada, dan memungkinkan objek alih-alih variabel global)

function ReadValue(varname,o=window)
{
    if(typeof(varname)==="undefined" || typeof(o)==="undefined" || o===null)
        return undefined;
    var v=varname.split(".");
    if(!v.length)
        return undefined;
    for(var i=0;i<v.length-1;i++)
    {
        if(o[v[i]]===null || typeof(o[v[i]])==="undefined") 
            o[v[i]]={};
        o=o[v[i]];
    }
    if(typeof(o[v[v.length-1]])==="undefined")    
        return undefined;
    else    
        return o[v[v.length-1]];
}

function AssignValue(varname,value,o=window)
{
    if(typeof(varname)==="undefined" || typeof(o)==="undefined" || o===null)
        return;
    var v=varname.split(".");
    if(!v.length)
        return;
    for(var i=0;i<v.length-1;i++)
    {
        if(o[v[i]]===null || typeof(o[v[i]])==="undefined")
            o[v[i]]={};
        o=o[v[i]];
    }
    o[v[v.length-1]]=value;
}

Contoh:

ReadValue("object.subobject.property",o);
WriteValue("object.subobject.property",5,o);

Ini sama dengan o.object.subobject.property

hamboy75
sumber
1
persis apa yang saya cari, ini berguna untuk bereaksi this.setState ({dynamic property: value}) terima kasih!
Kevin Danikowski
0

Inilah cara saya memecahkan masalah.

var obj = {

};
var field = "someouter.someinner.someValue";
var value = 123;

function _addField( obj, field, value )
{
    // split the field into tokens
    var tokens = field.split( '.' );

    // if there's more than one token, this field is an object
    if( tokens.length > 1 )
    {
        var subObj = tokens[0];

        // define the object
        if( obj[ subObj ] !== undefined ) obj[ subObj ] = {};

        // call addfield again on the embedded object
        var firstDot = field.indexOf( '.' );
        _addField( obj[ subObj ], field.substr( firstDot + 1 ), value );

    }
    else
    {
        // no embedded objects, just field assignment
        obj[ field ] = value;
    }
}

_addField( obj, field, value );
_addField(obj, 'simpleString', 'string');

console.log( JSON.stringify( obj, null, 2 ) );

Menghasilkan objek berikut:

{
  "someouter": {
    "someinner": {
      "someValue": 123
    }
  },
  "simpleString": "string"
}
lewma
sumber
0

Ini dapat berguna jika campuran properti baru ditambahkan dalam runtime:

data = { ...data, newPropery: value}

Namun, operator penyebaran menggunakan salinan dangkal tetapi di sini kami menetapkan data untuk dirinya sendiri sehingga harus kehilangan apa-apa

Mohsen
sumber
-2

Cara mudah dan sempurna

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};

var newProperty = 'getThisFromUser';
data[newProperty] = 4;

console.log(data);

Jika Anda ingin menerapkannya pada array data (versi ES6 / TS)

const data = [
  { 'PropertyA': 1, 'PropertyB': 2, 'PropertyC': 3 },
  { 'PropertyA': 11, 'PropertyB': 22, 'PropertyC': 33 }
];

const newProperty = 'getThisFromUser';
data.map( (d) => d[newProperty] = 4 );

console.log(data);
Umesh
sumber
-14

Pastinya. Anggap saja sebagai kamus atau array asosiatif. Anda dapat menambahkannya kapan saja.

thedz
sumber
1
Hanya mengatakan itu tidak akan membantu.
Obinna Nwakwue