javascript always pushes the same object - javascript

Do you have any idea why this code always adds the last object?
Because I used
var obj = {}
and
var newBase = Object.assign({}, baseJson)
but code always use the same reference?
module.exports = (csv, baseJson) => {
var lines=csv.split("\n");
var result = [];
var headers=lines[0].split(";");
for(var i=1;i<lines.length;i++){
var obj = {};
var newBase = Object.assign({}, baseJson);
obj["case"] = "Scenario";
obj["request"] = newBase;
obj["response"] = {
responseCode: "5",
actionCode: "0",
approvalCode: "98765X",
}
var currentline=lines[i].split(";");
var responseTags = ["responseCode", "actionCode", "approvalCode"];
for(var j=0;j<headers.length;j++){
headers[j] = headers[j].replace('\r','');
currentline[j] = currentline[j].replace('\r','')
if (headers[j] == "Scenario") {
obj["case"] = currentline[j];
}
else if (responseTags.indexOf(headers[j]) > -1 ){
obj["response"][headers[j]] = currentline[j];
}
else {
saveValue(obj["request"], headers[j], currentline[j]);
}
}
result.push(obj);
}
I tried almost everything but I could not manage to create a new object. It uses the same reference. This code is in node.js.
Thank you

Object.assign may not clone inner objects and it just takes same reference, try stringify and parse it.
var newBase = JSON.parse(JSON.stringify(baseJson));
Refer to know more : What is the most efficient way to deep clone an object in JavaScript?

This is because Javascript vars scoped to functions, not blocks. Effectively in your code obj is declared outside of the loop and it's properties mutated.
let should solve the problem:
for(var i=1;i<lines.length;i++){
let obj = {};
...
result.push(obj);
}

Related

How to detect new fields added in cloud firestore function onUpdate() [duplicate]

I need to compare two objects, and find out what properties are missing.
The objects are fairly big, with several levels.
I will give short example of the type of object:
UC = {};
UC.start = {}
UC.start.enableHardEccDecline = '';
UC.start.template = {};
UC.start.template.ecc = '';
UC.start.template.decline = {};
UC.start.template.decline.title = '';
UC.start.template.decline.body = '';
UC.general = {};...
So this is an example object. What I need to compare is just the properties. I do not care for the value. I will be comparing this object with another one very similar, but some properties might be missing.
function compare(base, compared, deepSearch) {
var missing = [];
var compareProp = function (baseValue, comparedValue, path, deepSearch) {
//console.log('comparing', path.join('.'));
if (comparedValue === undefined) {
console.log('missing key', path.join('.'));
if (!deepSearch) {
return;
}
}
if (typeof baseValue === 'object') {
Object.keys(baseValue).forEach(function (key) {
compareProp(baseValue [key], comparedValue && comparedValue [key], path.concat(key), deepSearch);
});
}
};
Object.keys(base).forEach(function (key) {
compareProp(base [key], compared [key], [key], deepSearch);
});
}
UC = {};
UC.start = {}
UC.start.enableHardEccDecline = '';
UC.start.template = {};
UC.start.template.ecc = '';
UC.start.template.decline = {};
UC.start.template.decline.title = '';
UC.start.template.decline.body = '';
UC.general = {};
compare (UC, {}, true);
I have just made a quick example here, not sure exactly how you want to apply this, but I have added the missing items to an array, which is logging it.
Obj1 should be your standard comparison object, obj2 the one received from request.
var obj1 = {};
obj1.test1 = 0;
obj1.test2 = 0;
obj1.test2222 = 0;
obj1.testLoremIpsum = 0;
obj1.lalala = 0;
var obj2 = {};
obj2.test1 = 0;
obj2.test25 = 0;
obj2.lalala1 = 0;
var k , i = 0;
var missingProps = [];
for( i in obj1 )
{
var isFound = false;
for( k in obj2) if( i == k ) isFound = true;
if(!isFound) missingProps.push( i );
}
console.log(missingProps);
How about use JSON.stringify to convert object to string, then do the string comparison:
JSON.stringify(UC) === JSON.stringify(UCToBeCompared)
By using this method, you have to make sure the objects don't have circular reference, otherwise JSON.stringify would throw an exception
If your situation allows it I'd suggest using http://underscorejs.org/ library, rather than rolling your own solution (or go look at their implementation). In JS deep object comparison is sometimes not trivial.
If you decide to roll your own solution, you would recursively iterate through the properties and compare them one by one (ignoring native / built-in object properties and perhaps inherited from some prototype).
I'll gladly elaborate if you'd like.
I have a made a example here. Hope it resolves your issue. It will compare Object KEYS only and return the object key which is not exist with compared object.
var a = Object.keys(obj1);
var b = Object.keys(obj2);
var missing= a.filter(function(v){
return b.indexOf(v)==-1;
})
console.log(missing);

Create nested Javascript Object dynamically

I have got a . (dot) separated string, from which I want to create nested JSON object. The length of the string is not fixed. For example,
var string = 'a.b.c.d';
Then my JSON object should be as following:
a: {
b: {
c:{
d: {
//Some properties here.
}
}
}
}
I've tried following code:
var packageName = "a.b.c.d"
var splitted = packageName.split('.');
var json = {};
for(var i=0;i<splitted.length-1;i++){
json[splitted[i]] = splitted[i+1];
}
But this returns
{
a: 'b',
b: 'c',
c: 'd'
}
But this is not what I want. I've also searched on google and found similar questions, but no solutions answer my problem. For example this.
A good use case for reduce
packageName = "a.b.c.d";
initProps = {hi: 'there'};
obj = packageName.split('.').reduceRight((o, x) => ({[x]: o}), initProps);
console.log(JSON.stringify(obj))
If you find loops easier to work with, a loop could be written concisely as
result = {};
ptr = result;
for (let prop of packageName.split('.'))
ptr = ptr[prop] = {};
You need to create a new object each time and attribute it to the last object created. And it goes until splitted.length, not splitted.length - 1, because you're using <, not <=.
var packageName = "a.b.c.d";
var splitted = packageName.split('.');
var json = {};
var current = json;
for (var i = 0; i < splitted.length; i++) {
current[splitted[i]] = {};
current = current[splitted[i]];
}
console.log(json);
You may use the last splittted part as property for some payload.
I suggest to keep the object reference and use a temporary variable for aceessing an creating a new property, if necessary.
Please avoid the use of JSON for not stringified objects.
var packageName = "a.b.c.d",
splitted = packageName.split('.'),
result = {},
temp = result,
i;
for (i = 0; i < splitted.length - 1; i++) {
temp[splitted[i]] = temp[splitted[i]] || {};
temp = temp[splitted[i]];
}
temp[splitted[i]] = { some: 'data' };
console.log(result);

Create deep object from string like "obj.obj1.obj2.data'

I'm starting with unit testing. I need to create some fake data to run the tests. So let's say inside a stubbed method I'm passing an obj as an argument and I do things with obj.obj1.obj2.data inside the function. Is there a way to set this fake object? So, given:
obj.obj1.obj2.data
It creates:
obj = {
obj1: {
obj2: {
data: 'whatever'}}}
So it would be at the end something like:
var obj = creator('obj.obj1.obj2.data', 20);
Assuming the string is only a set of objects (no arrays) this should be fairly straightforward. Just split the input string on . and then use a while loop to do the nesting.
function creator(str,val){
var tree = str.split('.');
var ret = {};
var cur = ret;
while(tree.length){
var name = tree.shift();
cur[name] = tree.length ? {} : val;
cur = cur[name];
}
return ret;
}
document.querySelector("#out").innerHTML = JSON.stringify(creator('obj.obj1.obj2.data',20));
<div id="out"></div>
Just in case anyone else in interested, I created a simple npm module with the function below (https://github.com/r01010010/zappy) check it out:
var objFrom = function(str, last_value){
var objs = str.split('.');
var r = {};
var last = r;
for(i=0; i < objs.length; i++) {
if(i !== objs.length - 1){
last = last[objs[i]] = {};
}else{
last[objs[i]] = last_value;
}
}
return r;
}
var obj = objFrom('obj1.obj2.data', 20);
console.log(obj.obj1.obj2.data);

How to recursively merge 2 javascript objects?

I have 2 objects that I need to merge and keep all properties in tact, tried with jQuery $.extend but I cant get it to work . I tried all posts with how to merge javascript objects but simply cant get this to work.
var thz_icon_source = {"Spinners":["spinnericon1","spinnericon2"],"Awesome":["awesomeicon1","awesomeicon2"]};
var fa_icon_source = {"Spinners":["faspinner1","faspinner2"],"Awesome":["faawesome1","faawesome2"]};
var new_source ={};
$.extend(new_source,fa_icon_source,thz_icon_source);
console.log(thz_icon_source);
console.log(fa_icon_source);
console.log(new_source);
desired output should be like
{
"Spinners":["faspinner1","faspinner2","spinnericon1","spinnericon2"],
"Awesome":["faawesome1","faawesome2","awesomeicon1","awesomeicon2"]
}
This post Merge two json/javascript arrays in to one array has a simple object mine is not same as that one.
Demo
function mergeJSON(json1,json2)
{
var result = json1 ;
for (var prop in json2)
{
if (json2.hasOwnProperty(prop))
{
result[prop] = result[prop].concat(json2[prop]);
}
}
return result;
}
$.extend merges in missing properties, it doesn't combine the properties that are in common. You need to write a loop.
var thz_icon_source = {
"Spinners": ["spinnericon1", "spinnericon2"],
"Awesome": ["awesomeicon1", "awesomeicon2"]
};
var fa_icon_source = {
"Spinners": ["faspinner1", "faspinner2"],
"Awesome": ["faawesome1", "faawesome2"]
};
var new_source = {};
// First add in the new elements from thz_icon_source
$.extend(new_source, fa_icon_source, thz_icon_source);
// Now merge the common elements
$.each(fa_icon_source, function(k, e) {
if (thz_icon_source.hasOwnProperty(k)) {
new_source[k] = e.concat(thz_icon_source[k]);
}
});
console.log(thz_icon_source);
console.log(fa_icon_source);
console.log(new_source);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You can use this prototype to merge 2 or more objects the way you want it:
Object.prototype.assignDeep = function() {
var self = this;
Object.keys(arguments).forEach(obj => {
Object.keys(self).forEach(val => {
if (arguments[obj].hasOwnProperty(val)) {
var tmp = arguments[obj][val] instanceof Array ? arguments[obj][val] : [arguments[obj][val]];
self[val] = self[val].concat(tmp);
}
});
});
return self;
}
var thz_icon_source = {"Spinners":["spinnericon1","spinnericon2"],"Awesome":["awesomeicon1","awesomeicon2"]};
var fa_icon_source = {"Spinners":["faspinner1","faspinner2"],"Awesome":["faawesome1","faawesome2"]};
var b = thz_icon_source.assignDeep(fa_icon_source);
console.log(b);
You should use a loops with .concat():
function objectConcatArrays(){
var a = arguments, o = {};
for(var i=0,l=a.length; i<l; i++){
for(var p in a[i]){
if(p in o){
o[p] = o[p].concat(a[i][p]);
}
else{
o[p] = a[i][p];
}
}
}
return o;
}
var thz_icon_source = {"Spinners":["spinnericon1","spinnericon2"],"Awesome":["awesomeicon1","awesomeicon2"]};
var fa_icon_source = {"Spinners":["faspinner1","faspinner2"],"Awesome":["faawesome1","faawesome2"]};
var res = objectConcatArrays(thz_icon_source, fa_icon_source);
console.log(res);
Each argument represents an Object of Arrays. Add more if you want.

Easy way to set javascript object multilevel property?

I am trying to create a javascript object like
var allUserExpiry={};
allUserExpiry[aData.userId][aData.courseId][aData.uscId] = aData;
But I am getting an error like allUserExpiry[aData.userId] undefined.
Is there a way, whereby I can set multi-level JS-Object keys? or is it important that I should go by doing allUserExpiry[aData.userId]={}, then allUserExpiry[aData.userId][aData.courseId]={} ?
Please let me know if there are any utility functions available for the same.
No, there is no way to set "multilevel keys". You need to initialize each object before trying to add properties to it.
var allUserExpiry = {};
allUserExpiry[aData.userId] = {}
allUserExpiry[aData.userId][aData.courseId] = {}
allUserExpiry[aData.userId][aData.courseId][aData.uscId] = aData;
Using Computed property names from ES6, it is possible to do:
var allUserExpiry = {
[aData.userId] = {
[aData.courseId]: {
[aData.uscId]: aData
}
}
};
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names
Simply use loadash,
let object = {};
let property = "a.b.c";
let value = 1;
_.set(object, property, value); // sets property based on path
let value = _.get(object, property, default); // gets property based on path
Or you can do it:
function setByPath(obj, path, value) {
var parts = path.split('.');
var o = obj;
if (parts.length > 1) {
for (var i = 0; i < parts.length - 1; i++) {
if (!o[parts[i]])
o[parts[i]] = {};
o = o[parts[i]];
}
}
o[parts[parts.length - 1]] = value;
}
And use:
setByPath(obj, 'path.path2.path', someValue);
This approach has many weak places, but for fun... :)
Why not just do this?
var allUserExpiry={};
allUserExpiry[aData.userId] = {aData.courseId: {aData.uscId: aData}};
I have a pretty hacky but short way of doing it in IE9+ as well as real browsers.
Given var path = 'aaa.bbb.ccc.ddd.eee'; where path is what your intending to make into an object and var result = {}; will will create the object {aaa: {bbb: {ccc: {ddd: {eee: {}}}}}
result = {}
path.split('.').reduce(function(prev, e) {
var newObj = {};
prev[e] = newObj;
return newObj;
}, result);
will store the object in result.
How it works:
split('.') converts the input into ['aaa', 'bbb', 'ccc', 'ddd', 'eee']
reduce(function (...) {...}, result) runs through the array created by split, and for each entry will pass along a returned value to the next one. In our case we pass the new object through after adding the new object to the old one. This creates a chain of objects. reduce returns the last object you return inside of it, so we have to defined result beforehand.
This relies on using references so it won't be immediately clear how it works if you're expecting your code to be maintained by anyone else and should probably be avoided to be honest, but it works at least.
You can also use the following to create the initial structure:
var x = function(obj, keys) {
if (!obj) return;
var i, t;
for (i = 0; i < keys.length; i++) {
if (!t) {
t = obj[keys[i]] = {};
} else {
t[keys[i]] = {};
t = t[keys[i]];
}
}
};
var a = {};
x(a, ['A', 'B', 'C', 'D', 'E', 'F']);
Another approach without strings or array as argument.
function fillObject() {
var o = arguments[0];
for(var i = 1; i < arguments.length-1; i++) {
if(!o.hasOwnProperty(arguments[i])) {
o[arguments[i]] = {};
}
if(i < arguments.length-2) {
o = o[arguments[i]];
}else {
o[arguments[i]] = arguments[i+1]
}
}
}
var myObj = {"foo":{}};
fillObject(myObj,"back","to","the","future",2);
console.log(JSON.stringify(myObj));
// {"foo":{},"back":{"to":{"the":{"future":2}}}}
But I wouldn't use it :-) It's just for fun.
Because I don't like too much intelligent algorithm. (If it was in this category)
Using lodash you can do this easily (node exists and empty check for that node)..
var lodash = require('lodash-contrib');
function invalidateRequest(obj, param) {
var valid = true;
param.forEach(function(val) {
if(!lodash.hasPath(obj, val)) {
valid = false;
} else {
if(lodash.getPath(obj, val) == null || lodash.getPath(obj, val) == undefined || lodash.getPath(obj, val) == '') {
valid = false;
}
}
});
return valid;
}
Usage:
leaveDetails = {
"startDay": 1414998000000,
"endDay": 1415084400000,
"test": { "test1" : 1234 }
};
var validate;
validate = invalidateRequest(leaveDetails, ['startDay', 'endDay', 'test.test1']);
it will return boolean.
Another solution using reduce function (thanks Brian K).
Here we created a get/set to general proposes. The first function return the value in any level. The key is splited considering the separator. the function return the value refered from last index in the key's array
The second function will set the new value considering the last index of the splited key
the code:
function getObjectMultiLevelValue(_array,key,separator){
key = key.split(separator || '.');
var _value = JSON.parse(JSON.stringify(_array));
for(var ki in key){
_value = _value[key[ki]];
}
return _value;
}
function setObjectMultiLevelValue(_array,key,value,forcemode,separator){
key.split(separator || '.').reduce(function(prev, currKey, currIndex,keysArr) {
var newObj = {};
if(prev[currKey] && !forcemode){
newObj = prev[currKey];
}
if(keysArr[keysArr.length-1] == currKey){
newObj = value;
prev[currKey] = newObj;
}
prev[currKey] = newObj;
return newObj;
}, _array);
return _array;
}
//testing the function
//creating an array
var _someArray = {a:'a',b:'b',c:{c1:'c1',c2:{c21:'nothing here...'}}};
//a multilevel key to test
var _key = 'a,a1,a21';
//any value
var _value = 'new foo in a21 key forcing replace old path';
//here the new value will be inserted even if the path exists (forcemode=true). Using comma separator
setObjectMultiLevelValue(_someArray,_key,_value,true,',');
console.log('_someArray:');
console.log(JSON.stringify(_someArray));
//inserting another value in another key... using default separator
_key = 'c.c2.c21';
_value = 'new foo in c21 key';
setObjectMultiLevelValue(_someArray,_key,_value);
console.log('_someArray:');
console.log(JSON.stringify(_someArray));
//recovering the saved value with different separators
_key = 'a,a1,a21';
console.log(getObjectMultiLevelValue(_someArray,_key,','));
_key = 'c.c2.c21';
console.log(getObjectMultiLevelValue(_someArray,_key));
Let assume our object is
const data = {
//some other data
userInfo: {},
};
First, define a new property of that object
data.userInfo.vehicle = {};
then simply
data.userInfo.vehicle.vehicleType = state.userInfo.vehicleType;

Categories