The JavaScript ES6 version has brought a whole array of new tools and utilities. One such new feature is the spread operator.
The operatorâs shape is three consecutive dots and is written as: ...
It allows an iterable to expand in places where 0+ arguments are expected.
you can use the spread operator on Arrays and objects. you can use them in different cases: Expanding Arrays or objects, Combining or Merging Arrays and Objects, Cloning Arrays and Objects and Using with Math Functions.
Definitions are tough without context. Letâs explore some different use cases:
Expanding Arrays or objects:
Expand arrays or objects with new elements or in other names adding elements or properties to arrays or objects and operations on arrays(push-unshift):
let arr1 = ['arbok','kfc','mack'];
let arr2 = ['sfdsdfs', 'tyutyu', 'bnmbn' ];
/*
push elements in arr2 to arr1 so the output of arr1 is ["arbok", "kfc", "mack", "sfdsdfs", "tyutyu", "bnmbn"]
*/
arr1 = [âŠarr1, âŠarr2];
console.log({arr1, arr2});
/*
unishift elements in arr2 to arr1 so output of arr1 is ["sfdsdfs", "tyutyu", "bnmbn", "arbok", "kfc", "mack"]
*/
arr1 = [âŠarr2, âŠarr1];
Objects:
let pickau = {name: 'pickau'};
let stats = {hp:40, attack: 60, defense: 45};
pickau = {âŠpickau, âŠstats};
console.log(pickau)
//Output: {name: "pickau", hp: 40, attack: 60, defense: 45}
//If I did the following:
pickau = {âŠstats,âŠpickau};
console.log(pickau);
//Output: {hp: 40, attack: 60, defense: 45, name: "pickau" }
Because arrays in JS are reference values, so when you try to copy it using the = it will only copy the reference to the original array and not the value of the array, so if you will do the following code:
If you donât know how many arguments you need to accept in an arrow function, you can use the spread operator with the ârestâ parameter to make this work:
const sum = (...args) => {
let sum = 0;
for(let i = 0; i < args.length; i++){
sum += args[i];
}
return sum;
};
console.log(sum(2,3)); //5
console.log(sum(2,3,4)); //9
console.log(sum(2,3,4, 5)); //14
Some Tricks with Spread:
1- First One
let greet = ['Hello', 'World'];
console.log(greet); // Without spread operator
console.log(âŠgreet); // Using spread operator
/* If we run this code weâll see the following:[âHelloâ, âWorldâ]Hello World */
2-Secon Trick:
Sometimes, we may feel the need to convert a String into a list of characters. We can use spread operator for this use-case:
let greetings = âhelloâ;
let chars = [âŠgreetings];
console.log(chars);
/*If we run this code, weâll be greeted with:[ âhâ, âeâ, âlâ, âlâ, âoâ ] */
3- Organize Properties
Sometimes properties arenât in the order we need them to be. Using a couple of tricks we can push properties to the top of the list or move them to the bottom.
To move id to the first position, add id: undefined to the new Object before spreading object.
const user1 = { password: 'Password!', name: 'Naboo', id: 300 }
const organize = object => ({ id: undefined, ...object })
console.log(organize(user1)) //Output: //=> { id: 300, password: 'Password!', name: 'Naboo' }
/*To move password to the last property, first destructe password out of object. Then set password after spreading object. */
const user2 = { password: 'Password!', name: 'Naboo', id: 300 }
const organize = ({ password, ...object }) => ({ ...object, password })
console.log(organize(user2))
//Output: //=> { name: 'Naboo', id: 300, password: 'Password!' }
Please note spread only goes one level deep when copying an array. So if you're trying to copy a multi-dimensional array, you will have to use other alternatives.
const arr = [ [1, 2], [10] ];
const cloneArr = [...arr];
// Let's change the first item in the first nested item in our cloned array.
cloneArr [0][0] = 'đ»';
console.log(cloneArr); // [ [ 'đ»', 2 ], [ 10 ], [ 300 ] ]
// NOOooo, the original is also affected
console.log(arr);
// [ [ 'đ»', 2 ], [ 10 ], [ 300 ] ]
Hereâs an interesting thing I learned. A shallow copy means the first level is copied, deeper levels are referenced.
The problem
The spread syntax and the Object.assign() the method can only make shallow copies of objects. This means that the deeply nested values inside the copied object are put there just as a reference to the source object.
Wrong solutions
Online you will find many wrong suggestions:
Using Object.create():
const copied = Object.create(original)
Here the original object is being used as the prototype of copied.
You will lose any JavaScript property that has no equivalent type in JSON, like Function or Infinity. Any property thatâs assigned to undefined will be ignored by JSON.stringify, causing them to be missed on the cloned object.
Also, some objects are converted to strings, like Date objects for example (also, not taking into account the timezone and defaulting to UTC).
So How we can clone an Object with Right Way?
Lodash comes with two different functions that allow you to do shallow copies and deep copies. These are clone and clonedeep.
Lodash has this nice feature: you can import single functions separately in your project to reduce a lot the size of the dependency.
Take Look at the following example to understand:
const clone = require('lodash/clone');
const cloneDeep = require('lodash/clonedeep');
const externalObject = {
animal: 'Cow'
};
const originalObject = {
a: 1,
b: 'string',
c: false,
d: externalObject
};
const shallowClonedObject = clone(originalObject);
externalObject.animal = 'Lion';
// The `animal` property in both the originalObject and shallowClonedObject so it is shallow copy
console.log(originalObject);
console.log(shallowClonedObject);
const deepClonedObj = clonedeep(originalObject);
externalObject.animal = 'jiraffi';
// The 'animal' property only in the originalObject changes, because it is deep clone,
console.log(originalObject);
console.log(deepClonedObject);
2-Using immutability-helper Library:
Mutate a copy of an object without changing the original source.
Setup via NPM
npm install immutability-helper --save
We can get this library via NPM: npm install immutability-helper --save.
To deep copy our object, we could use the update() method available in immutability-helper, passing the object we want to copy as the first argument and the actual data to change as the second one:
import update from 'immutability-helper';
const originalObject = {
a: 1,
b: 'string',
c: false,
d: {
animal: 'Cow'
}
};
const deepClonedObj = update(originalObject, {d: {animal: 'Lion'} } );
// log the copied object to the console
console.log(deepClonedObj); // This will log animal: 'Lion', as expected
// log the source object to the console
console.log(originalObject); // This will correctly log animal: 'Cow', the original Object!