Can we add properties to immutable object in JavaScript? - javascript

An object is like:
const obj = [{name: 'Alex', age: 20}, {name: 'James', age: 22}];
This obect is immutable from Immutable.js.
Is it possible to add a new key for each object? example:
const obj = [{name: 'Alex', age: 20, city: 'New York'}, {name: 'James', age: 20, city: 'Rome'}];

Not if it’s immutable. But that is ok, you can copy all the properties over to a new structure and add whatever you need to that way:
const newData = obj.map(person => ({
...person,
city: someLogicToDetermineCity(person)
}))
function someLogicToDetermineCity(person) {
// logic based on person
return city
}

const doesn't create immutability - it just means that the reference assigned to it on creation cannot be changed later (which simply means that you cannot assign a new value to it).
See these examples:
const a = {}
a = { name: "peter" } // => TypeError: invalid assignment to const `a'
However it's no problem to assign a property on a:
const a = {}
a.name = "peter"
console.log(a); // => { "name": "peter" }
The same applies for Array objects:
const arr = [{}]
arr.push(1);
arr[0].name="peter"
console.log(arr);
// [
// {
// "name": "peter"
// },
// 1
// ]

Related

Lodash merge two objects but replace the same key values with new object value

I have two objects with some common keys but different values like below.
const object1 = {
name: 'John',
age: 23,
books: ['book1', 'book2']
};
const object2 = {
name: 'John',
age: 23,
books: ['book3'],
city: 'London'
};
I need the desired output as follows
object3 = {
name: 'John',
age: 23,
books: ['book3'],
city: 'London'
};
When I do the merge using lodash as below
object3 = _.merge(object1 , object2);
the output I am getting is
const object3 = {
name: 'John',
age: 23,
books: ['book1','book2','book3'],
city: 'London'
};
How can I replace the books array with the new data from object2?
Lodash is trying to be helpful by recursively merging subobjects
This method is like _.assign except that it recursively merges own and inherited enumerable string keyed properties of source objects into the destination object. Source properties that resolve to undefined are skipped if a destination value exists. Array and plain object properties are merged recursively. Other objects and value types are overridden by assignment. Source objects are applied from left to right. Subsequent sources overwrite property assignments of previous sources.
https://lodash.com/docs/4.17.15#merge (emphasis mine)
If you don't want this to happen, just use the standard ES6 spread operator ... or Object.assign
const object1 = {
name: 'John',
age: 23,
books: ['book1', 'book2']
};
const object2 = {
name: 'John',
age: 23,
books: ['book3'],
city: 'London'
};
object3 = {...object1, ...object2};
object4 = Object.assign({}, object1, object2);
console.log(object3);
console.log(object4);
/* make the Stack Overflow console bigger */ .as-console-wrapper { max-height: 100vh !important; }

Filtering object keys inside an array of objects

Let's assume I'm obtaining an array of objects from a Node Repository, for example:
results = [
{
name: "John",
surname: "Fool",
age: 22
},
{
name: "Erik",
surname: "Owl",
age: 38
}
]
How can I filter every object taking only the keys I need, for example avoiding 'age' key?
filteredResults = [
{
name: "John",
surname: "Fool",
},
{
name: "Erik",
surname: "Owl",
}
]
I've already obtained this by creating another empty array and populating it by looping on the original one, but in case of large-data this would be heavy.
repository.retrieve((error, result) => {
let filteredData = [];
result.forEach(r => {
filteredData.push({
name: r.name,
description: r.description,
});
});
});
In SQL, I would obtain it this way:
SELECT `name, description` FROM results;
You can just rebuild the object as you want
{
name: rec.name,
surname: rec.surname
}
const results = [
{
name: "John",
surname: "Fool",
age: 22
},
{
name: "Erik",
surname: "Owl",
age: 38
}
]
const result = results.map((rec) => {
return {
name: rec.name,
surname: rec.surname
}
})
console.log(result)
Or delete fields that is useless
const results = [
{
name: "John",
surname: "Fool",
age: 22
},
{
name: "Erik",
surname: "Owl",
age: 38
}
]
const result = results.map((rec) => {
delete rec.age
return rec
})
console.log(result)
I suggest you can tell more about what you will need to perform on the output to get the answer that can help.
Case 1. if your original list will survive and you accept your "modified list" to always follow the original list, you may use a generator to wrap your original object, by always not returning those extra properties.
Case 2. if you really want a query system, you may try using real DB thing such as levelDB
Case 3. if you need to display the modified list, write a simple wrapper to fit the format of each list item
Case 4. if you need to snapshot the modified list as object, the method you already made is already a very reasonable method
Case 5. if you need to snapshot the modified list as another output, you can try to directly obtain such output rather than making the intermediate object
You can use map and reduce to simplify this, which obviates the need to create a new array.
var results = [ { name: "John", surname: "Fool", age: 22 }, { name: "Erik", surname: "Owl", age: 38 } ];
let keys = ['name', 'surname'];
var filtered = results.map(obj=>
keys.reduce((acc,curr)=>(acc[curr]=obj[curr],acc), {}));
console.log(filtered);
You can also use object destructuring.
var results = [ { name: "John", surname: "Fool", age: 22 }, { name: "Erik", surname: "Owl", age: 38 } ];
var filtered = results.map(({name,surname})=>({name,surname}));
console.log(filtered);
Take a look at Array.map.It creates the transformed array.
let arr = [
{
name: "John",
surname: "Fool",
age: 22
},
{
name: "Erik",
surname: "Owl",
age: 38
}
]
let result = arr.map((elem) => {
return {
name: elem.name,
surname: elem.surname
}
});
console.log(result);
You can use Array.map() to transform individual elements of the array. And in the callback function use Object destructuring assignment to use only the keys you are interested in and return a new object with only those keys.
let results = [
{ name: "John", surname: "Fool", age: 22 },
{ name: "Erik", surname: "Owl", age: 38 }
];
let modified = results.map(({name, surname}) => ({name, surname}));
console.log(modified);

How overwrite and combine two objects in js?

I have two objects.
ObjectA = {name: 'Peter', age: 56, country: 'USA'}
ObjectB = {age: 34}
I want to update ObjectA to become
{name: 'Peter', age: 34, country: 'USA'}
if (ObjectB) {
const newObject = ObjectA[Object.keys(ObjectB)[0]] === ....
}
What would be a better way to update ObjectA?
ES9/Regular Javascript
let object1 = {
foo: 'foo'
}
let object2 = {
bar: 'bar'
}
console.log({ ...object1, ...object2 })
console.log(Object.assign(object1, object2))
Just use Object.assign(ObjectA, ObjectB)

Using template literal for dynamic property in ReactJS

My failed attempt:
temp.map((obj,i) => ({
obj[`person${++i}`] = obj.person.name
})
I want to produce something like this
[{id:324, person1:'mike'},{id:23, person2:'jane'}]
But I'm stuck on making the property dynamic with concatenation using template literal string.
Issue with you code is, you are directly returning the data by using
() => ({....})
and there you are using obj[...] that is not a valid key.
map return the a new array so store the result in a new variable, if you want to modify the same array then better to use forEach.
Check this snippet:
let arr = [{id: 10, name: 'A'}, {id: 20, name: 'B'}];
let newArr = arr.map((el,i) => ({
id: el.id,
[`name${i+1}`]: el.name
}));
console.log('new array', newArr);
Modifying the same data using forEach:
let arr = [{id: 10, name: 'A'}, {id: 20, name: 'B'}];
arr.forEach((el,i) => {
el[`person${i+1}`] = el.name;
})
console.log('modified array', arr);
This should do it:
var myInput = ["John", "Jane", "Steven", "Alice"];
var myOutput = myInput.map ((name, index) => {
var out = {};
out[`person${index}`] = name;
return out;
}); // myOutput is [{person1:"John"}, {person2:"Jane"} ... etc.
map creates a new array rather than modifying the existing one. The values of the array are made out of the return values of the function, so if you want your values to be objects, you must create new objects and then assign your properties to them.
How about this?
describe("sample test", () => {
it("Dynamic property in ES6", () => {
const temp = [
{ id: 324, person: { name: "mike" } },
{ id: 23, person: { name: "jane" } }
];
console.log(
temp.map((obj, i) => ({
id: obj.id,
[`person${i + 1}`]: obj.person.name
}))
);
});
});
Output:
[ { id: 324, person1: 'mike' }, { id: 23, person2: 'jane' } ]

how to destruct part of properties from an object

For example, I got an object like this:
obj1 = {
name: 'Bob',
age: 20,
career: 'teacher'
}
Now I need to duplicate part of its properties instead all of them.
obj2 = {
name: '',
age: '',
}
I know I can do it like obj2.name = obj1.name, which will be verbose if many properties need to be duplicated. Are there any other quick ways to solve this problem?
I tried
let {name: obj2.name, age: obj2.age} = obj1;
but got error.
Actually you don't need object destructuring, just simple assignment:
obj2 = { name: obj1.name, age: obj1.age }
Now, obj2 holds wanted properties:
console.log(obj2);
// Prints {name: "Bob", age: 20}
If you want to merge old properties of obj2 with new ones, you could do:
obj2 = { ...obj2, name: obj1.name, age: obj1.age }
Drop the let (you're not declaring variables) and surround with parentheses:
({name: obj2.name, age: obj2.age} = obj1);
I guess you can use ES6 Object destructuring syntax
var obj = { name: 'kailash', age: 25, des: 'backenddev'}
({name} = obj);
You could use the target object as template for the properties and assign the values of obj1 with a default value of the target object.
var obj1 = { name: 'Bob', age: 20, career: 'teacher' },
obj2 = { name: '', age: '' };
Object.keys(obj2).forEach(k => obj2[k] = obj1[k] || obj2[k]);
console.log(obj2);
Another solution would be to write a reuable method for this. You can supply an object and the methods you would like to copy.
const duplicatePropertiesFromObject = (obj, propertyNames = [], newObj = {}) => {
Object.keys(obj).forEach((key) => {
if (propertyNames.includes(key)) {
newObj[key] = obj[key];
}
});
return newObj;
}

Categories

Resources