Can I write block of code shorter using ES6/ES7 [duplicate] - javascript

This question already has answers here:
One-liner to take some properties from object in ES 6
(12 answers)
Closed 6 years ago.
I have a block of code:
const {address, cityDistrict, city, country} = data;
const obj = {
location: {address, cityDistrict, city, country}
};
But can I write this one shorted? I tried this one, but it's wrong:
const obj = {
location: {address, cityDistrict, city, country} = data
};
Is it possible?

This actually does work (in Chrome at least, in Babel too if you wrap the assignment in parenthesis), but the two pieces of code are not equivalent.
The second piece of code simply assigns data to the location property and creates 4 new variables in scope called address, cityDistrict, etc.
For example:
const data = {
address: "Address",
cityDistrict: "District",
city: "City",
country: "Country"
}
const obj = {
location: ({address, cityDistrict, city, country} = data)
};
console.log(obj);
Looks like it logs the correct data, but what is actually printing is data, not new object. So if we do something like this:
const obj = {
location: ({address, cityDistrict, city, country} = data)
};
data.address = "Test"
console.log(obj); // location.Address = Test
You'd get unexpected data. As a side effect of that, you'd also get 4 new variables in scope:
const obj = {
location: ({address, cityDistrict, city, country} = data)
};
console.log(address, cityDistrict, city, country); // All defined
What you really want to do is to use Object.assign to create a new instance of an object:
const obj = {
location: Object.assign({}, data);
}

This will not work using the es2015 preset, but will work using es2016.
Trying this in https://babeljs.io/repl illustrates this.
Updated
The answer from CodingIntrigue shows why this one does not work.
I also think what you want is currently not achievable with a destructuring one-liner. You'd better stick to your first intent unless you really don't want to have some variables assignments, and in such case you'd likely use an IIFE to filter keys.
As zeroflagl said, you can do it using spread properties if you use ES proposal stage 3.
const data = {
address: 'address',
cityDistrict: 'district',
city: 'city',
country: 'country'
}
const { address, cityDistrict, city, country } = data;
const obj = {
location: {...data}
};
console.log(obj)
/* logs Object {
"location": Object {
"address": "address",
"city": "city",
"cityDistrict": "district",
"country": "country"
}
}
*/

If you want to copy data you can use it:
const obj = {location: Object.assign({}, data)}
Or you also can use next code, but changing obj.location can change data:
const obj = {location: data}

Related

How to convert a 2D Javascript array to object with identifiers

What's the best way to convert a 2D array into an object with identifiers that count up?
There could be an unlimited number of identifiers in the object - based on what's in the array.
So in the array we might have
data: [
["Lisa", "Heinz"],
["Bob", "Sleigh"]
]
And we'd be keen that the array looked something like this in the end:
data: {
person1 {
{name: Lisa},
{last_name: Heinz}
},
person2 {
{name: Bob},
{last_name: Sleigh}
}
}
Using map I can create an array of objects, but this isn't quite
json = formData.map(function(x) {
return {
"name": x[0],
"last_name": x[1]
}
})
console.log(json);
Something like this? I changed your object structure a bit to be easier to access.
let newDataObj = {}
for (let person of data) {
const identifier = `person${data.indexOf(person)}`;
const [name, last_name] = person;
newDataObj[identifier] = { name, last_name };
}

How to create create a new custom(specific) object and map the data from Array of object

I get a response from backend which is an array of object which is as below mentioned
[{"userID":1,"firstName":"George","lastName":"Russell","addressID":"1","address_value":"27 London Street E146AA","expDate":"2022-12-12T17:09:37.000Z"},{"userID":1,"firstName":"George","lastName":"Russell","phoneId":"1","phone_value":"97627445368"},{"userID":2,"firstName":"George","lastName":"Russell","phoneId":"2","phone_value":"07884076692"},{"userID":1,"firstName":"George","lastName":"Russell","emailId":"1","email_value":"georgerussell#outlook.com"},{"userID":1,"firstName":"George","lastName":"Russell","employerId":"1","employer_value":"QMUL"},{"userID":28,"firstName":"Binny","lastName":"Bansal","employerId":"2","employer_value":"Google Inc"},{"userID":1,"firstName":"George","lastName":"Russell","nationalityId":"1","nationality":"Indian"},{"userID":1,"firstName":"George","lastName":"Russell","passportId":"1","passportNumber":"123445567"}]
I am trying to get all the details of users from the backend which are stored in different tables like a separate table for Phone, Address, Email etc. And similarly for EmailShared or PhoneShared which contains the information regarding with which organisation has the information has been shared. As we can see that HSBC has the address of George.
But what I want to try and do is that have all the information in a single object instead of a different one for each attribute(address, phone, email).
What right now we have is the below one
[
{
addressID: "1"
address_value: "27 London Street E146AA"
expDate: "2022-12-12T17:09:37.000Z"
firstName: "George"
lastName: "Russel"
userID: 1
},
{
firstName: "George"
lastName: "Russel"
phoneId: "1"
phone_value: "97627445368"
userID: 1
}
]
What I am trying to achieve is something which has phone number and address as an example but would love to have all the attributes(phone, email, passport, employer, address etc) .
{
addressID: "1"
address_value: "27 London Street E146AA"
expDate: "2022-12-12T17:09:37.000Z"
firstName: "George"
lastName: "Russel"
userID: 1
phoneId: "1"
phone_value: "97627445368"
emailId:"1",
email_value:"georgerussell#outlook.com"
employerId:"1"
employer_value:"QMUL"
nationalityId:"1"
nationality:"Indian"
passportId:"1"
passportNumber:"123445567"
},
I was trying to do it with the following code as we have the userId as unique property and based on that I was trying to have the desired output but I cannot understand what am I missing in here.
result = data.reduce(function (r, a) {
r[a.userID] = r[a.userID] || [];
r[a.userID].push(a);
return r;
}, Object.create(null));
console.log(result);
const finalResult = [];
Object.keys(result).forEach(el => {
result[el].forEach(el1 => {
console.log(el1)
//finalResult.push(...el1)
})
})
You were on the right track, just needs little improvement like using Object.values() instead of Object.keys(); and I used logical nullish assignment (??=)
const data = [{"userID":1,"firstName":"George","lastName":"Russell","addressID":"1","address_value":"27 London Street E146AA","expDate":"2022-12-12T17:09:37.000Z"},{"userID":1,"firstName":"George","lastName":"Russell","phoneId":"1","phone_value":"97627445368"},{"userID":2,"firstName":"George","lastName":"Russell","phoneId":"2","phone_value":"07884076692"},{"userID":1,"firstName":"George","lastName":"Russell","emailId":"1","email_value":"georgerussell#outlook.com"},{"userID":1,"firstName":"George","lastName":"Russell","employerId":"1","employer_value":"QMUL"},{"userID":28,"firstName":"Binny","lastName":"Bansal","employerId":"2","employer_value":"Google Inc"},{"userID":1,"firstName":"George","lastName":"Russell","nationalityId":"1","nationality":"Indian"},{"userID":1,"firstName":"George","lastName":"Russell","passportId":"1","passportNumber":"123445567"}];
const result = data.reduce(function(r, a) {
r[a.userID] ??= []; // it's the same as r[a.userID] = r[a.userID] || [];
r[a.userID].push({ ...a
});
return r;
}, {}); //Object.create(null)
let finalResult = [];
Object.values(result).forEach((arrObj) => {
let result = {};
Object.values(arrObj).forEach((obj) => {
Object.assign(result, obj);
});
finalResult.push(result);
});
console.log(finalResult);
For this type of problem, I would go with changing how the backend service operates; where it should doing a JOIN on the multiple tables so that you only get one object for each user, instead multiple.
That being said, I would accomplish this easiest with a map.
const result = [{"userID":1,"firstName":"George","lastName":"Russell","addressID":"1","address_value":"27 London Street E146AA","expDate":"2022-12-12T17:09:37.000Z"},{"userID":1,"firstName":"George","lastName":"Russell","phoneId":"1","phone_value":"97627445368"},{"userID":2,"firstName":"George","lastName":"Russell","phoneId":"2","phone_value":"07884076692"},{"userID":1,"firstName":"George","lastName":"Russell","emailId":"1","email_value":"georgerussell#outlook.com"},{"userID":1,"firstName":"George","lastName":"Russell","employerId":"1","employer_value":"QMUL"},{"userID":28,"firstName":"Binny","lastName":"Bansal","employerId":"2","employer_value":"Google Inc"},{"userID":1,"firstName":"George","lastName":"Russell","nationalityId":"1","nationality":"Indian"},{"userID":1,"firstName":"George","lastName":"Russell","passportId":"1","passportNumber":"123445567"}];
const newUserMap = new Map();
result.forEach((user) => {
const { userID } = user;
if (newUserMap.has(userID)) {
const existingUser = newUserMap.get(userID);
newUserMap.set(userID, {...existingUser, ...user});
} else {
newUserMap.set(userID, user);
}
});
console.log(newUserMap);
Where the keys are the user ids and the values within them are the user objects. You are also able to run through each entry with a .forEach() loop; just like an array.
If you want to keep them as an array of objects, then you could accomplish this with something similar to a map, but it is quite costly in performance due to the .findIndex():
const result = [{"userID":1,"firstName":"George","lastName":"Russell","addressID":"1","address_value":"27 London Street E146AA","expDate":"2022-12-12T17:09:37.000Z"},{"userID":1,"firstName":"George","lastName":"Russell","phoneId":"1","phone_value":"97627445368"},{"userID":2,"firstName":"George","lastName":"Russell","phoneId":"2","phone_value":"07884076692"},{"userID":1,"firstName":"George","lastName":"Russell","emailId":"1","email_value":"georgerussell#outlook.com"},{"userID":1,"firstName":"George","lastName":"Russell","employerId":"1","employer_value":"QMUL"},{"userID":28,"firstName":"Binny","lastName":"Bansal","employerId":"2","employer_value":"Google Inc"},{"userID":1,"firstName":"George","lastName":"Russell","nationalityId":"1","nationality":"Indian"},{"userID":1,"firstName":"George","lastName":"Russell","passportId":"1","passportNumber":"123445567"}];
const newUserArray = [];
result.forEach((user) => {
const { userID } = user;
const existingUserIndex = newUserArray.findIndex(newUser => newUser.userID === userID);
if (existingUserIndex !== -1) {
newUserArray[existingUserIndex] = Object.assign(newUserArray[existingUserIndex], user);
} else {
newUserArray.push(user);
}
});
console.log(newUserArray);

React object property value being duplicated on .push inside loop

I have a handleCreate function that takes care of taking some user data and inserting it into a database.
Inside the aliasArr.forEach() loop I POST into my DB new user instances for each element in the aliasArr array. This particular code works as expected, if I check the DB, I will find the new members.
After saving the new members, I want to keep the members in the members array so I can pass it along to another function.
For this, I'm doing members.push(memberAttributes); but if I log the contents of members I get the right amount of elements but the alias property value is duplicated (all other properties should have the same value cause they are being added into the same role in a batch operation).
If I have two new users, say: xyz and abc, I get:
[
{alias: "abc", Role: "admin", "grantedBy": "someone"},
{alias: "abc", Role: "admin", "grantedBy": "someone"},
]
Instead of:
[
{alias: "xyz", Role: "admin", "grantedBy": "someone"},
{alias: "abc", Role: "admin", "grantedBy": "someone"},
]
Here's the code:
handleCreate = () => {
const { memberAttributes } = this.state;
const { role, createRoleMember } = this.props;
const roleArr = [];
roleArr.push(role);
const aliasArr = memberAttributes.alias.split(",");
let members = [];
//false hardcoded during debugging.
if (false /* await aliasIsAdmin(memberAttributes.alias, roleArr) */) {
this.setState({ userExists: true });
} else {
memberAttributes["Granted By"] = window.alias;
memberAttributes.Role = role;
memberAttributes.timestamp = Date.now().toString();
this.handleClose();
aliasArr.forEach((currAlias) => {
memberAttributes.alias = currAlias;
console.log("memberAttributes:", memberAttributes);
members.push(memberAttributes);
console.log("members", members);
const marshalledObj = AWS.DynamoDB.Converter.marshall(memberAttributes);
const params = {
TableName: "xxx",
Item: marshalledObj,
};
axios.post(
"https://xxx.execute-api.us-west-2.amazonaws.com/xxx/xxx",
params
);
});
}
createRoleMember(members); //passing members to this function to do more stuff.
};
I'm wondering if this issue is due to memberAttributes being part of the component's state.
The problem here is that you are pushing references to the same object into the array after changing a value within that object. So whenever you make the change to memberAttributes.alias, it's changing the alias to the most recent one. After that, all references to the same object (which in this case is every item in the members array) present the new value in alias.
const obj = { alias: 'abc', role: 'role1' }
const arr = []
arr.push(obj)
obj.alias = 'new alias'
arr.push(obj)
for (var mem of arr) {
console.log(mem)
}
To fix it, you need to create a new object each time and push it onto the array instead, like so:
aliasArr.forEach((currAlias) => {
// Creates a new object in memory with the same values, but overwrites alias
const newMemberAttributes = Object.assign(memberAttributes, { alias: currAlias });
console.log("memberAttributes:", newMemberAttributes);
members.push(newMemberAttributes);
console.log("members", members);
...
}
Similarly, you can use the spread operator to create a deep copy of the object and then reassign alias.
aliasArr.forEach((currAlias) => {
// Creates a new object in memory with the same values, but overwrites alias
const newMemberAttributes = { ...memberAttributes };
newMemberAttributes.alias = currAlias
console.log("memberAttributes:", newMemberAttributes);
members.push(newMemberAttributes);
console.log("members", members);
...
}

ES6 object namespacing

I came across some syntax I haven't seen before. When I deal with objects and when using React, you can simplify namespacing by doing such as
let {someProp} = prevProps
Doing this allows me to avoid writing prevProps.someProp everytime I want to use it.
What I don't understand is this syntax
let {someProp: oldData} = prevProps
console.log(someProp) will show the value of the prevPros.someProp but WHERE does oldData come from???
console.log(olddata) above this line will show undefined but console.log(oldData) underneath will show the previous props.
let {someProp: myAlias} = prevProps
This syntax allows you use an alias, for example you can use myAlias in your code, instead someProp, it is called Object destructuring
As stated in the comments by #FelixKling here is the official reference.
Example from provided link:
let o = {p: 42, q: true};
let {p: foo, q: bar} = o;
console.log(foo); // 42
console.log(bar); // true
Yes:
let {someProp} = prevProps
is similar to this:
let someProp = prevProps.someProp;
And this:
let {someProp: oldData} = prevProps
would be similar to this:
let oldData = prevProps.someProp
Take a look at this link
Basically you are destructuring prevProps and in this case oldData will now be have the value of someProp
This syntax is one of the shiny new things in ES6 called object destructuring.
Here's an elaborate example on how you can use destructuring in different ways
const person = {
first: 'Jack',
last: 'Daniels',
address: {
city: 'Dallas',
}
};
// destructure as it is
const { first, last } = person;
// destructure with custom name
const { first: firstName, last: lastName } = person;
// destructure with default value
const { first, last, middle = 'The Boss' } = person;
// destructure with custom name and default value
const { first, last, middle: middleName = 'The Boss' } = person;
// destructure nested keys
const { first, last, address: { city } } = person;
// destructure nested keys with custom name
const { first, last, address: { city: myCity } } = person;
// destructure nested keys safely
const { first, last, address: { city } = {} } = person;
// destructure rest of the values
const { first, ...rest } = person; // => rest will have all keys but first

Best way to rename object properties in ES6

I'm still learning js and I need an advice. I get json object from backend, but keys have underscores. What is best practice to rename keys to, for example folder_name to Folder name? The list of properties is known and finished so I can keep new names in constants. At frontend I already use it like this:
const showPropertiesList = properties => Object.keys(properties).map(property => (
<PropertyKey key={property}}>
`${property}: ${properties[property]}`
</PropertyKey>
));
It's better to use rename function in this map or create separate function before to get all renamed keys with values?
json file:
properties {
folder_name: 'test',
user_email: 'test#example.com',
user_agreed: 1,
site: 'example.com',
}
You can create some kind of a mapping object and then use the following combination of Object.keys and reduce functions:
const properties = {
folder_name: "test",
user_email: "test#example.com",
user_agreed: 1,
site: "example.com"
};
const mapping = {
folder_name: "Folder name",
user_email: "User email",
user_agreed: "User agreed",
site: "Site"
};
const mapped = Object.keys(properties).reduce((acc, key) => {
acc[mapping[key]] = properties[key];
return acc;
}, {});
console.log(mapped);
try this:
const { folder_name: folderName, user_email: email, ...others } = originObject;
const renamedPropsObject = { folderName, email, ...others }
Am traveling so I can’t program atm. But I think this will drive you in the correct direction.
let newArray = array()
oldArray.forEach(function(value, key) {
// do stuff here to change the key value
let newKeyValue = //something
newArray[newKeyValue] = value;
});
// do stuff with newArray
Hope it helps. Not tester it!
Mapping is a good approach, as the previous answer specifies.
In your case you can also do the renaming inline:
const showPropertiesList = properties => Object.keys(properties).map(property => (
<PropertyKey key={property}}>
`${property.replace('_', ' ')}: ${properties[property]}`
</PropertyKey>
));
Depending on if you want it changed everywhere or just where presented to the user

Categories

Resources