È possibile aggiungere proprietà con nome dinamico all'oggetto JavaScript?


746

In JavaScript, ho creato un oggetto in questo modo:

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

È possibile aggiungere ulteriori proprietà a questo oggetto dopo la sua creazione iniziale se il nome delle proprietà non viene determinato fino al runtime? vale a dire

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

Risposte:


1212

Sì.

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

data["PropertyD"] = 4;

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


142
@thedz: data.PropertyD deve conoscere il nome della proprietà, che non è abbastanza dinamico.
Georg Schölly,

6
+1 perché questo mi ha aiutato. Ma non capisco perché le proprietà di un oggetto siano gestite come una matrice.
Ron van der Heijden,

9
@Bondye: fa parte dello strano design di javascript. In questo caso object["property"]non è esattamente lo stesso array[4], il primo non è stato creato come un vero array.
Georg Schölly,

5
Sono solo io o questo post non risponde alla domanda mentre riceve 195 voti? Ho pensato che stesse chiedendo come definire le proprietà in cui il nome è sconosciuto fino a quando non viene generato nel codice JavaScript.
Qantas 94 Pesante,

20
@Qantas: diciamo che non risponde direttamente. Ma passare da data["PropertyD"]a data[function_to_get_property_name()]sembra banale.
Georg Schölly,

154

ES6 per la vittoria!

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

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

Se accedi dataottieni questo:

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

Questo utilizza la nuova sintassi della proprietà calcolata e i template letterali .


1
Questo è ciò di cui avevo bisogno nel caso in cui volessi che il mio codice fosse completamente funzionale (come in, nessuna affermazione imperativa che diceva obj[propname]). Invece, sono stato in grado di utilizzare questo con la sintassi di diffusione degli oggetti.
creatore

2
Non è immediatamente ovvio cosa stia facendo questo frammento di codice a qualcuno che non ha visto o compreso la nuova sintassi. Suggerirei una modifica per visualizzare le proprietà di output / previste con la const "a".

Personalmente, penso che il modo ES5 sia molto più pulito e facile da capire:var a = {}; a["dynamic-" + prop] = true;
Jack Giffin,

1
@JackGiffin in alcuni casi sì, ma quando si lavora con strutture immutabili, questa sintassi può essere molto utile, poiché l'approccio che hai mostrato è mutante a. (Specialmente quando si usano pacchetti come redux)
Mauricio Soares,

3
Questo è semplicemente fantastico {... state, [prop]: val}
Xipo,

87

Sì, è possibile. assumendo:

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

O:

data[propertyName] = propertyValue;

o

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

Il primo metodo è preferito. eval () ha le ovvie preoccupazioni di sicurezza se stai usando valori forniti dall'utente, quindi non usarlo se puoi evitarlo ma vale la pena sapere che esiste e cosa può fare.

Puoi fare riferimento a questo con:

alert(data.someProperty);

o

data(data["someProperty"]);

o

alert(data[propertyName]);

40
L'uso di eval è davvero pericoloso.
Georg Schölly,

10
Per non parlare lento.
Eamon Nerbonne,

@ GeorgSchölly True.
Obinna Nwakwue,

1
Nota (nel caso in cui qualcuno riscontri lo stesso problema che ho fatto io): per oggetti normali questo funziona bene. Ma ho dovuto aggiungere alcune proprietà a un oggetto dell'interfaccia utente jQuery per tenere traccia di un elenco di elementi. In tal caso, la proprietà andava persa se aggiunta in questo modo perché jQuery crea sempre una copia. Qui devi usare jQuery.extend () .
Matt

Mi piace aggiungere al mio commento precedente, anche se non ha funzionato nel mio caso. Così ho finito per usare il $("#mySelector").data("propertyname", myvalue);set e var myValue=$("#mySelector").data("propertyname");per riavere il valore. Anche oggetti complessi (elenchi, matrici ...) possono essere aggiunti in questo modo.
Matt

61

So che la domanda ha una risposta perfetta, ma ho anche trovato un altro modo per aggiungere nuove proprietà e volevo condividerla con te:

Puoi usare la funzione Object.defineProperty()

Trovato su Mozilla Developer Network

Esempio:

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

4
Pro e contro di questo metodo?
Trevor,

6
@Trevor: totale configurabilità e possibilità di aggiungere getter e setter; inoltre, possibilità di aggiungere più proprietà contemporaneamente con defineProperties(plurale).
rvighne,

@Thielicious Object.definePropertynon è pensato per essere lo strumento di praticità semplice, ma quello con il controllo a grana fine. Se non hai bisogno di quel controllo aggiuntivo, non è lo strumento giusto da scegliere.
Kleinfreund,

Object.defineProperty(obj, prop, valueDescriptor)è molto più lento e difficile da ottimizzare per V8 rispetto al semplice fare obj[prop] = value;
Jack Giffin,

27

ES6 introduce nomi di proprietà calcolati, che consentono di farlo

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

23

Qui, usando la tua notazione:

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'

18

Puoi aggiungere quante più proprietà desideri semplicemente usando la notazione punto:

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

oppure :

data[newattribute] = somevalue

per chiavi dinamiche.


4
se il nome della proprietà non viene determinato fino al runtime ", quindi non funzionerà se non si utilizza eval, che non è una buona opzione
Marc Gravell

1
oppure usa la [] sintassi ... data [somevar] = somevalue
Gabriel Hurley,

17

oltre a tutte le risposte precedenti, e nel caso ti stia chiedendo come scriveremo nomi di proprietà dinamici in futuro usando Nomi di proprietà calcolati (ECMAScript 6), ecco come:

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

personIndex[ personId ]; // "John Doe"

riferimento: Capire ECMAScript 6 - Nickolas Zakas


11

Solo un'aggiunta alla risposta di abeing sopra. È possibile definire una funzione per incapsulare la complessità di defineProperty come indicato di seguito.

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

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


9

È possibile aggiungere proprietà in modo dinamico utilizzando alcune delle opzioni seguenti:

Nel tuo esempio:

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

È possibile definire una proprietà con un valore dinamico nei due modi seguenti:

data.key = value;

o

data['key'] = value;

Ancora di più..se anche la tua chiave è dinamica puoi definire usando la classe Object con:

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

dove i dati sono il tuo oggetto, chiave è la variabile per memorizzare il nome della chiave e valore è la variabile per memorizzare il valore.

Spero che questo possa essere d'aiuto!


8

So che ci sono già diverse risposte a questo post, ma non ne ho visto una in cui ci sono più proprietà e si trovano all'interno di un array. E questa soluzione è per ES6.

Per esempio, supponiamo di avere un array chiamato persona con oggetti all'interno:

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

Quindi, puoi aggiungere una proprietà con il valore corrispondente. Diciamo che vogliamo aggiungere una lingua con un valore predefinito di EN .

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

L' array Person ora diventerebbe così:

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

In realtà non stai aggiungendo proprietà a un oggetto, stai creando un nuovo oggetto con le proprietà dell'oggetto vecchio (tramite l'operatore spread) e anche i nuovi oggetti di scena.
Ed Orsi,

3
Hai ragione sul fatto che avrebbe dovuto essere Person = Person.map(code here). Ma il punto è che puoi aggiungere facilmente proprietà a un oggetto esistente ES6.
Edper,

5

Il modo più semplice e portatile è.

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

Basato sulla risposta #abeing!


3

Prestare attenzione durante l'aggiunta di una proprietà all'oggetto esistente utilizzando il metodo (punto) .

Il metodo (.dot) per aggiungere una proprietà all'oggetto deve essere usato solo se si conosce in anticipo la 'chiave', altrimenti utilizzare il metodo [parentesi] .

Esempio:

   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 }

Notare il problema alla fine del registro della console: 'chiave: 1999' invece di Proprietà6: 6, Proprietà7: 7, ........., Proprietà 1999: 1999 . Quindi il modo migliore per aggiungere proprietà create dinamicamente è il metodo [parentesi].


1

Un buon modo per accedere da nomi di stringhe dinamiche che contengono oggetti (ad esempio 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;
}

Esempio:

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

eval funziona per il valore di lettura, ma il valore di scrittura è un po 'più difficile.

Una versione più avanzata (Crea sottoclassi se non esistono e consente oggetti anziché variabili globali)

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

Esempio:

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

Questo è lo stesso di o.object.subobject.property


1
esattamente quello che stavo cercando, questo è utile per reagire this.setState ({proprietà dinamica: valore}) grazie!
Kevin Danikowski il

0

Ecco come ho risolto il problema.

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

Genera il seguente oggetto:

{
  "someouter": {
    "someinner": {
      "someValue": 123
    }
  },
  "simpleString": "string"
}

0

Può essere utile se nel runtime vengono aggiunte nuove proprietà miste:

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

Tuttavia, l'operatore di diffusione utilizza copia superficiale, ma qui assegniamo i dati a se stesso, quindi non dovremmo perdere nulla


-2

Un modo semplice perfetto

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

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

console.log(data);

Se si desidera applicarlo su una matrice di dati (versione 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);

-14

Decisamente. Pensalo come un dizionario o un array associativo. Puoi aggiungere ad esso in qualsiasi momento.


1
Dire solo che non aiuterà.
Obinna Nwakwue,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.