Javascript Property with three dots (...) - javascript

I have a problem with code I am supposed to work with. I found a syntax I am not familiar with and I have trouble googling the documentation:
export const Something = class Something {
constructor(someObject = {}) {
this.someObject = {...Something.someObjectDefaultAsStaticMethod,...someThing};
};
// The rest of the class
};
I have problems understanding what the three dots (...) in front of the parameter do. And "dots in parameter javascript" is a bad search term. Can someone help me, maybe tell me what this syntax is actually called or just directly link me to documentation?

That is not ES6 but has only been added in ECMAScript 2018.
It is called "Object Rest/Spread Properties" and is part of the Spread Syntax.

... (three dots in Javascript) is called the Spread Syntax or Spread Operator. This allows an iterable such as an array expression or string to be expanded or an object expression to be expanded wherever placed.
I want to list down the mostly used practical Use Cases of the Spread Syntax (Spread Operator). The following has been explained with examples in this stackoverflow answer.
Combine Arrays (Concatenate Arrays)
Copying Arrays
Calling Functions without Apply
Destructuring Arrays
Function Arguments as Rest Parameters
Using Math Functions
Combining Two Objects
Separate a String into Separate Characters

The [...something] is the spread operator. It in essence allows for an array or string to be expanded. You will see it used often in React, but has many other use cases.
MDN has great documentation on the spread operator:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator

You can use "..." in an object. In this example below, "...data" gets 'name: "John", age: 24':
const data= { name: "John", age: 24 };
const newData = {
...data, // Here
sex: "Male"
}
console.log(newData);
This is the result:
{ name: "John", age: 24, sex: "Male" }
This is other example with "...data[key]" to add "id" to each object in an array:
const data = [
{ name: "John", age: 24 },
{ name: "Marry", age: 18 },
{ name: "Tom", age: 15 },
]
const newData = [];
for(const key in data) {
const obj = {
id: Number(key),
...data[key] // Here
}
newData.push(obj);
}
console.log(newData);
This is the result:
[
{ id: 0, name: "John", age: 24 },
{ id: 1, name: 'Marry', age: 18 },
{ id: 2, name: 'Tom', age: 15 }
]

Context: One of the use cases is to do a "copy", but you should take care of this particular "by reference" behavior when working with sub-properties.
Finding: Take care that sub-properties are NOT passed by value, but by reference. In other words, only first level properties are passed as a copy "by value". See the example:
sourcePerson = { name: 'John', colors: ["red", "blue"] }
targetPerson = { ...sourcePerson }
console.log("Target person result:\n", JSON.stringify(targetPerson), "\n\n") //it seems a copy, but...
console.log("Let's update the name source value:\n")
sourcePerson.name = 'Kevin'
console.log("Updated source person:\n", JSON.stringify(sourcePerson), "\n")
console.log("Target person is NOT updated, It keeps a copy by value\n")
console.log(JSON.stringify(targetPerson), "\n\n")
//But if you update a sub-property, it has NOT been copied by value
console.log("Let's update a color sub-property:\n")
sourcePerson.colors[0] = "YELLOW"
console.log("Updated source person:\n", JSON.stringify(sourcePerson), "\n")
console.log("Target person is updated BY REFERENCE!\n")
console.log(JSON.stringify(targetPerson)) // it is not a copy, it is a reference!
console.log("\nCONCLUSION: ... spread syntax make a copy 'by value' for first level properties, but 'by reference' for sub-properties, so take care!\n")

Related

.map usage in an object

just wondering if someone could point me in the right direction of .map functionality. This is unfortunately something I'm struggling to get my head around.
If I had an object, lets say the following:
const myPetsAndFood = {
pets:[
{
species: "dog",
breed: "Labrador",
age: 12
},
{
species: "cat",
breed: "unknown",
age: 7,
},
{
species: "fish",
breed: "goldfish",
age: 1,
}
],
food: [
{
dogfood: 15.00,
},
{
catfood: 11.00,
},
{
fishfood: 4.00,
}
],
};
Could anyone explain how I'd utilise .map to obtain the data values of age and price if possible please?
A brief explanation or example is more than suffice, I'd appreciate any time/input possible. In all probability, I'll be sat here reading and trying to figure it out in the mean time.
If you got this far - Thank you for your time.
So the .map can only be used with arrays. This way you can not do something similar to:
myPetsAndFood.map()
Let's say you want do console.log the age. You would have to get the array first. So:
myPetsAndFood.pets.map((pet) => {
console.log(pet.age)
})
And it would print 12, followed by 7 followed by 1. If you want to store it inside an array you can create an array and use .push("//infos wanted to be pushed//")
Object.keys(myPetsAndFood).map(function(key, index) {
console.log(myPetsAndFood[key][0].dogfood);
console.log(myPetsAndFood[key][0].age);
});
You are going to have to figure out a way to replace the 0 with some sort of counter that will increment.
map is a method of arrays, it doesn't exist on objects. You could use it on the arrays within the object ( myPetsAndFood.pets.map( /* ... */ ) ) but you'd have to use a for loop or some other technique to parse each item in the object.
An example of how to use the map function for one of your arrays:
const agesArray = myPetsAndFood.pets.map((item) => {
return item.age;
});
So you have imbricated arrays here. This makes it so you have to go into your wanted array first before being able to execute your map.
For example: myPetsAndFood.pets.map(function)
The way that .map works is it executes your function on every element in your array and returns an array with the equivalency(source).
Therefore, in order to get the age of every pet, you have to tell your function to get your age property of your objects.
For example: myPetsAndFood.pets.map((pet) => pet.age)
This will return an array containing only the age of every one of your pets.
Now the problem with this is your second array. We cannot call the .map function on that array because your different properties don't have the same name. Therefore, your .map won't have any common ground to return a sensible array.
We can fix this issue by splitting your one variable into two: name and price for example. After this change, we can now call the .map on your array properly by telling it which property you need.
For example: myPetsAndFood.foods.map((food) => food.price)
Below is a full code snippet which should show off the above description.
const myPetsAndFood = {
pets:[
{
species: "dog",
breed: "Labrador",
age: 12
},
{
species: "cat",
breed: "unknown",
age: 7,
},
{
species: "fish",
breed: "goldfish",
age: 1,
}
],
foods: [
{
name: "dog",
price: 15.00,
},
{
name: "cat",
price: 11.00,
},
{
name: "fish",
price: 4.00,
}
],
};
const catAge = myPetsAndFood.pets.map((pet) => pet.age)
const foodPrice = myPetsAndFood.foods.map((food) => food.price)
console.log(catAge)
console.log(foodPrice)

Lodash merge object with nested array not working correctly

I found unexpected result when try to merge with lodash object with flat array inside.
Here the example:
var people = { name: 'Andrew', age: '30', values: ["PT", "PORTA 31"] };
const person = { age: '31', values: ["PT"] };
var people2 = { name: 'Andrew', age: '30', values: [{ pippo : 1}] };
const person2 = { age: '31', values: [{ pippo : 2}] };
// Now merge person back into people array
console.log(_.merge({}, people, person));
console.log(_.merge({}, people2, person2));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>
The result of first console.log is
{
age: "31",
name: "Andrew",
values: ["PT", "PORTA 31"]
}
And not as expected
{
age: "31",
name: "Andrew",
values: ["PT"]
}
Someone can explain me why and give me a solution to make sure that with a flat array it takes me the correct value
I think assign is better in this case than merge
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.
var people = { name: 'Andrew', age: '30', values: ["PT", "PORTA 31"] };
const person = { age: '31', values: ["PT"] };
console.log(_.assign({}, people, person));
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.20/lodash.min.js"></script>
I believe _.assign(people, person) would produce the desired outcome in this case https://lodash.com/docs/4.17.15#assign
This functionality is also native and can be used like this Object.assign(target, source)

What's the benefit of using an array of key: value pairs over a single object?

In a few different places I've seen the following being used:
const arr = [
{ key: "someKey", value: 1 },
{ key: "anotherKey", value: true },
{ key: "yetAnotherOne", value: "hello world" },
];
To me, it seems more logical to use this structure:
const ob = {
someKey: 1,
anotherKey: true,
yetAnotherOne: "hello world",
};
Is there an advantage when using an array like this?
Arrays are explicitly ordered.
An array is typically used for a list of similar objects. Some advantages would be:
having a selection of array-specific methods to e.g. to filter/sort the objects
In an array of objects it would be possible to use the same key-property multiple times. In an object these would be overwritten.
That's all I could think of. Hope it's helpful ;).
That said I would normally recommend using an object if the above is not relevant.
In your example, it would be better to use the object because it means you can access the value of the property faster and easier using something like ob.anotherKey without having to use a loop or having to know the index in the array.
However, this might not always be the case...
Slightly different from the example above:
const people = [
{ firstName: "someKey", lastName: 1 },
{ firstName: "anotherKey", lastName: true },
{ firstName: "yetAnotherOne", lastName: "hello world" },
];
Is much easier to understand and a better representation of the data and than...
const people = {
someKey: 1,
anotherKey: true,
yetAnotherOne: "hello world",
};
This also requires previous knowledge that each key is the firstName and each value is the lastName.

JavaScript Syntax Explanation - return { ...state}; [duplicate]

I have a problem with code I am supposed to work with. I found a syntax I am not familiar with and I have trouble googling the documentation:
export const Something = class Something {
constructor(someObject = {}) {
this.someObject = {...Something.someObjectDefaultAsStaticMethod,...someThing};
};
// The rest of the class
};
I have problems understanding what the three dots (...) in front of the parameter do. And "dots in parameter javascript" is a bad search term. Can someone help me, maybe tell me what this syntax is actually called or just directly link me to documentation?
That is not ES6 but has only been added in ECMAScript 2018.
It is called "Object Rest/Spread Properties" and is part of the Spread Syntax.
... (three dots in Javascript) is called the Spread Syntax or Spread Operator. This allows an iterable such as an array expression or string to be expanded or an object expression to be expanded wherever placed.
I want to list down the mostly used practical Use Cases of the Spread Syntax (Spread Operator). The following has been explained with examples in this stackoverflow answer.
Combine Arrays (Concatenate Arrays)
Copying Arrays
Calling Functions without Apply
Destructuring Arrays
Function Arguments as Rest Parameters
Using Math Functions
Combining Two Objects
Separate a String into Separate Characters
The [...something] is the spread operator. It in essence allows for an array or string to be expanded. You will see it used often in React, but has many other use cases.
MDN has great documentation on the spread operator:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator
You can use "..." in an object. In this example below, "...data" gets 'name: "John", age: 24':
const data= { name: "John", age: 24 };
const newData = {
...data, // Here
sex: "Male"
}
console.log(newData);
This is the result:
{ name: "John", age: 24, sex: "Male" }
This is other example with "...data[key]" to add "id" to each object in an array:
const data = [
{ name: "John", age: 24 },
{ name: "Marry", age: 18 },
{ name: "Tom", age: 15 },
]
const newData = [];
for(const key in data) {
const obj = {
id: Number(key),
...data[key] // Here
}
newData.push(obj);
}
console.log(newData);
This is the result:
[
{ id: 0, name: "John", age: 24 },
{ id: 1, name: 'Marry', age: 18 },
{ id: 2, name: 'Tom', age: 15 }
]
Context: One of the use cases is to do a "copy", but you should take care of this particular "by reference" behavior when working with sub-properties.
Finding: Take care that sub-properties are NOT passed by value, but by reference. In other words, only first level properties are passed as a copy "by value". See the example:
sourcePerson = { name: 'John', colors: ["red", "blue"] }
targetPerson = { ...sourcePerson }
console.log("Target person result:\n", JSON.stringify(targetPerson), "\n\n") //it seems a copy, but...
console.log("Let's update the name source value:\n")
sourcePerson.name = 'Kevin'
console.log("Updated source person:\n", JSON.stringify(sourcePerson), "\n")
console.log("Target person is NOT updated, It keeps a copy by value\n")
console.log(JSON.stringify(targetPerson), "\n\n")
//But if you update a sub-property, it has NOT been copied by value
console.log("Let's update a color sub-property:\n")
sourcePerson.colors[0] = "YELLOW"
console.log("Updated source person:\n", JSON.stringify(sourcePerson), "\n")
console.log("Target person is updated BY REFERENCE!\n")
console.log(JSON.stringify(targetPerson)) // it is not a copy, it is a reference!
console.log("\nCONCLUSION: ... spread syntax make a copy 'by value' for first level properties, but 'by reference' for sub-properties, so take care!\n")

In a JS array of objects, should I use a keys to identify each object?

I'm still learning javascript patterns, and I'm curious about this one.
If I have an array of objects, should I make the array of objects not have keys (Example A), or use their keys (Example B)?
An array of objects without any key:
var soylent_green_candidates = [{
id: 12341,
name: "Don",
gender: "Male",
weapon_of_choice: "Kangaroo Cannon"
},
{
id: 24325,
name: "Jimmy",
gender: "Male",
weapon_of_choice: "Sushi Blaster"
},
...
]
Or an array of objects using the unique ID's as keys:
var soylent_green_candidates = [
12341: {
name: "Don",
gender: "Male",
weapon_of_choice: "Kangaroo Cannon"
},
24325: {
name: "Jimmy",
gender: "Male",
weapon_of_choice: "Sushi Blaster"
},
...
]
Your second example is invalid, so that should put the question to sleep.
In Javascript you have the option of arrays, which are sorted but essentially "key less". Each array entry can only be accessed by its numeric index, period.
The other option is objects, which have no guaranteed order but are keyed by arbitrary values.
['foo', 'bar', 'baz']
{ foo : 'bar', baz : 42 }
You make the choice based on these two criteria, order and requirement for keys.
(Note: while you can use arbitrary numeric indices for arrays, you can't do so using the literal syntax [..], and it's not usually a good idea. If you need explicit keys, you want objects.)

Categories