My aim is to combine 2 similar JSON objects so that the output will have its value taken from the json objects supplied. For eg:
var obj1 = {'name': 'xyz', 'age':''}, obj2 = {'name':'', 'age':'66'}
//would like to have some functionality like below that gives me the output
obj3 = combine(obj1,obj2)
//desired output below.
obj3 = {'name': 'xyz', 'age':'66'}
Since you say the two objects are similar I am going to assume that this means for those keys which are common among the two objects one has data and other has ''.
The second assumption I am going to make is that for any keys not common to both the objects you want it to be copied as is to the new object.
var obj1 = {'a': 'b', 'c': ''};
var obj2 = {'a': '', 'c': 'd', 'e': 'f'};
var obj3 = {};
var key;
for (key in obj1) {
if(obj1[key] === '') {
obj3[key] = obj2[key];
} else {
obj3[key] = obj1[key];
}
}
for(key in obj2) {
if(!(key in obj3)) {
obj3[key] = obj2[key];
}
}
Since you added the jQuery tag, I assume you are using it. If so, you can use jQuery's $.extend method.
var obj1 = {'name': 'xyz', 'age':''},
obj2 = {'name':'', 'age':'66'},
obj3 = $.extend(obj1,obj2);
I'm not entirely sure about what the disired result is, but this code should point you in the right direction. It copies values from obj2 to obj1, if the value has a value (with isnt empty or false):
combine = function(a, b) {
var bKeys = Object.keys(b)
for (var i = 0; i < bKeys.length; i++) {
var key = bKeys[i]
if (b[key]) {
a[key] = b[key]
}
}
}
Related
I found this JavaScript code for copying Objects, the code is doing what it's suppose to do, but what I don't understand is when the function call itself; how come newObject in the first iteration desn't loose its value, it should be overwritten when the function called itself and created a new newObject ? does that mean that when a function call itself it still keeps a copy of the first newObject created before it called itself?
const o = {
a: 'a',
b: 'b',
obj: {
key: 'key',
},
}
const o2 = o
o2.a = 'new value'
// o and o2 reference the same object
console.log(o.a)
// this shallow-copies o into o3
const o3 = Object.assign({}, o)
// deep copy
function deepCopy(obj) {
// check if vals are objects
// if so, copy that object (deep copy)
// else return the value
const keys = Object.keys(obj)
const newObject = {}
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
if (typeof obj[key] === 'object') {
newObject[key] = deepCopy(obj[key])
} else {
newObject[key] = obj[key]
}
}
return newObject
}
const o4 = deepCopy(o)
o.obj.key = 'new key!'
console.log(o4.obj.key)
Recursive functions can be confusing. A few well placed console.log()s or running the code in a debugger can really help. The function makes a newObject for the original object and each child object in the object. As the recursion unwinds it sets the property in the parent to the result of the recursive call on the child.
You can see the effect in the console.logs here:
const o = {
a: 'a',
b: 'b',
obj: {
key: 'key',
deeper: {one: 1, two: 2}
},
}
// deep copy
function deepCopy(obj) {
console.log("deep copy of: ", obj)
const keys = Object.keys(obj)
const newObject = {}
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
if (typeof obj[key] === 'object') {
console.log("setting child of", key, "to:")
newObject[key] = deepCopy(obj[key])
} else {
newObject[key] = obj[key]
}
}
return newObject
}
console.log("starting with")
const o4 = deepCopy(o)
Each of the lines starting with deep copy of indicates a newly created newObject in a recursive call, but the only newObject returned is the first one — all the others get set as children.
I have two objects, obj1 and obj2. If obj2 has a key that obj1 doesn't have, that obj2 key/value pair gets added to obj1.
for example:
obj1 = {
a:1,
b:2
}
obj2 = {
b:4,
c:3
}
c:3 would be put into obj1.
Here's what I have as an attempt, but my brain is being run in circles by this. I can't modify the 2nd object at all (don't need to), and i have to keep the value in obj1 if it also exists in obj2.
function extend(obj1, obj2) {
function comparison(obj1,obj2){
var object1keys = Object.keys(obj1)
var object2keys = Object.keys(obj2)
var flag = 0
for(var i = 0; i<object2keys.length;i++){
flag = 0
for(var j = 0; j<object1keys.length;j++){
if(object2keys[i] === object1keys[j]){
flag = 1
console.log(i,j)
break
}
if(flag = 0 && j == object1keys.length - 1){
obj1[i] = obj2[j]
}
}
}
return obj1
}
return obj1
}
Edit:This is a unique question because it looked like the other question didn't involve adding a specific key:value pair that didn't exist.
Simple solution using Object.keys() and Object.hasOwnProperty() functions:
var obj1 = {a:1,b:2}, obj2 = {b:4,c:3};
Object.keys(obj2).forEach(function(k) {
if (!obj1.hasOwnProperty(k)) obj1[k] = obj2[k];
});
console.log(obj1);
This should work.
function extend(obj1, obj2) {
Object.keys(obj2).forEach(function(key) {
obj1[key] = obj2[key];
})
return obj1;
}
console.log(extend({
a: 1,
b: 2
}, {
b: 3,
c: 4
}))
I have the following code (which works correctly):
var arr = [];
for(var i = 0; i < 2; i++) {
var obj = { a: 'A'};
obj.c = 'C' + i;
arr.push(obj);
}
// now arr is:
// [ {a: 'A', 'c': 'C0'}, {a: 'A', 'c': 'C1'} ]
To improve the performance of my code, I placed the obj outside the loop, then adding/modifying the new property only, like this:
var arr = [];
var obj = { a: 'A'};
for(var i = 0; i < 2; i++) {
obj.c = 'C' + i;
arr.push(obj);
}
// now arr is:
// [ {a: 'A', 'c': 'C1'}, {a: 'A', 'c': 'C1'} ]
Why both objects got C1 ? Please explain what I'm doing wrong, and how to place the object out of the loop and get correct results?
Note: I know this is a simple problem where performance is not an issue, but I'm actually dealing with big number of objects in reality where performance matters.
You are pushing the object (not a copy of the object) to the array, and then changing it.
If you want different objects in each index, then you need to create a new object each time you go around the loop.
Like the others wrote, you are changing the same object (the original) all the time which ends in the results being the same (the original).
To place the object out of the loop and still get the correct result, you would still have to 'copy' it inside of the loop:
var arr = [];
var obj = { a: 'A'};
var objstring = JSON.stringify(obj);
for(var i = 0; i < 2; i++) {
var obj = JSON.parse(objstring);
obj.c = 'C' + i;
arr.push(obj);
}
This question already has answers here:
How can I merge properties of two JavaScript objects dynamically?
(69 answers)
Closed 6 years ago.
I have two JavaScript objects with the structure below.
var obj1 = {id1: 10, name1: "stack"};
var obj2 = {id2: 20, name2: "overflow"};
I want to concat them together as a single object (not array) using Javascript.
The result should be like this.
var res = {id: 10, name1: "stack", id2: 20, name2: "overflow"};
Is there an easy way to do this using pure javascript?
Note: I don't need jQuery to do this and I want to concat is for json objects, not as json arrays using concat method. Is there any simple method or way to achieve this?
Use Object.assign
var obj1 = {a: 1}, obj2 = {b:2}
// Using three arguments so that obj 1 and 2 aren't modified
var result = Object.assign({}, obj1, obj2);
// result.a -> 1
// result.b -> 2
// obj1.b -> undefined
// obj2.a -> undefined
// You could modify obj1
Object.assign(obj1, obj2);
// obj1.b -> 2
Polyfill:
if (typeof Object.assign != 'function') {
(function () {
Object.assign = function (target) {
'use strict';
if (target === undefined || target === null) {
throw new TypeError('Cannot convert undefined or null to object');
}
var output = Object(target);
for (var index = 1; index < arguments.length; index++) {
var source = arguments[index];
if (source !== undefined && source !== null) {
for (var nextKey in source) {
if (source.hasOwnProperty(nextKey)) {
output[nextKey] = source[nextKey];
}
}
}
}
return output;
};
})();
}
A simple plain solution:
function addToObject(source, target) {
Object.keys(source).forEach(function (k) {
target[k] = source[k];
});
}
var obj1 = { id1: 10, name1: "stack" },
obj2 = { id2: 20, name2: "overflow" },
result = {};
addToObject(obj1, result);
addToObject(obj2, result);
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
I have a nested Javascript object like
var data = { 'name': { 'heading': 'Name', 'required': 1, 'type': 'String' },
'profile': {
'age': { 'heading': 'Age', 'required': 0, 'type': 'Number' },
'phone': { 'heading': 'Phone', 'required': 0, 'type': 'String'},
'city': { 'heading': 'City', 'required': 0, 'type': 'String'},
},
'status': { 'heading': 'Status', 'required': 1, 'type': 'String' }
};
Here, I can access the fields as data.profile.age.type or data.name.type. No Issues
And if I have dynamic variable names, I can access as below. Again, No Problems.
f = 'profile'; data[f].age.type
But, here I have variable names like 'name', 'profile.age', 'profile.city' etc and obviously I cannot access them as f = 'profile.age'; data[f].type which will not work.
Can anyone guide me how to access them (get/set) in the most straight-forward and simple way?
Note: I tried this and it works for get.
data.get = function(p) { o = this; return eval('o.'+p); };
f = 'profile.age'; data.get(f).name;
though set does not seem to be simple enough. Please let me know, if there are better solutions for get and set as well.
Don't use eval unless absolutely necessary. :) At least in this case, there are better ways to do it -- you can split the nested name into individual parts and iterate over them:
data.get = function(p) {
var obj = this;
p = p.split('.');
for (var i = 0, len = p.length; i < len - 1; i++)
obj = obj[p[i]];
return obj[p[len - 1]];
};
data.set = function(p, value) {
var obj = this;
p = p.split('.');
for (var i = 0, len = p.length; i < len - 1; i++)
obj = obj[p[i]];
obj[p[len - 1]] = value;
};
You can just nest the brackets:
var a = 'name', b = 'heading';
data[a][b]; // = `Name`
Perhaps a function that takes in the path to the property you're interested in and breaks it up into tokens representing properties. Something like this (this is very rough, of course):
data.get = function(path) {
var tokens = path.split('.'), val = this[tokens[0]];
if (tokens.length < 2) return val;
for(var i = 1; i < tokens.length; i++) {
val = val[tokens[i]];
}
return val;
}
example:
var f = 'one.two';
var data = { one: {two:'hello'}};
data.get = /* same as above */;
var val = data.get(f);
A clean way to access/set nested values is using reduce in ES6:
const x = ['a', 'b', 'c'], o = {a: {b: {c: 'tigerking'}}}
// Get value: "tigerking"
console.log(x.reduce((a, b) => a[b], o))
// Set value:
x.slice(0, x.length-1).reduce((a, b) => a[b], o)[x[x.length-1]] = 'blossom'
console.log(o) // {a: {b: {c: 'blossom'}}}
So, you can first convert your variable 'profile.age' to an array using 'profile.age'.split('.'), then use the approach above.
This uses the jquery.each() function to traverse down a json tree using a string variable that may or may not contain one or more "."'s. You could alternatively pass in an array and omit the .split();
pathString = something like "person.name"
jsonObj = something like {"person" : {"name":"valerie"}}.
function getGrandchild(jsonObj, pathString){
var pathArray = pathString.split(".");
var grandchild = jsonObj;
$.each(pathArray, function(i, item){
grandchild = grandchild[item];
});
return grandchild;
};
returns "valerie"