ES6 object namespacing - javascript

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

Related

React setState Array Hook doesn't re-render component [duplicate]

I want to update value of one object only but updating value of one Object, Updates the value for all objects.
let default = {
name: '',
age: ''
}
this.state = {
values: Array(2).fill(default)
}
updateName (event) {
let index = event.target.id,
values = this.state.values;
values[index].name = event.target.value;
this.setState ({
values: values
});
}
There are four significant problems in that code.
You're using the same object for all entries in your array. If you want to have different objects, you have to create multiple copies of the default.
You're calling setState incorrectly. Any time you're setting state based on existing state (and you're setting values based, indirectly, on this.state.values), you must use the function callback version of setState. More: State Updates May Be Asynchronous
You can't directly modify the object held in this.state.values; instead, you must make a copy of the object and modify that. More: Do Not Modify State Directly
default is a keyword, you can't use it as an identifier. Let's use defaultValue instead.
Here's one way you can address all four (see comments):
// #4 - `default` is a keyword
let defaultValue = {
name: '',
age: ''
};
this.state = {
// #1 - copy default, don't use it directly
values: [
Object.assign({}, defaultValue),
Object.assign({}, defaultValue),
] // <=== Side note - no ; here!
};
// ....
updateName(event) {
// Grab the name for later use
const name = event.target.value;
// Grab the index -- I __don't__ recommend using indexed updates like this;
// instead, use an object property you can search for in the array in case
// the order changes (but I haven't done that in this code).
const index = event.target.id;
// #2 - state updates working from current state MUST use
// the function callback version of setState
this.setState(prevState => {
// #3 - don't modify state directly - copy the array...
const values = prevState.values.slice();
// ...and the object, doing the update; again, I wouldn't use an index from
// the `id` property here, I'd find it in the `values` array wherever it
// is _now_ instead (it may have moved).
values[index] = {...values[index], name};
return {values};
});
}
Note that this line in the above:
values[index] = {...values[index], name};
...uses property spread syntax added in ES2018 (and shorthand property syntax, just name instead of name: name).
I would use the Array.prototype.map function with combination of the object spread syntax (stage 4):
Note that i changed the name of the default object to obj.
default is a reserved key word in javascript
let obj = {
name: '',
age: ''
}
this.state = {
values: Array(2).fill(obj)
}
updateName(event){
const {id, value} = event.target;
this.setState(prev => {
const {values} = prev;
const nextState = values.map((o,idx) => {
if(idx !== id)
return o; // not our object, return as is
return{
...o,
name: value;
}
});
return{
values: nextState
}
});
}
There is an easy and safe way to achieve that through the following:
this.setState({
values: [ newObject, ...this.state.values],
});
this will create an instance of the state and change the value of an existing object with new object.

How to Set a Javascript Object Key to Be Another Object's Value

I have an Javascript object called person with various properties such as id, name, phone, etc.
I want to create a new Javascript object called roster that is just the name. Something like this:
let person = { name: "Hilda", "id": 123, "phone": 000-000-0000 };
let roster = { person.name : person.phone };
However, React throws an error having person.name in the key. It doesn't matter if I do person.name or person["name"]. I have to do:
let roster = {};
roster[person.name] = person.phone;
Is there some special syntax to allow person.name to be set as the key directly, or is the work-around required?
Use []
let person = { name: "Hilda", "id": 123, "phone": "000-000-0000" };
let roster = { [person.name] : person.phone };
console.log(roster)
Vugar's answer is correct, this can be done by placing brackets [] around the first object's property name.
This is called a computed property name. From the MDN web docs:
The object initializer syntax also supports computed property names.
That allows you to put an expression in brackets [], that will be
computed and used as the property name. This is reminiscent of the
bracket notation of the property accessor syntax, which you may have
used to read and set properties already.
Now you can use a similar syntax in object literals, too:
// Computed property names
let i = 0;
const a = {
[`foo${++i}`]: i,
[`foo${++i}`]: i,
[`foo${++i}`]: i,
};
console.log(a.foo1); // 1
console.log(a.foo2); // 2
console.log(a.foo3); // 3
const items = ["A", "B", "C"];
const obj = {
[items]: "Hello",
};
console.log(obj); // A,B,C: "Hello"
console.log(obj["A,B,C"]); // "Hello"
const param = 'size';
const config = {
[param]: 12,
[`mobile${param.charAt(0).toUpperCase()}${param.slice(1)}`]: 4,
};
console.log(config); // {size: 12, mobileSize: 4}
MDN Docs Reference

Refactoring a destructuring into an object destructuring

I am refactoring my code, which involves converting a big list of let statements into an object called personDetails:
personDetails = {
firstName: '',
lastName: '',
zipcode: 'xyz',
age: 20,
gender: 'm'
}
Currently, I am destructuring the values returned from my array like this:
[firstName, lastName] = getNames(zipcode, age, gender)
This works fine. But now that I am switching to an object, how do I update that object with the returned values? I will be passing in the object as an argument like this:
getNames(personDetails)
Do I have to do something like this?
personDetails = getNames(personDetails)
The called function might look something like this (abbreviated):
const getNames(personDetails) => {
personDetails.firstname = 'Jack'
personDetails.lastName = 'Jones'
}
1) Your arrow function had a typo, you must declare it with an = before the argument, like this:
const getNames = (personDetails) => { // Correct
const getNames(personDetails) => { // Incorrect
2) Inside your function, you weren't modifying an object key, but creating a new one instead. Remember that objects keys differs if you use upper or lowercase letters, firstName and firstname are not the same key.
3) Last, when you create an argument in your function, do not declare it with the same name of the global object, since it could create unexpected results. Then, you don´t need to destructure your object, just return the complete object.
let personDetails = { // Using let
firstName: '',
lastName: '',
zipcode: 'xyz',
age: 20,
gender: 'm'
};
const getNames = (obj) => { // obj is the argument
obj.firstName = 'Jack';
obj.lastName = 'Jones';
return obj; // Return complete object
}
personDetails = getNames(personDetails);
console.log(personDetails);
If you want to destructure the object, you can do it too the same way you do it with the array, but I wouldn´t recommend it because it makes the code less clear:
const personDetails = { // Using const
firstName: '',
lastName: '',
zipcode: 'xyz',
age: 20,
gender: 'm'
};
const getNames = (obj) => { // obj is the argument
obj.firstName = 'Jack';
obj.lastName = 'Jones';
return [obj.firstName, obj.lastName]; // Return part of object as an array
}
[personDetails.firstName, personDetails.lastName] = getNames(personDetails);
console.log(personDetails);

Iterating through a an array executing a switch statement returns TypeError: Cannot assign to read only property 'location' of object '#<Object>'

I have a read only array that i copied to become a mutable array let mutableForecast = [...forecast] I am taking that new array and iterating through it with forEach so i can mutate the array. im trying to use some flow control with a switch statement, but I am getting TypeError: Cannot assign to read only property 'location' of object '#<Object>'
let mutableForecast = [...forecast]
mutableForecast.forEach((obj, i) => {
switch (obj.location) {
case obj.location === "BRITISH_COLUMBIA":
obj.location = "BC"
break;
default:
obj.location = "oother"
}
})
Whats the issue here? I've look at this, this, this and some others but cannot find an answer.
This is what the forecast array looks like before i copied it
It's hard to be sure without knowing where forecast comes from, but I suspect the problem is that the elements of the array are not plain objects, but instances of a custom type that are defined as immutable. Your third link has the likely solution. The key is that you can't convert an array of immutables into an array of mutables simply by using rest & spread in this way. You need to modify the mutability of each item in the array individually.
You probably need something like this:
let mutableForecast = [...forecast]
mutableForecast.forEach((obj, i) => {
// make this element's location property mutable
Object.defineProperty(obj, 'location', { writable: true })
// calculate and set new value
switch (obj.location) {
case 'BRITISH_COLUMBIA':
obj.location = 'BC'
break;
default:
obj.location = 'other'
}
})
This might also work, and I think it's cleaner. You'd have to try it to be sure:
let mutableForecast = Array.from(forecast)
.map(forecastItem => ({
...forecastItem,
location: getShortLocation(forecastItem.location)
}))
function getShortLocation( sourceLocation ) {
switch (sourceLocation) {
case 'BRITISH_COLUMBIA': return 'BC'
default: return 'other'
}
}
The core problem we're working around is that whatever package gives you forecast, it clearly trafficks in some custom datatype, some of whose properties are defined as immutable. That fact doesn't show up when you log the objects, and it isn't changed when you convert an array-like container into an array.
That's because [...forecast] doesn't edit the items, it just copies them as-is from one data structure into another. Actually, be to precise, it copies references to those objects into a new array. If the original objects are weird things with locked properties, then your new array will consist of weird things with locked properties. If we want to change the value of that property on each element, we need to redefine the property before doing so.
Consider a case like this:
let myDog = {
species: 'dog',
name: 'Fido'
}
//> myDog { species: 'dog', name: 'Fido' }
We can create another object with the same properties like so:
let congruentAnimal = {
...myDog
}
//> congruentAnimal { species: 'dog', name: 'Fido' }
If the same property names occurs twice, the engine will only honor the last one:
let myDog = {
species: 'cat',
name: 'Fido',
species: 'dog' // this will cause cat to be ignored
}
//> myDog { name: 'Fido', species: 'dog' }
So, we can override individual object properties while copying by re-declaring those properties last:
let anotherCongruentAnimal = {
...myDog,
species: 'NEW DOG'
}
//> anotherCongruentAnimal { name: 'Fido', species: 'NEW DOG' }
That's what is going on in that second snippet. Here's an expanded version:
// create a real array whose elements are *references* to
// the objects in the array-like forecast
let arrayOfImmutableForecasts = Array.from(forecast)
// create another real array of new objects
// whose property names, values, and metadata are
// the same as the source objects
let arrayOfMutableForecasts = arrayOfImmutableForecasts.map(originalObject => {
let newObject = {
// I think this will also preserve special rules like immutability
...originalObject,
// before we finalize the object, we declare a new simple property
// the engine will _drop_ the implied prop declaration from above
// and define the prop based on this simple declaration instead
location: 'new value'
}
return newObject
})
It seems like you are not allowed to mutate the location property of the objects in the array...
You can try creating a clone of the object and mutate that:
let mutableForecast = [...forecast]
mutableForecast = mutableForecast.map(obj => {
const location = obj.location
const objClone = {}
for (const key in obj) {
if (key !== 'location') objClone[key] = obj[key]
}
switch (location) {
case "BRITISH_COLUMBIA":
objClone.location = "BC"
break;
default:
objClone.location = "other"
}
return objClone
})
If that fails, you can try creating a new property insteade, and later read that property:
let mutableForecast = [...forecast]
mutableForecast.forEach((obj, i) => {
switch (obj.location) {
case "BRITISH_COLUMBIA":
obj.newLocation = "BC"
break;
default:
obj.newLocation = "other"
}
})

How to use the Array find function to return an object in JavaScript

I have this Homework that requires me to pass a parameter called userID to an arrow function. Inside this function, I am required to use the .find function on an array called users. this find function should return an object containing the userID. Here is the full instruction :
Create a getSelectedUser arrow function above
displaySelectedUser. It should take a userId parameter and use the Array .find function on the users collection to find and
return the selected user object. Your .find call should take an inline
arrow function and de-structure its parameter to obtain the id
property.
the users is an array: users =
[{
age: 50,
weight: 55,
height: 6,
country: 'US',
name: 'Bob Manuel',
id: 'ehriuiuye'
},
{
age: 20,
weight: 80,
height: 6,
country: 'UK',
name: 'Michael Lawrence',
id: 'fjikijd'
}];
what I have done
const getSelectedUser = (userId) =>{
users.find(element => element.id === userId);
};
Now, the auto-grader returns this error:
Create a "getSelectedUser" function that returns the selected "user
object". See the instructions for details.
Is there anything wrong with the function I created?
try this:
const getSelectedUser = (userId) => users.find(({id}) => id == userId)
I guess what could be missing is the "destructuring" mentioned in the instructions. Destructuring is the process of assigning selected properties of an object to variables. For example, if you have an object
const foo = {
bar: "hi",
baz: "friend"
}
you could either access it’s properties via foo.bar and foo.baz or by destructuring the object with
const {bar, baz} = foo;
which would define two variables bar and baz.
In your case you could do the destructuring instead of specifying the element parameter of the arrow function.
Edit:
As was pointed out in a comment, you're not returning anything from the getSelectedUser function. You would need to do return user.find(element => ...) or maybe return user.find(({id}) => ...)
Edit 2:
The full code should be:
const getSelectedUser = (userId) => {
return users.find(({id}) => id === userId);
};
or the short version:
const getSelectedUser = (userId) => users.find(({id}) => id === userId);

Categories

Resources