Ist es möglich, dem JavaScript-Objekt dynamisch benannte Eigenschaften hinzuzufügen?

745

In JavaScript habe ich ein Objekt wie folgt erstellt:

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

Ist es möglich, diesem Objekt nach seiner ersten Erstellung weitere Eigenschaften hinzuzufügen, wenn der Name der Eigenschaft erst zur Laufzeit festgelegt wird? dh

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

Antworten:

1211

Ja.

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
quelle
142
@thedz: data.PropertyD muss den Eigenschaftsnamen kennen, der nicht dynamisch genug ist.
Georg Schölly
6
+1 weil mir das geholfen hat. Aber ich verstehe nicht, warum Objekteigenschaften wie ein Array behandelt werden.
Ron van der Heijden
9
@ Bondye: Das ist Teil des seltsamen Designs von Javascript. In diesem Fall object["property"]ist dies nicht genau das Gleiche wie array[4], das erstere wurde nicht als echtes Array erstellt.
Georg Schölly
5
Ist es nur ich oder beantwortet dieser Beitrag die Frage nicht, während er 195 Upvotes erhält? Ich dachte, es wurde gefragt, wie Eigenschaften definiert werden sollen, bei denen der Name unbekannt ist, bis er im JavaScript-Code generiert wird.
Qantas 94 Heavy
20
@Qantas: Nehmen wir an, es antwortet nicht direkt. Aber von data["PropertyD"]zu gehen data[function_to_get_property_name()]scheint trivial.
Georg Schölly
154

ES6 für den Sieg!

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

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

Wenn Sie sich anmelden, erhalten dataSie Folgendes:

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

Dies nutzt die neue Syntax für berechnete Eigenschaften und Vorlagenliterale .

Mauricio Soares
quelle
1
Dies ist das, was ich für den Fall brauchte, dass mein Code vollständig funktionsfähig sein sollte (wie in, keine zwingenden Aussagen obj[propname]). Stattdessen konnte ich dies mit der Objektverbreitungssyntax verwenden.
Intcreator
2
Es ist nicht sofort ersichtlich, was dieses Codefragment mit jemandem macht, der die neue Syntax nicht gesehen oder verstanden hat. Ich würde eine Bearbeitung vorschlagen, um die Ausgabe / erwarteten Eigenschaften mit der Konstante 'a' anzuzeigen.
Persönlich denke ich, dass der ES5-Weg viel sauberer und leichter zu verstehen ist:var a = {}; a["dynamic-" + prop] = true;
Jack Giffin
1
@ JackGiffin in einigen Fällen ja, aber wenn Sie mit unveränderlichen Strukturen arbeiten, kann diese Syntax sehr praktisch sein, da der von Ihnen gezeigte Ansatz mutiert a. (Speziell bei Verwendung von Paketen wie Redux)
Mauricio Soares
3
Das ist einfach toll {... state, [prop]: val}
Xipo
87

Ja, es ist möglich. Angenommen:

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

Entweder:

data[propertyName] = propertyValue;

oder

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

Die erste Methode ist bevorzugt. eval () hat die offensichtlichen Sicherheitsbedenken, wenn Sie vom Benutzer bereitgestellte Werte verwenden. Verwenden Sie sie daher nicht, wenn Sie sie vermeiden können, aber es lohnt sich zu wissen, dass sie vorhanden sind und was sie tun können.

Sie können dies referenzieren mit:

alert(data.someProperty);

oder

data(data["someProperty"]);

oder

alert(data[propertyName]);
Cletus
quelle
40
Die Verwendung von eval ist wirklich gefährlich.
Georg Schölly
10
Ganz zu schweigen von langsam.
Eamon Nerbonne
@ GeorgSchölly Richtig.
Obinna Nwakwue
1
Hinweis (falls jemand auf dasselbe Problem stößt wie ich): Bei normalen Objekten funktioniert dies einwandfrei. Aber ich musste einem jQuery-UI-Objekt eine Eigenschaft hinzufügen, um eine Liste von Elementen zu verfolgen. In diesem Fall ging die Eigenschaft verloren, wenn sie auf diese Weise hinzugefügt wurde, da jQuery immer eine Kopie erstellt. Hier müssen Sie jQuery.extend () verwenden .
Matt
Ich möchte meinen vorherigen Kommentar ergänzen - auch das hat in meinem Fall nicht funktioniert. Also habe ich das verwendet, um $("#mySelector").data("propertyname", myvalue);zu setzen und var myValue=$("#mySelector").data("propertyname");den Wert zurückzubekommen. Auf diese Weise können auch komplexe Objekte (Listen, Arrays ...) hinzugefügt werden.
Matt
61

Ich weiß, dass die Frage perfekt beantwortet ist, aber ich habe auch einen anderen Weg gefunden, um neue Eigenschaften hinzuzufügen, und wollte sie mit Ihnen teilen:

Sie können die Funktion verwenden Object.defineProperty()

Gefunden im Mozilla Developer Network

Beispiel:

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
quelle
4
Vor- und Nachteile dieser Methode?
Trevor
6
@Trevor: Vollständige Konfigurierbarkeit und Fähigkeit, Getter und Setter hinzuzufügen; auch die Fähigkeit, mehrere Eigenschaften gleichzeitig mit defineProperties(Plural) hinzuzufügen .
Rvighne
@Thielicious Object.definePropertysoll nicht das einfache Komfortwerkzeug sein, sondern das mit der feinkörnigen Steuerung. Wenn Sie diese zusätzliche Steuerung nicht benötigen, ist sie nicht das richtige Werkzeug.
Kleinfreund
Object.defineProperty(obj, prop, valueDescriptor)ist für V8 viel langsamer und schwieriger zu optimieren als nur zu tun obj[prop] = value;
Jack Giffin
27

ES6 führt berechnete Eigenschaftsnamen ein, mit denen Sie dies tun können

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

Hier mit Ihrer Notation:

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
quelle
18

Sie können beliebig viele Eigenschaften hinzufügen, indem Sie einfach die Punktnotation verwenden:

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

oder :

data[newattribute] = somevalue

für dynamische Tasten.

Gabriel Hurley
quelle
4
Wenn der Name der Eigenschaft erst zur Laufzeit festgelegt wird "- das funktioniert nur, wenn Sie eval verwenden, was keine gute Option ist
Marc Gravell
1
oder verwenden Sie die [] Syntax ... data [somevar] = somevalue
Gabriel Hurley
17

Zusätzlich zu allen vorherigen Antworten und für den Fall, dass Sie sich fragen, wie wir in Zukunft dynamische Eigenschaftsnamen mithilfe von berechneten Eigenschaftsnamen (ECMAScript 6) schreiben werden, gehen Sie wie folgt vor:

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

personIndex[ personId ]; // "John Doe"

Referenz: ECMAScript 6 verstehen - Nickolas Zakas

Anas Nakawa
quelle
11

Nur eine Ergänzung zu Abes Antwort oben. Sie können eine Funktion definieren, um die Komplexität von defineProperty wie unten beschrieben zu kapseln.

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

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

Sarvesh
quelle
9

Sie können Eigenschaften dynamisch hinzufügen, indem Sie einige der folgenden Optionen verwenden:

In Ihrem Beispiel:

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

Sie können eine Eigenschaft mit einem dynamischen Wert auf die folgenden zwei Arten definieren:

data.key = value;

oder

data['key'] = value;

Noch mehr ... Wenn Ihr Schlüssel auch dynamisch ist, können Sie ihn mithilfe der Object-Klasse definieren mit:

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

Wenn Daten Ihr Objekt sind, ist der Schlüssel die Variable zum Speichern des Schlüsselnamens und der Wert die Variable zum Speichern des Werts.

Ich hoffe das hilft!

Fabricio
quelle
8

Ich weiß, dass es bereits mehrere Antworten auf diesen Beitrag gibt, aber ich habe keine gesehen, bei der es mehrere Eigenschaften gibt und die sich in einem Array befinden. Und diese Lösung ist übrigens für ES6.

Nehmen wir zur Veranschaulichung an, wir haben ein Array mit dem Namen person mit Objekten darin:

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

Sie können also eine Eigenschaft mit dem entsprechenden Wert hinzufügen. Angenommen, wir möchten eine Sprache mit dem Standardwert EN hinzufügen .

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

Das Personenarray würde nun folgendermaßen aussehen:

Person = [{id:1, Name: "John", Language:"EN"}, 
{id:2, Name: "Susan", Language:"EN"}, {id:3, Name: "Jet", Language:"EN"}]
Edper
quelle
Sie fügen einem Objekt keine Eigenschaften hinzu, sondern erstellen ein neues Objekt mit den Eigenschaften des alten Objekts (über den Spread-Operator) und den neuen Requisiten.
Ed Orsi
3
Sie haben Recht damit, dass es hätte sein sollen Person = Person.map(code here). Der Punkt ist jedoch, dass Sie einem vorhandenen Objekt auf einfache Weise Eigenschaften hinzufügen können ES6.
Edper
5

Der einfachste und tragbarste Weg ist.

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

Basierend auf #abeing Antwort!

Sydwell
quelle
3

Seien Sie vorsichtig, wenn Sie dem vorhandenen Objekt mit der Methode. (Punkt) eine Eigenschaft hinzufügen .

(DOT) Methode eine Eigenschaft zum Objekt der Zugabe sollte nur verwendet werden , wenn Sie wissen , den ‚Schlüssel‘ im Voraus ansonsten verwenden Sie die [Konsole] Methode.

Beispiel:

   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 }

Beachten Sie das Problem am Ende des Konsolenprotokolls - 'key: 1999' anstelle von Property6: 6, Property7: 7, ........., Property1999: 1999 . Der beste Weg, dynamisch erstellte Eigenschaften hinzuzufügen, ist die [Klammer] -Methode.

SridharKritha
quelle
1

Eine gute Möglichkeit, über dynamische Zeichenfolgennamen zuzugreifen, die Objekte enthalten (z. B. 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;
}

Beispiel:

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

eval funktioniert für den Lesewert, aber der Schreibwert ist etwas schwieriger.

Eine erweiterte Version (Erstellen Sie Unterklassen, wenn diese nicht vorhanden sind, und lassen Sie Objekte anstelle globaler Variablen zu.)

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

Beispiel:

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

Dies ist das gleiche wie o.object.subobject.property

hamboy75
quelle
1
genau das, wonach ich gesucht habe, dies ist nützlich, um auf this.setState ({dynamic property: value}) zu reagieren. Danke!
Kevin Danikowski
0

So habe ich das Problem gelöst.

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

Erzeugt das folgende Objekt:

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

Es kann nützlich sein, wenn gemischte neue Eigenschaften zur Laufzeit hinzugefügt werden:

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

Der Spread-Operator verwendet jedoch eine flache Kopie, aber hier weisen wir uns selbst Daten zu, damit nichts verloren geht

Mohsen
quelle
-2

Ein perfekter einfacher Weg

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

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

console.log(data);

Wenn Sie es auf ein Datenarray anwenden möchten (ES6 / TS-Version)

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
quelle
-14

Bestimmt. Stellen Sie sich das als Wörterbuch oder assoziatives Array vor. Sie können es jederzeit hinzufügen.

thedz
quelle
1
Nur zu sagen, das wird nicht helfen.
Obinna Nwakwue