Javascript dynamic nested objects - javascript

I was looking into how to create a dynamic nested objects from a string, for example, a string "obj1.obj2.obj3.obj4", how do you turn that into nested objects with the same order.
I googled around and i found this nice and clean code, but i did not understand how it worked, and there was no explanation on the page where it was written, can someone explain how this works please?
here is the code:
var s = "key1.key2.key3.key4";
var a = s.split('.');
var obj = {};
var temp = obj;
for (var k =0; k < a.length; k++) {
temp = temp[a[k]] = {};
console.log(temp);
}
console.log(obj);
why is there a var temp = obj?
what does this line do?:
temp = temp[a[k]] = {};
also, the console.log(temp) inside the loop always logs an empty object {}, why?
Thanks for the feedback!

why is there a var temp = obj?
obj is a variable to hold the completed object. temp is a variable to hold each intermediate step of the object being built. temp starts out with the same value as obj so that the first iteration of the loop adds on to obj.
what does this line do?:
temp = temp[a[k]] = {};
Assign an empty object to a property in temp with the name a[k], where a[k] is one of the values in a.
Assign that new empty object to temp.
This could be written separately as two lines:
temp[a[k]] = {};
temp = temp[a[k]];
also, the console.log(temp) inside the loop always logs an empty object {}, why?
Because the previous line assigns an empty object to temp.

Your question boils down to this (comments inline)
var x = {};
var y = x;
y[ "a" ] = {}; //reference to x stays so x also becomes { "a": {} }
y = y["a"]; //now y effectively becomes {} but has the same reference to y["a"] as assignment works right to left hence property `a` is becomes non-enumerable and hence shadowed.
console.log( "First Run" );
console.log( y ); //prints {}
console.log( x ); //prints { "a": {} }
y[ "a" ] = {}; //y still has a non-enumerable property `a`
y = y["a"]; //same as above y = y["a"], y again becomes {}
console.log( "Second Run" );
console.log( y ); //prints {} again
console.log( x ); //prints { "a": { "a": {} } }
Outputs
First Run
{}
{ "a": {} }
Second Run
{}
{ "a": {
"a": {} } }

Have added comments in code, hope it will be useful
var s = "key1.key2.key3.key4";
//split the string by dot(.) and create an array
var a = s.split('.');
//Creating an empty object
var obj = {};
var temp = obj;
//looping over the array
for (var k = 0; k < a.length; k++) {
//a[k] will be key1,key2,key3....
// temp is an object,square bracket is use to create a object key
// using a variable name
// variable name here is key1,key2....
//temp[a[k]] will initialize an empty object
temp = temp[a[k]] = {};
console.log(temp);
}
console.log(obj);

It seems where you are iterating the array, in that temp object is newly creating and assigning key to obj.
temp = temp[a[k]] = {};
above line simply assigns a[index] value as a key to the new object and as a reference to obj the nested object is created.
for your question,
why is there a var temp = obj?
it copies obj object into temp variable
also, the console.log(temp) inside the loop always logs an empty object {}, why?
since you are recreating an empty object (or reassigning).

Related

Add an existing var to a new object in JavaScript and loop through them

I find numerous guides on how to add variables to existing objects, but nowhere how to add an "existing" variable to an existing object.
I have a whole list with variables already defined in my script. e.g.: a, b, c, d.
and they all have their own values.
Now I want to call a function on all these variables and then show the variable-names and outcome in console.
Therefor I want to create an object out of them to loop through. How do I do this?
This is my workflow:
Values are created in various places in the script:
a = 1.333;
b = 1.64252345;
c = 2.980988;
I create the object and try to add the already existing variables (this is where I fail):
var abc = {};
abc.a;
abc.b;
abc.c;
I want to loop through the object, flooring all numbers, and printing the variable-name with the returned number:
var i;
for (i = 0; i < abc.length; ++i) {
var variablename = Object.keys(abc[i]);
var flooredvalue = floor(abc[i]);
var abc[i] = flooredvalue; // Save the floored value back to the variable.
console.log(variablename+": "+flooredvalue);
}
My desired output in console.log:
a = 1
b = 1
c = 2
Looping through the array of object keys will be a good idea.
a = 1.333;
b = 1.64252345;
c = 2.980988;
var abc = {};
abc.a = a;
abc.b = b;
abc.c = c;
var i;
var keys = Object.keys(abc);
console.log(abc['a'])
for (i = 0; i < keys.length; i++) {
var key = keys[i];
var flooredvalue = Math.floor( abc[key] );
abc[key] = flooredvalue;
window[key] = flooredvalue; //global variable change.
}
console.log(a);
console.log(b);
console.log(c);

Javascript - Get the associative array key value

I have an object with one key value as given below -
var a = {};
a.x = "randomvalue";
My requirement is to get access the value "randomvalue", but the catch is I dont know that the property name is "x".
Simplest way to get the value??
Try:
var v, i;
var a = {};
a.x = "randomvalue";
for (x in a) {
if a[x] === "randomvalue" {
v = x;
i = "randomvalue";
}
}
Then v contains the object key and i contains the object value (although you don't really need it).
Or, if you know the value index:
var obj = { first: 'someVal' };
obj[Object.keys(obj)[0]]; //returns 'someVal'

clear and undo clear the array

If I do have the following code then empty the arry:
var a1 = [1,2,3];
a1 = [];
//returns []
But I'm trying to make a function to clear and undo clear the array, it's not working as expected:
var foo = ['f','o','o'];
var storeArray;
function clearArray(a){
storeArray = a;
a = [];
}
function undoClearArray(a){
a = storeArray;
}
clearArray(foo);
foo; //still returns ['f','o','o']
//but expected result is: []
Here's the problem:
You assign an array to a variable foo.
Then you pass this object to your function which stores it in another variable a. Now you have one object that two variable are pointing at. In the function you then reassign a to a different object an empty array []. Now a points at the empty object and foo still points at the original object. You didn't change foo by reassigning a.
Here's a concise way to store you're array:
var storeArray = [];
function clearArray(a){
while (a.length>0){
storeArray.push(a.shift()) //now a is empty and storeArray has a copy
}
}
I tried something different. Maybe it's dirty, but the storage itself is on the object.
the fiddle
//define the object to hold the old data
Object.defineProperty(Array.prototype, "storage", {
enumerable: false,
configureable: true,
get: function () {
return bValue;
},
set: function (newValue) {
bValue = newValue;
}
});
//define the prototype function clear to clear the data
Object.defineProperty(Array.prototype, "clear", {
enumerable: false,
writable: false,
value: function () {
this.storage = this.slice(0); //copy the data to the storage
for (var p in this) {
if (this.hasOwnProperty(p)) {
delete this[p]; //delete the data
}
}
return this; //return the object if you want assign the return value
}
});
//define the prototype function restore to reload the data
Object.defineProperty(Array.prototype, "restore", {
enumerable: false,
writable: false,
value: function () {
var a = this.storage.slice(0); //copy the storage to a local var
for (var p in this.storage) {
if (this.storage.hasOwnProperty(p)) {
this[p] = a[p]; //assign the pointer to the new variable
delete this.storage[p]; //delete the storage
}
}
return this;
}
});
var a = ['f','o','o'];
console.log(a); //--> displays ['f','o','o']
a.clear();
console.log(a); //--> displays []
a.restore();
console.log(a); //--> displays ['f','o','o']
You can use splice() method to delete all elements of an array likes below
function clearArray(a){
storeArray = a;
a.splice(0,a.length);
}
var a = [1,2,3,4];
var tempArr ;
clearArray = function() {
tempArr = a.slice(0);
a.length = 0;
}
undoArray = function() {
a = tempArr.slice(0);
}
Here is a small jsfiddle: http://jsfiddle.net/66s2N/
Here's working way of what you want to achieve:
var foo = ['f','o','o'];
var storeArray;
function clearArray(a){
storeArray = a.slice(0);
for (var i=0; i<a.length; i++)
delete a[i];
a.length = 0;
}
function undoClearArray(a){
for (var i=0; i<storeArray.length; i++)
a.push(storeArray[i]);
}
console.log(foo);
clearArray(foo);
console.log(foo); //now foo is []
undoClearArray(foo);
console.log(foo); // now foo is ['f','o','o']
http://jsfiddle.net/44EF5/1/
When you do:
var a1 = [1,2,3];
a1 = [];
it's as if you've written:
var a1 = [1,2,3];
var a1 = [];
You're overwriting variables.
Now, why your approach doesn't work - in JS there's no passing by reference. MarkM response explains what's happening within the function.
Now, why does the above work - while you've got two variables pointing towards the same array, nothing prevents you from modifying that array. As such storeArray = a.slice(0) will create a copy of the array. Then by using delete we're removing all values of the array, and then as length isn't enumerable (so using for (var i in a) wouldn't help) we reassign the length of the array. This has removed the values of original array, while creating a new array assigned to storeArray.
function clearArray(a){
storeArray = a.slice(0);
return a.length = 0;
}
or set foo.length = 0;
Just update your both function with below ones
function clearArray(a){
storeArray = a.slice(0);
a.length = 0;
}
function undoClearArray(a){
a = storeArray;
return a;
}
in undoClearAray() we are returning the variable which have new reference(in your clearArray(), Both the original and new array refer to the same object. If a referenced object changes, the changes are visible to both the new and original arrays). so use it as foo=undoClearArray(foo); for old values.
try
var foo = ['f','o','o'];
var storeArray;
function clearArray(a){
storeArray = a;
a = [];
return a;
}
function undoClearArray(a){
a = storeArray;
}
foo = clearArray(foo);
foo; //returns []
You can use wrappers to do this quite nicely. First create a wrapper function with the additional methods defined, then create your array using that function instead of []. Here is an example (see JSFiddle):
var extendedArray = function() {
var arr = [];
arr.push.apply(arr, arguments);
arr.clearArray = function() {
this.oldValue = this.slice(0);
this.length = 0;
}
arr.undoArray = function() {
this.length = 0;
for (var i = 0; i < this.oldValue.length; i++) {
this.push(this.oldValue[i]);
}
}
return arr;
};
var a = extendedArray('f', 'o', 'o');
alert(a);
a.clearArray();
alert(a);
a.undoArray();
alert(a);

Returning key/value pair in javascript

I am writing a javascript program, whhich requires to store the original value of array of numbers and the doubled values in a key/value pair. I am beginner in javascript. Here is the program:
var Num=[2,10,30,50,100];
var obj = {};
function my_arr(N)
{
original_num = N
return original_num;
}
function doubling(N_doubled)
{
doubled_number = my_arr(N_doubled);
return doubled_number * 2;
}
for(var i=0; i< Num.length; i++)
{
var original_value = my_arr(Num[i]);
console.log(original_value);
var doubled_value = doubling(Num[i]);
obj = {original_value : doubled_value};
console.log(obj);
}
The program reads the content of an array in a function, then, in another function, doubles the value.
My program produces the following output:
2
{ original_value: 4 }
10
{ original_value: 20 }
30
{ original_value: 60 }
50
{ original_value: 100 }
100
{ original_value: 200 }
The output which I am looking for is like this:
{2:4, 10:20,30:60,50:100, 100:200}
What's the mistake I am doing?
Thanks.
Your goal is to enrich the obj map with new properties in order to get {2:4, 10:20,30:60,50:100, 100:200}. But instead of doing that you're replacing the value of the obj variable with an object having only one property.
Change
obj = {original_value : doubled_value};
to
obj[original_value] = doubled_value;
And then, at the end of the loop, just log
console.log(obj);
Here's the complete loop code :
for(var i=0; i< Num.length; i++) {
var original_value = my_arr(Num[i]);
var doubled_value = doubling(original_value);
obj[original_value] = doubled_value;
}
console.log(obj);
You can't use an expression as a label in an Object literal, it doesn't get evaluated. Instead, switch to bracket notation.
var original_value = my_arr(Num[i]),
doubled_value = doubling(Num[i]);
obj = {}; // remove this line if you don't want object to be reset each iteration
obj[original_value] = doubled_value;
Or:
//Original array
var Num=[2,10,30,50,100];
//Object with original array keys with key double values
var obj = myFunc(Num);
//Print object
console.log(obj);
function myFunc(arr)
{
var obj = {};
for (var i in arr) obj[arr[i]] = arr[i] * 2;
return obj;
}

Javascript: Loop through unknown number of object literals

I have a list of objects all named in this fashion:
var p1 = {};
var p2 = {};
p1.name = "john";
p1.hobby = "collects stamps";
p2.name = "jane";
p2.hobby = "collects antiques";
I know how to loop through p1 and p2 to collect the properties, provided I know how many of these p object literals there are. Here's my problem, I don't always know how many of these p object literals there will be. Sometimes it goes up to p2, sometimes it goes up to p20.
Is there a way to loop through objects if I know they all share the same prefix?
Edit: I can't change how I'm getting the list of objects. It's given to me in that format...
If we make the following assumptions:
The objects are global
The number suffixes are sequential
...then the following works:
for (var i = 1; window["p" + i] !== undefined; i++) {
console.log(window["p" + i]); // loop over each object here
}
You should have them in an Array referenced by a single variable.
var p = [];
p.push({
name:"john",
hobby:"collects stamps"
}, {
name:"jane",
hobby:"collects antiques"
});
Then you'd loop the Array, and enumerate each object...
for( var i = 0; i < p.length; i++ ) {
for( var n in p[i] ) {
console.log( p[i][n] );
}
}
EDIT:
It seems from a comment that these may be arriving as individual variable.
If they're global variables, and if they always have the same p1 naming, then you can access them as properties of the global window object.
var obj;
for( var i = 1; obj = window['p' + i]; i++ ) {
if( typeof obj === 'object' ) {
for( var n in obj ) {
console.log( obj[n] );
}
}
}
This loop will run until a p(n) global returns a falsey value.
So as long as a truthy value is found, and its typeof is 'object', you'll iterate that object.
If you have all your data stored in a variable , or a few variables you can push it into the array.
var data = "....JSON";
var a = [];
a.push(data);
Push keeps adding stuff into the array in basic sense.
You could also pop to remove the last pushed data.
Take a look at the other methods here:
http://www.w3schools.com/jsref/jsref_obj_array.asp
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array
Why don't you just store them all in one top-level object literal? It will make it easier to enumerate through them.
EG:
var MyObj = {
p1: {},
p2: {}
};
etc..
[edit]
If they are local vars, are you can't change the format of this data, you might have to use eval.
Don't shoot me:
var p1 = {};
var p2 = {};
p1.name = "john";
p1.hobby = "collects stamps";
p2.name = "jane";
p2.hobby = "collects antiques";
var found = true, c = 1;
while(found) {
try {
var obj = eval('p' + c);
c++;
console.log(obj);
} catch(e){
found = false;
}
}
I don't suggest using this, I suggest changing the format of the data you are receiving, but this is one possible solution.

Categories

Resources