This question already has answers here:
How to determine equality for two JavaScript objects?
(82 answers)
Closed 2 years ago.
I have a javascript object on my DB, its personal data, this is the structure:
const storedUserData = {
name: "John",
sirname:"Doe",
phone: "666-666-66666",
streetName: "Fake Street",
streetNumber: "123",
zipCode: "90125"
}
and I have a separate object, which has the same structure, which basically is on the front end, and its the result of reading form data.
const formData = {
name: "John",
sirname:"Doe",
phone: "666-666-66666",
streetName: "Fake Street",
streetNumber: "123",
zipCode: "90125"
}
Basically, when the user clicks submit I want to check if there are differences between the stored object storedUserData, above, and the new object, formData. If there are differences, save the differences to the DB.
Of course, I could go on like this for each property, since there are few:
if(storedUserData.name !== formData.name) {
pushDataToDb()
}
but its the lazy approach, and I want to do it correctly. I've been reading into object keys, but I cant figure it out. How could I successfully loop between each property of both items comparing them, and then only if there is a change between the two properties I would push to DB.
Thank you.
You could use a loop as you mentioned above,
function isEquivalent(a, b) {
// Create arrays of property names
var aProps = Object.getOwnPropertyNames(a);
var bProps = Object.getOwnPropertyNames(b);
// If number of properties is different,
// objects are not equivalent
if (aProps.length != bProps.length) {
return false;
}
for (var i = 0; i < aProps.length; i++) {
var propName = aProps[i];
// If values of same property are not equal,
// objects are not equivalent
if (a[propName] !== b[propName]) {
return false;
}
}
// If we made it this far, objects
// are considered equivalent
return true;
}
Read more about it here
Related
I have two different objects but they have some common properties. Both are filled with some values. I want to assign X object's values to override Y's property values if they have the same key in both object, else do nothing but y's empty prop keys should be remain.
I can achieve this purpose with some custom mapping operations but is there a simple way to do it in javascript?
var x = {
name: 'John',
addressInformation: null
}
var y = {
name: '',
paymentInformation: {
iban: '12313123',
cardNumber: '1231231231'
},
addressInformation: {
city: 'Berlin'
}
}
Merged object should be in my scenario:
y = {
name 'John',
paymentInformation: {
iban: '12313123',
cardNumber: '1231231231'
},
addressInformation: {
city: 'Berlin'
}
}
(I only shared the simplified version of that objects. There are many more properties)
Object.assign or spread operator will do the job.
const newObject = Object.assign(y, x);
const newObject = {
...y,
...x
}
Also, what aweebit said is important.
It is important to note that, whereas { ...y, ...x } leaves y intact and merges y and x into a new object which is assigned to the variable newObject, Object.assign(y, x) mutates y and returns it without creating a new object, so newObject === y evaluates to true after calling it.
I would post this as a comment to Baruch's answer but I do not have enough reputation yet, so your upvotes are appreciated :)
i am not getting proper the return after insertgraph in objection.js
i am getting the result like :
[
User {
name: 'Santosh Devi',
city: 'Suratgarh',
number: '9898987458',
userroles: UserRoles { role_id: 2, user_id: 37 },
id: 37
}
]
where i want the result like :
[
{
name: 'Santosh Devi',
city: 'Suratgarh',
number: '9898987458',
userroles: { role_id: 2, user_id: 37 },
id: 37
}
]
There are few ways to get rid of the specific class references:
1. JSON.parse(JSON.stringify(result))
This will rebuild the object by first converting the whole object to a string (in JSON format), and then by doing the reverse -- creating a new object from a string. As this string format (JSON) does not store custom class information, it achieves your purpose. However, if your object has functions, symbols, then these will be omitted. Also Map and Set will become empty objects. For a more complete list of restrictions. See JSON.stringify
2. Deep Clone
There are several deep-clone functions out there, that may or may not do what you expect. Some will still try to maintain the original prototype references, so that it would not benefit you. You can find some here: How to Deep clone in javascript. For your case, this one would do the job:
function deepClone(obj, hash = new WeakMap()) {
if (Object(obj) !== obj) return obj; // primitives
if (hash.has(obj)) return hash.get(obj); // cyclic reference
const result = Array.isArray(obj) ? [] : {};
hash.set(obj, result);
return Object.assign(result, ...Object.keys(obj).map(
key => ({ [key]: deepClone(obj[key], hash) }) ));
}
You call it as newResult = deepClone(result).
The advantage here, is that it supports cyclic references, which JSON.stringify cannot handle. Also, there is no string conversion happening, which really is not necessary. You can extend this function to keep deal with some class instances that you like to stay that way. See how you can support Date, RegExp, Map, Set, ... in this answer. But don't do the "catch-all" line.
3. Change the prototype
With this strategy you mutate the result in-place.
function removeClasses(obj, hash = new WeakSet()) {
if (Object(obj) !== obj) return; // primitives
if (hash.has(obj)) return; // cyclic reference
hash.add(obj);
if (Array.isArray(obj)) Object.setPrototypeOf(obj, Array.prototype);
else Object.setPrototypeOf(obj, Object.prototype);
for (let value of Object.values(obj)) {
removeClasses(value, hash);
}
}
Call it as removeClasses(result), and afterwards result will have been "fixed". Again, this method does not use a conversion to string. As it does not create a new object either, it consumes less memory. But on the other hand you mutate an object, and some would advise against that.
This question already has answers here:
Accessing nested JavaScript objects and arrays by string path
(44 answers)
Closed 5 years ago.
Not sure if my title describes what I want to do correctly. Basically, I want a function that extracts properties from objects containing objects. I am going to need to loop through various arrays containing many objects of the same class and extract specific values.
myarray1[
0:
object1 = {
objectProp1: {
objectProp1Prop1:"Hello",
objectProp1Prop2:"Goodbye",
objectProp1Prop3:{
objectProp1Prop3Prop1: "Come here",
objectProp1Prop3Prop2: "Go away"
},
},
objectProp2: "Yo",
objectProp3: "Seeya",
}
1:
object2 = { same as object1 but with other property values }
];
myarray2[
0: { different type of object with a different set of nested properties that the function can extract }
1: { idem }
];
function extractProperty(objectArray, property) {
//How do I write this code?
propertyvalue = objectArray.property;
return propertyvalue;
}
extractProperty(myarray1[0], object.objectProp3) = "Seeya"
extractProperty(myarray1[0], object.objectProp1.objectProp1Prop1) = "Hello"
extractProperty(myarray1[0], object.objectProp1.objectProp1Prop3.objectProp1Prop3Prop1) = "Come here"
In the final code the function needs to be able to loop through all the array keys and create an array list containing the chosen property from every object in the original array, but that I can manage. It's the sending of the specific property that needs to be extracted from the objects in the array into the function that I have no idea how to do.
Is there a generalised way to send a "path" of properties into a function and then use it there? How?
Thanks for your help!
Looks like an assignment to me. So I won't give you the code but will explain the approach.
First you need to pass the property names as a string
In your function you need to split the string based on the delimiter, like .
Keep a reference of current object
Then iterate on all the property names that you got from #2
Fetch current property name from current object and replace current object with the returned value.
return current object at the end.
Note: you need to add some validations in between. I've skipped those for you to explore ;)
You could try recursion:
object1 = {
objectProp1: {
objectProp1Prop1:"Hello",
objectProp1Prop2:"Goodbye",
objectProp1Prop3:{
objectProp1Prop3Prop1: "Come here",
objectProp1Prop3Prop2: "Go away"
},
},
objectProp2: "Yo",
objectProp3: "Seeya",
};
object2 = {
objectProp1: 'test1',
objectProp2: 'test2'
}
var myArray = [object1, object2];
function getProp(objArray, prop) {
for(var key in objArray) {
if (key == prop)
return objArray[key];
if (typeof objArray[key] == 'object')
return getProp(objArray[key], prop);
}
}
//test
document.getElementsByTagName('h1')[0].innerHTML = getProp(myArray[0],'objectProp1Prop3Prop1');
I added a Fiddle for you to try it: https://jsfiddle.net/afabbro/vrVAP/
This question already has answers here:
Accessing nested JavaScript objects and arrays by string path
(44 answers)
Closed 4 years ago.
var person = {
name: 'Joe',
contact: {
phone: '555'
}
}
var nameOfPerson = person['name']; //Joe
var str = 'contact.phone';
var phoneToPerson = person[str]; //undefined
Is this possible to do somehow? I got some logic where I end up with a string and I need to access a nested property with it.
https://jsbin.com/xehokozaco/edit?js,console
You'll have to split the string by the period, and then access each node iteratively. This could be done in a simple reduce:
var value = str.split('.').reduce(function(p,prop) { return p[prop] }, person);
The above would work regardless if str contains a period or not, i.e. for name as well as contact.phone.
You can by splitting the string. the [..] operator lets you access object properties by name (and array items index). In a case of nested objects, you simply access them one after the other.
Try like this:
var person = {
name: 'Joe',
contact: {
phone: '555'
}
}
var nameOfPerson = person['name']; //Joe
var str = 'contact.phone';
var phoneToPerson = str.split('.').reduce(function(o, key) {
return o[key];
}, person);
alert(phoneToPerson);
try
var select = "contact.phone";
var value = person;
select.split(".").forEach(function(val){
value = value[val];
});
console.log(value);
Natively, no. However there are way to do it, like splitting the string by . and recursively descend from the person object. It's also possible by evaluating the full string in eval or new Function, but I highly discourage for security reasons.
I know this post is quite old but its strange I can't see very popular "Lodash" solution here which allows to get object nested properties safely.
Example:
var object = {
a: [
{
b: {
c: 3
}
}
]
};
_.get(object, 'a[0].b.c'); // → 3
For your example:
var person = {
name: 'Joe',
contact: {
phone: '555'
}
}
var personPhoneProp = 'contact.phone';
_.get(person, personPhoneProp); // -> '555'
Documentation: https://lodash.com/docs#get
I want to create a hashtable of json objects, where each json object represents a user.
I want to do this to sort of create a client side 'cache' of users.
User { ID: 234, name: 'john', ..);
So I can then reference things like this:
if(userCache[userid] != null)
alert(userCache[userid].ID);
is this possible?
Javascript objects themselves are maps, so for instance:
var userCache = {};
userCache['john'] = {ID: 234, name: 'john', ... };
userCache['mary'] = {ID: 567, name: 'mary', ... };
userCache['douglas'] = {ID: 42, name: 'douglas', ... };
// Usage:
var id = 'john';
var user = userCache[id];
if (user) alert(user.ID); // alerts "234"
(It wasn't clear to me whether your "userid" would be "john" or 234, so I went with "john" above, but you could use 234 if you preferred.)
It's up to the implementation how the keys are stored and whether the map is a hash map or some other structure, but I've done this with hundreds of objects and been perfectly happy with the performance, even on IE, which is one of the slower implementations (at the moment).
This works because there are two ways to get at the properties of a Javascript object: Via dotted notation, and via bracketed notation. For example:
var foo = {bar: 10};
alert(foo.bar); // alerts "10"
alert(foo['bar']); // alerts "10"
alert(foo['b' + 'a' + 'r']); // alerts "10"
s = "bar";
alert(foo[b]); // alerts "10"
It may seem strange that this bracketed syntax for getting an object property by name is the same as getting an array element by index, but in fact, array indexes are object properties in Javascript. Property names are always strings (in theory), but auto-conversion occurs when you do things like user[234]. (And implementations are free to optimize-out the conversion if they can, provided the semantics are maintained.)
Edit Some bits and pieces:
Looping through the cache
And if you want to loop through the cache (and based on your follow-up question, you do, so perhaps others reading this question will want to too):
var key, user;
for (key in userCache) {
// `key` receives the name of each property in the cache, so "john",
// "mary", "douglas"...
user = userCache[key];
alert(user.ID);
}
The keys are looped in no defined order, it varies by browser.
Deleting from the cache
Suppose you want to delete a property from the cache entirely:
delete userCache['john'];
Now there is no longer a "john" property in the object at all.
This is almost verbatim your code, but it works, yes:
var cache = {}
cache[234] = { id: 234, name: 'john' }
if (cache[1]) alert('Hello ' + cache[1].name);
if (cache[234]) alert('Hello ' + cache[234].name);
Or was your question on how to implement this on the server side too, to get the user cache to the client?
function findUser(users, userid) {
for (var i = 0; i < users.length; i++) {
if (users[i].ID === userid) {
return users[i];
}
}
return null;
}
var users = [{ ID: 234, name: 'john' }, { ID: 235, name: 'smith' }];
var user = findUser(users, 235);
if (user != null) {
alert(user.name);
}
Since all objects in Javascript are really dictionaries, you can do this in a couple ways.
One way might be:
var dict = new Object;
dict.Bobby = { ID: 1, Name: "Bobby" };
if (dict.Bobby != null) alert(dict.Bobby.Name);