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?
Yes.
var data = {
'PropertyA': 1,
'PropertyB': 2,
'PropertyC': 3
};
data["PropertyD"] = 4;
// dialog box with 4 in it
alert(data.PropertyD);
alert(data["PropertyD"]);
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.
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]);
ES6 introduces computed property names, which allows you to do
let a = 'key'
let myObj = {[a]: 10};
// output will be {key:10}
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
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'
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.
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
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
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"}]
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
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!
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:
obj = {}: creates a new object and assigns it to the variable obj
obj[field] = 123: adds a computed property name to obj
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
The simplest and most portable way is.
var varFieldName = "good";
var ob = {};
Object.defineProperty(ob, varFieldName , { value: "Fresh Value" });
Based on #abeing answer!
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.
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
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"
}
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}
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);
Definitely. Think of it as a dictionary or associative array. You can add to it at any point.
Hello I am struggling with arrays in JavaScript/NodeJS.
Basically, here is my code:
let arr = new Array();
arr = {
"Username" : var1,
"Console" : var2,
"Pseudo" : var3,
}
console.log(arr);
var1, 2 and 3 contains my data that is changing each time.
Let's consider for our first case:
var1 is "Johnson"
var2 is "ps4"
var3 is "Johnson46"
The code above would display the following:
{ Username: 'Johnson', Console: 'ps4', Pseudo: 'Johnson46' }
Now if the data in var1, var2, and var3 change, it will replace the array's content with new data. So if var1 = "Dave", var2 = "xbox" and var3 = "Dave78", it will replace the current array and display:
{ Username: 'Dave', Console: 'xbox', Pseudo: 'Dave78' }
But instead I would like my code to print the follwing:
{ Username: 'Johnson', Console: 'ps4', Pseudo: 'Johnson46' }
{ Username: 'Dave', Console: 'xbox', Pseudo: 'Dave78' }
See? Without overriding the array, just adding my data in succession. "line by line" or "step by step" if you prefer, sorry I don't really know how to say that.
You must push your objects to the array instead modifying it
let arr = new Array();
object1 = {
"Username" : "Jhon",
"Console" : "xbox",
"Pseudo" : "asd",
}
arr.push(object1)
object2 = {
"Username" : "Doe",
"Console" : "ps4",
"Pseudo" : "efg",
}
arr.push(object2)
console.log(arr);
I am going for more of a theoretical route. Maybe it will clear some of your doubt maybe it will not.
First of all, on a side note, Even though Array is technically an object but {..} is the notation for objects not arrays. If there is a object like {'0':.., '1':.., '2':..} and it has a length property then is called an array like object (thanks #Alnitak)
Now, when you are declaring an object, and adding values from variables if you're referencing an immutable object like string, number it will reference the value itself. If you're referencing say an object it will hold the object's reference and if you change the object it will change too.
For example:
const obj = {'a':'b'};
const x = {
m: obj.a
}
console.log(x);
obj.a = 'c';
console.log(x);
This will print,
{ m: 'b' }
{ m: 'b' }
But when your code is:
const obj = {'a':'b'};
const x = {
m: obj //referencing obj
}
console.log(x);
obj.a = 'c';
console.log(x);
It will print:
{ m: { a: 'b' } }
{ m: { a: 'c' } }
So, if you want your code to just print it then you can reference an object in your variable.
Can anybody help me I am new to javascript. I am not able to understand the below line of code. I spend hours to debug this code but I am not able to rectify.
var data = [
{"name":"123123123123"},
{"name":"123123123124"},
{"name":"123123123125"},
{"name":"123123123126"}
];
var x1 = {}
var basicS = {
"question":[]
}
data.forEach(function(val,i){
x1[val.name]=basicS;
});
console.log(x1);
data.forEach(function(val,i){
x1[val.name].question.push('insert');
});
console.log(x1);
Output:
{
123123123123:{
question:[
0:"insert"
1:"insert"
2:"insert"
3:"insert"
]
},
123123123124:{
question:[
0:"insert"
1:"insert"
2:"insert"
3:"insert"
]
},
123123123125:{
question:[
0:"insert"
1:"insert"
2:"insert"
3:"insert"
]
},
123123123126:{
question:[
0:"insert"
1:"insert"
2:"insert"
3:"insert"
]
}
}
Expected Output should be:
{
123123123123:{
question:[
0:"insert"
]
},
123123123124:{
question:[
0:"insert"
]
},
123123123125:{
question:[
0:"insert"
]
},
123123123126:{
question:[
0:"insert"
]
}
}
Not able to understand from where four values are inserted inside the each question array while i am inserting only one in each question
array object.
Is there any alternative to solve this type of prblem.
Please help me out. I am totally confused. Thanks in advance.
You may want to create multiple objects:
data.forEach(function(val,i){
x1[val.name]={
"question":[]
};
});
Or both loops in one O(n) instead of O(2n):
data.forEach(function(val,i){
(x1[val.name]=x1[val.name] || {question:[]}).question.push(val);
});
This is happening because every value in x1 is referencing the same basicS array. So you are pushing insert into that array four times.
To avoid this, give each item in x1 a new array:
var data = [
{"name":"123123123123"},
{"name":"123123123124"},
{"name":"123123123125"},
{"name":"123123123126"}
];
var x1 = {}
data.forEach(function(val,i){
x1[val.name]= { "question": [] };
});
data.forEach(function(val,i){
x1[val.name].question.push('insert');
});
console.log(x1);
Or, depending on what you're ultimately trying to do, you could just populate the arrays with their initial value instead of looping twice:
var data = [
{"name":"123123123123"},
{"name":"123123123124"},
{"name":"123123123125"},
{"name":"123123123126"}
];
var x1 = {}
data.forEach(function(val,i){
x1[val.name] = { "question": ["insert"] };
});
console.log(x1);
Keep it simple.
Use a new object as your container to populate.
Switch from "forEach" to "for" loop to avoid confusion.
Create a new instance of the array on every iteration for reference.
Assign index at 0 to insert.Take object at iteration and set it the name property value.
Then assign to an Object with the question property set to your array at key '0'
var data = [{
"name": "123123123123"
},
{
"name": "123123123124"
},
{
"name": "123123123125"
},
{
"name": "123123123126"
}
];
var obj = {};
for (var i = 0; i < data.length; i++) {
var insert = [];
insert['0'] = 'insert';
obj[data[i].name] = {
question: insert
}
};
console.log(obj);
I'm wondering if something like this is possible - an extend that looks at an array of objects
Lets say I have :
myObj = [
{"name" : "one", "test" : ["1","2"]},
{"name" : "two", "test" : ["1","2"]}
]
And I'm trying to extend into that
{"name" : "one" , "test" : ["1","3"]}
So the result would be -
myObj = [
{"name" : "one", "test" : ["1","2", "3"]},
{"name" : "two", "test" : ["1","2"]}
]
And this would be like extend in that if there is no object there it would just create one. IS something like this possible? Thanks!
It looks like you want something like:
function deepSetMerge(base, next) {
var dataEntry = base.filter(function(it) {
return it.name === next.name;
})[0];
if (dataEntry) {
var diff = next.test.filter(function(it) {
return dataEntry.test.indexOf(it) === -1;
});
dataEntry.test = dataEntry.test.concat(diff).sort();
} else {
base.push(next);
}
}
var data = [{
"name": "one",
"test": ["1", "2"]
}, {
"name": "two",
"test": ["1", "2"]
}];
var add = {
"name": "one",
"test": ["1", "3"]
};
var obj = {
"name": "totally-unique",
"test": [1, 2, "nine", 17.0]
};
deepSetMerge(data, add);
deepSetMerge(data, obj);
document.getElementById('results').textContent = JSON.stringify(data);
<pre id="results"></pre>
This function works by finding the existing entry, by name, if one exists. If not, we just push the object to be merged in as a new entry.
If the entry does exist, find the difference between the two sets of items, then concatenate them onto the end of the existing array (and sort the results).
This is pretty specific to your data structure and not the most flexible solution in the world, but hopefully shows the algorithm well.
As a universal extend implementation this would be quite tricky and costly. It is why deep dives are usually avoided. It is better to know your data model and work with it that way.
Using your example I would establish some assumptions on the data model in question:
Our object will have a name property which is unique and can be searched for.
The value of the test property is an array (makes this easier but it could be an object that you use a typical extend implementation on.
In which case you could approach it like this:
var myObj = [
{name: 'one', test: ['1', '2']},
{name: 'two', test: ['1', '2']}
];
function extendTestValue(data, value) {
var names = data.map(function(item) {
return item.name;
});
var index = names.indexOf(value.name);
if (index < 0) {
data.push(value);
} else {
value.test.forEach(function(item) {
if (data[index].test.indexOf(item) < 0) {
data[index].test.push(item);
}
});
}
return data;
}
I have a function (that I can't change) that queries data from a database and returns it in a variable that shows as the following format if I display it as text:
var outputdata=
[
{ itemA: 'M0929', itemDate: new Date(1950,03-1,25,0,0,0,0), itemID: 'JDR12' },
{ itemA: 'X0121', itemDate: new Date(1983,07-1,07,8,0,0,0), itemID: 'RPN50' },
{ itemA: 'U0229', itemDate: new Date(1942,09-1,07,8,0,0,0), itemID: 'CRG98' },
];
I need it to be converted into the following format (specific date formatting doesn't matter) for use by another function (that I also can't change).
var inputdata=[
[
"M0929",
"1950-03-25",
"JDR12"
],
[
"X0121",
"1983-07-07",
"RPN50"
],
[
"U0229",
"1942-09-07",
"CRG98"
]
];
Could someone offer some assistance... I don't really understand javascript arrays and I'm really after a function to do the conversion.
You're probably going to have to write it yourself, for example:
function pad (what)
{
return what < 10 ? '0'+what : String(what);
}
function transformData (data)
{
var result = [];
for (var i=0;i<data.length;++i)
{
var date = data[i]['itemDate'];
result.push([
data[i]['itemA'],
date.getFullYear()+'-'+pad(date.getMonth())+'-'+pad(date.getDate()),
data[i]['itemID']
]);
}
return result;
}
var outputdata=
[
{ itemA: 'M0929', itemDate: new Date(1950,03-1,25,0,0,0,0), itemID: 'JDR12' },
{ itemA: 'X0121', itemDate: new Date(1983,07-1,07,8,0,0,0), itemID: 'RPN50' },
{ itemA: 'U0229', itemDate: new Date(1942,09-1,07,8,0,0,0), itemID: 'CRG98' },
];
var result = transformData(outputdata);
alert(result.join("\n"));
Now, the things to be aware of are the nature of UTC dates. More details can be found here http://www.w3schools.com/jsref/jsref_obj_date.asp. Also, I highly recommend reading more about Javascript in general.
function convert(outputdata){
var arr = [];
for(var i = 0; i<outputdata.length; i++){
var output = outputdata[i];
var temp = [output.itemA, output.itemDate, output.itemID];
arr[i] = temp;
}
return arr;
}
Edited: initialized arr.
Not a full response, because this smells like homework (and if it is, you should tag it as such). So hints first:
You can make an array by writing something like `[ 7, 9*7, "ho" ]
You can get at properties with dot notation like obj.itemA