943

In JavaScript, I've created an object like so:

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

Is it possible to add further properties to this object after its initial creation if the properties name is not determined until run time? i.e.

var propName = 'Property' + someUserInput
//imagine someUserInput was 'Z', how can I now add a 'PropertyZ' property to 
//my object?
danronmoon
  • 3,814
  • 5
  • 34
  • 56
Lee D
  • 12,551
  • 8
  • 32
  • 34
  • See also [How to use a variable for a key in a JavaScript object literal?](https://stackoverflow.com/q/2274242/1048572) – Bergi Jan 18 '21 at 22:32
  • Using user input to manipulate keys in data structures is an antipattern at a best and a security hazard at worst. What are you [really trying to accomplish](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem/233676#233676) by doing this? – ggorlen May 18 '21 at 17:51

22 Answers22

1495

Yes.

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

data["PropertyD"] = 4;

// dialog box with 4 in it
alert(data.PropertyD);
alert(data["PropertyD"]);
H. Pauwelyn
  • 13,575
  • 26
  • 81
  • 144
Georg Schölly
  • 124,188
  • 49
  • 220
  • 267
  • 1
    I didn't know you could use that syntax. I'm still a newb in JavaScript, I'm used to seeing [] used for working with arrays and wouldn't have thought to try that. Thanks! – Lee D Jul 26 '09 at 09:36
  • 168
    @thedz: data.PropertyD needs to know the property name, which isn't dynamic enough. – Georg Schölly Jul 26 '09 at 09:54
  • 11
    +1 because this helped me. But I don't understand why an object properties is handled like an array. – Ron van der Heijden Mar 05 '13 at 11:56
  • 9
    @Bondye: That's part of the strange design of javascript. In this case `object["property"]` is not exactly the same as `array[4]`, the former wasn't created as a true array. – Georg Schölly Mar 05 '13 at 12:15
  • Georg has the right way to do it, but I prefer to see it in dot notation. Example: data.PropertyD = 4; – Justin Noel Apr 07 '13 at 17:01
  • Are there known issues with IE8? I'm trying to do something similar with no luck. I get `data[...]' is null or not an object`. – edhedges May 07 '13 at 20:53
  • 11
    Is it just me or does this post not answer the question while getting 195 upvotes? I thought it was asking how to define properties where the name is unknown until it is generated in the JavaScript code. – Qantas 94 Heavy Feb 22 '14 at 09:37
  • 40
    @Qantas: Let's say it doesn't answer it directly. But going from `data["PropertyD"]` to `data[function_to_get_property_name()]` seems trivial. – Georg Schölly Feb 24 '14 at 10:17
  • 1
    You can also start with an empty object, such as data = {}; and then add to it: data.PropertyA = 1; – David M Mar 25 '15 at 19:47
  • 2
    I think data[function_to_get_property_name()] clears things up and is worth adding to the answer :D – Andrew Aug 25 '15 at 19:46
  • linter is throwing the warning saying that "object access via a string literals is disallowed" any other way to fix this issue ? – Varun Oct 18 '16 at 18:25
  • Instead can we use Object.defineProperty(obj, prop, descriptor) ? – Varun Oct 18 '16 at 18:50
  • 1
    @Varun: if you have the string literal already, why not access the property using the dot-syntax? The purpose of `Object.defineProperty` is to add properties with special behaviour, e.g. not enumerable. Your problem does not seem to be about that at all. – Georg Schölly Oct 18 '16 at 21:39
  • @Georg: I don't have the string literal present. I am creating it on the fly. So when I created using this I got a linter warning. Can you please let me know if you have any other way to create dynamic property in javascript which should be effective and efficient – Varun Oct 19 '16 at 12:31
  • @Varun: The linter says you have a string literal in there. What's your code? Maybe it's best you create a new question so other people can chime in. – Georg Schölly Oct 19 '16 at 14:18
  • my code is similar to data["PropertyD"] = 4; I am creating propertyD and assigning the value thats it – Varun Oct 19 '16 at 14:39
  • 1
    @Varun: `"PropertyD"` is a string literal. Why not just use `data.PropertyD = 4`? If it is because you're using the object like a dictionary, maybe tell your linter to ignore this error. If that is not possible, maybe use a [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map). However, you should know that using objects as dictionaries is completely normal in javascript. – Georg Schölly Oct 19 '16 at 15:29
  • Even though marked as correct, this does not answer the actual question by the OP. – mukesh.kumar Apr 06 '20 at 08:02
  • Can this be done even when you declare `data` to be a `const`? – gen Apr 16 '20 at 10:46
  • If anyone faces an issue with ES lint complaining that using the dot operator should be avoided, please have a look at this solution https://stackoverflow.com/a/51200448/2353713 – Andy Oct 05 '20 at 20:19
  • I can't see how this answer has so many upvotes and is the accepted answer. The question asks how to add properties dynamically. In this case 'PropertyD' is hardcoded in. What is the user has input 'D', or any other value, and you want to add Property + 'D', as the question asks. You need to use ```let val = 'D';```, assume you get this from the user, and then ```let myObject = {[`Property${val}`]: 4};```. – Juan Pablo Mar 29 '23 at 07:09
  • TypeError: Cannot set properties of undefined – Khalil Al Hooti May 21 '23 at 14:28
295

ES6 for the win!

const b = 'B';
const c = 'C';

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

If you log data you get this:

{
  a: true,
  B: true,
  interpolated-C: true,
  B-C: true
}

This makes use of the new Computed Property syntax and Template Literals.

nhe
  • 157
  • 2
  • 9
Mauricio Soares
  • 3,452
  • 1
  • 17
  • 16
  • 2
    This is what I needed in the case where I wanted my code to be completely functional (as in, no imperative statements saying `obj[propname]`). Instead, I was able to use this with object spread syntax. – intcreator Feb 13 '18 at 05:41
  • 2
    It is not immediately obvious what this code snippet is doing to someone who hasn't seen or comprehended the new syntax. I would suggest an edit to display the output / expected properies with the 'a' const. –  Mar 20 '18 at 16:47
  • Personally, I think the ES5 way is a lot cleaner and easier to understand: `var a = {}; a["dynamic-" + prop] = true;` – Jack G Apr 03 '18 at 16:39
  • 1
    @JackGiffin in some cases yes, but when working with immutable structures, this syntax can be very handy, since the approach you showed is mutating `a`. (Specially when using packages like redux) – Mauricio Soares Aug 10 '18 at 09:35
  • Thank you so much! Had no idea you could use [...] by itself! Always thought (thank you new ES6 ;-) ) you had to evoke the array first like x[...]. – Pedro Ferreira Feb 25 '19 at 09:51
  • 1
    This is the right answer which really helps to build it DYNAMICALLY, thx! – Maxime Culea Aug 23 '21 at 09:55
96

Yes it is possible. Assuming:

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

Either:

data[propertyName] = propertyValue;

or

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

The first method is preferred. eval() has the obvious security concerns if you're using values supplied by the user so don't use it if you can avoid it but it's worth knowing it exists and what it can do.

You can reference this with:

alert(data.someProperty);

or

data(data["someProperty"]);

or

alert(data[propertyName]);
cletus
  • 616,129
  • 168
  • 910
  • 942
  • 63
    Using eval is really dangerous. – Georg Schölly Jul 26 '09 at 09:29
  • @GeorgSchölly True. – Obinna Nwakwue Aug 28 '16 at 14:47
  • 1
    **Note** (in case someone runs into the same issue as I did): For normal objects this works fine. But I had to add some property to a jQuery UI object to keep track of a list of items. In that case, the property was lost if added this way because jQuery always creates a copy. Here you need to use [jQuery.extend()](https://api.jquery.com/jquery.extend/). – Matt Jul 07 '17 at 11:03
  • I like to add to my previous comment - even that didn't work in my case. So I ended up using the `$("#mySelector").data("propertyname", myvalue);` to set, and `var myValue=$("#mySelector").data("propertyname");` to get the value back. Even complex objects (lists, arrays ...) can be added this way. – Matt Jul 07 '17 at 12:28
78

ES6 introduces computed property names, which allows you to do

let a = 'key'
let myObj = {[a]: 10};
// output will be {key:10}
Rusty
  • 4,138
  • 3
  • 37
  • 45
70

I know that the question is answered perfectly, but I also found another way to add new properties and wanted to share it with you:

You can use the function Object.defineProperty()

Found on Mozilla Developer Network

Example:

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
  • 3,082
  • 2
  • 25
  • 31
  • 5
    Pros and cons of this method? – Trevor Jan 14 '14 at 21:06
  • 6
    @Trevor: Total configurability and ability to add getters and setters; also, ability to add multiple properties at once with [`defineProperties`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties) (plural). – rvighne Aug 10 '14 at 01:08
  • @Thielicious `Object.defineProperty` isn’t meant to be the easy convenience tool, but the one with the fine-grained control. If you don’t need that additional control, it’s not the right tool to choose. – kleinfreund Sep 06 '17 at 09:00
  • `Object.defineProperty(obj, prop, valueDescriptor)` is a lot slower and harder for V8 to optimize than simply doing `obj[prop] = value`; – Jack G Apr 03 '18 at 16:37
  • This is the best solution. Dynamically creating entries with `obj[prop] = value` will give you headaches when you're trying to parse your object with functions like `Object.getOwnPropertyNames` – Grumbunks May 23 '21 at 10:02
23

Here, using your 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
  • 15,176
  • 9
  • 43
  • 49
21

You can add as many more properties as you like simply by using the dot notation:

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

or:

data[newattribute] = somevalue

for dynamic keys.

Gabriel Hurley
  • 39,690
  • 13
  • 62
  • 88
19

in addition to all the previous answers, and in case you're wondering how we're going to write dynamic property names in the Future using Computed Property Names ( ECMAScript 6 ), here's how:

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

personIndex[ personId ]; // "John Doe"

reference: Understanding ECMAScript 6 - Nickolas Zakas

Anas Nakawa
  • 1,977
  • 1
  • 23
  • 42
15

Just an addition to abeing's answer above. You can define a function to encapsulate the complexity of defineProperty as mentioned below.

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

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

Sarvesh
  • 637
  • 9
  • 17
13

You can add properties dynamically using some of the options below:

In you example:

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

You can define a property with a dynamic value in the next two ways:

data.key = value;

or

data['key'] = value;

Even more..if your key is also dynamic you can define using the Object class with:

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

where data is your object, key is the variable to store the key name and value is the variable to store the value.

I hope this helps!

morewry
  • 4,320
  • 3
  • 35
  • 35
Fabricio
  • 3,248
  • 2
  • 16
  • 22
13

I know there are several answers to this post already, but I haven't seen one wherein there are multiple properties and they are within an array. And this solution by the way is for ES6.

For illustration, let's say we have an array named person with objects inside:

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

So, you can add a property with corresponding value. Let's say we want to add a Language with a default value of EN.

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

The Person array now would become like this:

Person = [{id:1, Name: "John", Language:"EN"}, 
{id:2, Name: "Susan", Language:"EN"}, {id:3, Name: "Jet", Language:"EN"}]
Edper
  • 9,144
  • 1
  • 27
  • 46
  • You're not actually adding properties to an object, you're creating a new object with the old object's properties (via spread operator) and the new props as well. – Ed Orsi Nov 10 '17 at 20:22
  • 3
    You're right on that it should have been `Person = Person.map(code here)`. But the point is you can add property to an existing object easily with `ES6`. – Edper Nov 10 '17 at 23:27
13

It can be useful if mixed new property add in runtime:

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

However, spread operator use shallow copy but here we assign data to itself so should lose nothing

Mohsen
  • 4,049
  • 1
  • 31
  • 31
12

I was looking for a solution where I can use dynamic key-names inside the object declaration (without using ES6 features like ... or [key]: value)

Here's what I came up with:

var obj = (obj = {}, obj[field] = 123, obj)

It looks a little bit complex at first, but it's really simple. We use the Comma Operator to run three commands in a row:

  1. obj = {}: creates a new object and assigns it to the variable obj
  2. obj[field] = 123: adds a computed property name to obj
  3. obj: use the obj variable as the result of the parentheses/comma list

This syntax can be used inside a function parameter without the requirement to explictely declare the obj variable:

// The test function to see the result.
function showObject(obj) {
    console.log(obj);
}

// My dynamic field name.
var field = "myDynamicField";

// Call the function with our dynamic object.
showObject( (obj = {}, obj[field] = 123, obj) );

/*
Output:

{
  "myDynamicField": true
}
*/

Some variations

"strict mode" workaround:

The above code does not work in strict mode because the variable "obj" is not declared.

// This gives the same result, but declares the global variable `this.obj`!
showObject( (this.obj = {}, obj[field] = 123, obj) );

ES2015 code using computed property names in initializer:

// Works in most browsers, same result as the other functions.
showObject( {[field] = 123} );

This solution works in all modern browsers (but not in IE, if I need to mention that)

Super hacky way using JSON.parse():

// Create a JSON string that is parsed instantly. Not recommended in most cases.
showObject( JSON.parse( '{"' + field +'":123}') );
// read: showObject( JSON.parse( '{"myDynamicfield":123}') );

Allows special characters in keys

Note that you can also use spaces and other special characters inside computed property names (and also in JSON.parse).

var field = 'my dynamic field :)';
showObject( {[field] = 123} );
// result: { "my dynamic field :)": 123 }

Those fields cannot be accessed using a dot (obj.my dynamic field :) is obviously syntactically invalid), but only via the bracket-notation, i.e., obj['my dynamic field :)'] returns 123

Philipp
  • 10,240
  • 8
  • 59
  • 71
7

The simplest and most portable way is.

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

Based on #abeing answer!

Sydwell
  • 4,954
  • 1
  • 33
  • 36
5

Be careful while adding a property to the existing object using .(dot) method.

(.dot) method of adding a property to the object should only be used if you know the 'key' beforehand otherwise use the [bracket] method.

Example:

   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 }

Note the problem in the end of console log - 'key: 1999' instead of Property6: 6, Property7: 7,.........,Property1999: 1999. So the best way of adding dynamically created property is the [bracket] method.

Eugen Konkov
  • 22,193
  • 17
  • 108
  • 158
SridharKritha
  • 8,481
  • 2
  • 52
  • 43
4

A nice way to access from dynamic string names that contain objects (for example 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;
}

Example:

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

eval works for read value, but write value is a bit harder.

A more advanced version (Create subclasses if they dont exists, and allows objects instead of global variables)

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

Example:

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

This is the same that o.object.subobject.property

Hamboy75
  • 938
  • 1
  • 11
  • 22
2

Here's how I solved the problem.

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

Generates the following object:

{
  "someouter": {
    "someinner": {
      "someValue": 123
    }
  },
  "simpleString": "string"
}
lewma
  • 181
  • 1
  • 5
2

Yes it is possible. I have achieved using below implementation. for that I am getting array in response which I want in an object as list of attributes.

response = {
  "equityMonths": [
    {
      "id": 1,
      "month": "JANUARY",
      "isEligible": false
    },
    {
      "id": 2,
      "month": "FEBRUARY",
      "isEligible": true
    },
    {
      "id": 3,
      "month": "MARCH",
      "isEligible": false
    },
    {
      "id": 4,
      "month": "APRIL",
      "isEligible": true
    },
    {
      "id": 5,
      "month": "MAY",
      "isEligible": false
    },
    {
      "id": 6,
      "month": "JUNE",
      "isEligible": true
    },
    {
      "id": 7,
      "month": "JULY",
      "isEligible": true
    },
    {
      "id": 8,
      "month": "AUGUST",
      "isEligible": false
    },
    {
      "id": 9,
      "month": "SEPTEMBER",
      "isEligible": true
    },
    {
      "id": 10,
      "month": "OCTOBER",
      "isEligible": false
    },
    {
      "id": 11,
      "month": "NOVEMBER",
      "isEligible": true
    },
    {
      "id": 12,
      "month": "DECEMBER",
      "isEligible": false
    }
  ]
}

here, I want equityMonths as an object and Jan to Dec it's key and isEligible as value. for that we have to use Object class's defineProperty() method which allows to add dynamic property into objects.

code for adding property dynamically to the object.

let equityMonth = new Object();

response.equityMonths.forEach(element => {
    Object.defineProperty(equityMonth, element['month'], {
       value: element['isEligible'],
       writable: true,
       enumerable: true,
       configurable: true
    });
});
console.log("DATA : " + JSON.stringify(equityMonth));

in above code we have array of equityMonths which we have converted as property into the object.

output:

DATA : {"JANUARY":false,"FEBRUARY":true,"MARCH":false,"APRIL":true,"MAY":false,"JUNE":true,"JULY":true,"AUGUST":false,"SEPTEMBER":true,"OCTOBER":false,"NOVEMBER":true,"DECEMBER":false}
Sandeep Patel
  • 2,069
  • 2
  • 14
  • 20
2

You could do something like this

let myObj = {
  propertyA: 1,
  propertyB: 2,
  propertyC: 3,
}

// Declaring val here, could get from the user
let val = 'D';
myObj = {...myObj, [`property${val}`]: 4}
Juan Pablo
  • 338
  • 2
  • 17
1

Simplest way to add data dynamically to js object.

 // Create an object
 const data = {};
     
 // Add properties to it with a key and value
 data['key'] = value;
Shah Fahad
  • 61
  • 3
-1

A perfect easy way

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

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

console.log(data);

If you want to apply it on an array of data (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
  • 2,704
  • 19
  • 21
-17

Definitely. Think of it as a dictionary or associative array. You can add to it at any point.

thedz
  • 5,496
  • 3
  • 25
  • 29