Rest Parameter [ …rest]
It is a collection of all remaining elements (hence, the name rest, as in “the rest of the elements”) into an array.
var myName = ["Marina" , "Magdy" , "Shafiq"] ;
const [firstName , ...familyName] = myName ;
console.log(firstName); // Marina ;
console.log(familyName); // [ "Magdy" , "Shafiq"] ;
As shown on line 2 in the above example , those three dots collected the rest of the elements of myName into a new sub array , this is something called destructuring which is breaking my array or object into smaller pieces.
Destructuring using rest parameter helped us to break our array into a main parameters that can be called directly such as firstName and collecting the rest into another array such as familyName .
Where can we find rest parameter again ?
If you are going to call a function and send a number of arguments , you will receive them into rest parameter in the function implementation .
function myData(...args){
console.log(args) ; // ["Marina",24,"Front-End Developer"]
}
myData("Marina",24,"Front-End Developer") ;
as shown in the above example , myData received parameters in …args which will be an array containing all the sent arguments from function’s call.
Spread Operator […spread]
It’s the opposite to rest parameter , where rest parameter collects items into an array, the spread operator unpacks the collected elements into single elements.
var myName = ["Marina" , "Magdy" , "Shafiq"];
var newArr = [...myName ,"FrontEnd" , 24];
console.log(newArr) ; // ["Marina" , "Magdy" , "Shafiq" , "FrontEnd" , 24 ] ;
Can you see what happened?
Yes it concatenated between 2 arrays and unpacked myName into single elements and, unlike the rest parameter, the spread operator can be the first element, but rest parameter needs to be the last to collect the rest elements .
It can be used to copy one array into another or to concatenate 2 arrays together.
Spread in array literals
Just like spread for argument lists, … can be used anywhere in the array literal, and may be used more than once.
let parts = ['shoulders', 'knees'];
let lyrics = ['head', ...parts, 'and', 'toes'];
// ["head", "shoulders", "knees", "and", "toes"]
Copy an array
let arr = [1, 2, 3];
let arr2 = [...arr]; // like arr.slice()
arr2.push(4);
// arr2 becomes [1, 2, 3, 4]
// arr remains unaffected
A better way to concatenate arrays
let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1 = [...arr1, ...arr2];
// arr1 is now [0, 1, 2, 3, 4, 5]
// Note: Not to use const otherwise, it will give TypeError (invalid assignment)
let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1 = [...arr2, ...arr1];
// arr1 is now [3, 4, 5, 0, 1, 2]
let arr1 = [1,2,3]
let arr2 = [...arr1, 5,6,7]
console.log(arr2)
arr1 = [1,2,3]
arr2 = [5,6,7]
let combinedArr = [...arr1,...arr2]
console.log(combinedArr)
Spread Opeartor can be used with functions
function mySum(num1, num2, num3){
console.log(num1 + num2 + num3)
}
let params = [32,50,21]
mySum(...params)
Rest Function
function mult(...args){
console.log(args.reduce(function(acc, currValue){
return acc * currValue
}))
}
mult(2,3,4)
The rest parameters must be at the end
function f(arg1, ...rest, arg2) { // arg2 after ...rest ?!
// error
}
The …rest must always be last.
Spread in object literals
Shallow-cloning (excluding prototype) or merging of objects is now possible using a shorter syntax than Object.assign().
let obj1 = { foo: 'bar', x: 42 };
let obj2 = { foo: 'baz', y: 13 };
let clonedObj = { ...obj1 };
// Object { foo: "bar", x: 42 }
let mergedObj = { ...obj1, ...obj2 };
// Object { foo: "baz", x: 42, y: 13 }
Note that you cannot replace or mimic the Object.assign() function:
let obj1 = { foo: 'bar', x: 42 };
let obj2 = { foo: 'baz', y: 13 };
const merge = ( ...objects ) => ( { ...objects } );
let mergedObj1 = merge (obj1, obj2);
// Object { 0: { foo: 'bar', x: 42 }, 1: { foo: 'baz', y: 13 } }
let mergedObj2 = merge ({}, obj1, obj2);
// Object { 0: {}, 1: { foo: 'bar', x: 42 }, 2: { foo: 'baz', y: 13 } }
In the above example, the spread syntax does not work as one might expect: it spreads an array of arguments into the object literal, due to the rest parameter.
Only for iterables
Objects themselves are not iterable, but they become iterable when used in an Array, or with iterating functions such as map(), reduce(), and assign(). When merging 2 objects together with the spread operator, it is assumed another iterating function is used when the merging occurs.
Spread syntax (other than in the case of spread properties) can be applied only to iterable objects:
let obj = {'key1': 'value1'};
let array = [...obj]; // TypeError: obj is not iterable
Get a new copy of an array/object
It is possible to do the same thing with the spread syntax like done in Object.assign().
let arr = [1, 2, 3];
let arrCopy = [...arr]; // spread the array into a list of parameters
// then put the result into a new array
// do the arrays have the same contents?
alert(JSON.stringify(arr) === JSON.stringify(arrCopy)); // true
// are the arrays equal?
alert(arr === arrCopy); // false (not same reference)
// modifying our initial array does not modify the copy:
arr.push(4);
alert(arr); // 1, 2, 3, 4
alert(arrCopy); // 1, 2, 3
Note that it is possible to do the same thing to make a copy of an object:
let obj = { a: 1, b: 2, c: 3 };
let objCopy = { ...obj }; // spread the object into a list of parameters
// then return the result in a new object
// do the objects have the same contents?
alert(JSON.stringify(obj) === JSON.stringify(objCopy)); // true
// are the objects equal?
alert(obj === objCopy); // false (not same reference)
// modifying our initial object does not modify the copy:
obj.d = 4;
alert(JSON.stringify(obj)); // {"a":1,"b":2,"c":3,"d":4}
alert(JSON.stringify(objCopy)); // {"a":1,"b":2,"c":3}
This way of copying an object is much shorter than let objCopy = Object.assign({}, obj); or for an array let arrCopy = Object.assign([], arr); so we prefer to use it whenever we can.
Cloning and merging, Object.assign – “shallow cop”
And here two independent objects are not equal,
let user = {
name: "John",
age: 30
};
let clone = {}; // the new empty object
// let's copy all user properties into it
for (let key in user) {
clone[key] = user[key];
}
// now clone is a fully independent object with the same content
clone.name = "Pete"; // changed the data in it
alert( user.name ); // still John in the original object
Object.assign(dest, [src1, src2, src3…])
It copies the properties of all source objects src1, …, srcN into the target dest. In other words, properties of all arguments starting from the second are copied into the first object.
For instance, we can use it to merge several objects into one:
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
// copies all properties from permissions1 and permissions2 into user
Object.assign(user, permissions1, permissions2);
// now user = { name: "John", canView: true, canEdit: true }
If the copied property name already exists, it gets overwritten:
let user = { name: "John" };
Object.assign(user, { name: "Pete" });
alert(user.name); // now user = { name: "Pete" }
It copies all properties of user into the empty object and returns it.
Nested cloning
Until now we assumed that all properties of user are primitive. But properties can be references to other objects. What to do with them?
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
alert( user.sizes.height ); // 182
Now it’s not enough to copy clone.sizes = user.sizes, because the user.sizes is an object, it will be copied by reference. So clone and user will share the same sizes:
https://javascript.info/rest-parameters-spread
https://javascript.info/object-copy#nested-cloning
https://medium.com/javascript-in-plain-english/es6-spread-parameter-vs-rest-operator-5e3c924c4e1f
https://zellwk.com/blog/creating-a-deep-assign-library/
https://zellwk.com/blog/copy-properties-of-one-object-to-another-object/
—
ArrayObject
API with & without Express
The Express.js API:
const express = require("express")
const app = express()
app.disable('x-powered-by');
app.get("/api", (req, res) => {
res.end(`Hey ${req.query.name} ${req.query.lastname}`)
})
app.listen(5000)
The API without Express.js:
const http = require("http")
const url = require("url")
const app = http.createServer((req, res) => {
const parsedURL = url.parse(req.url, true)
if(parsedURL.pathname === "/api") {
res.end(`Hey ${parsedURL.query.name} ${parsedURL.query.lastname}`)
}
})
app.listen(5000)
Logically, both APIs do absolutely the same thing. They only respond to the /api-route and return the query parameters they receive.
How I structure React component
Handle the UI code in one component and separate the logic of that component in other places. This will make the component feel lightweight 🐥 and you can code better.
UI:
import React from 'react';
import { useName } from '../logics/useName';
const Create = () => {
const { name, setName } = useName();
const onChange = e => {
setName(e.target.value);
};
return (
{name}
onChange(e)} value={name} />
);
};
Logic:
import React, { useState } from 'react';
const useName = () => {
const [name, setValue] = useState('');
const setName = name => {
setValue(name);
};
return { name, setName };
};
export { useName };
How to structure re-usable component using styled-components
This is an example of Atom [React Component] which can be re-used anywhere in the app.
import React from 'react';
import styled from 'styled-components';
const StyledInput = styled.input`
color: ${props => props.disabled ? `${props.theme.colors.gray}` : `${props.theme.colors.darkgray}`};
font-size: ${props => `${props.theme.fontSizes[2]}px`};
border: 1px solid;
border-color: ${props => props.theme.colors[props.borderColor] || props.theme.colors.lightgray};
background: ${props => props.theme.colors[props.bg] || props.theme.colors.white};
border-radius: ${props => `${props.theme.radii[2]}`};
padding: ${props => `${props.theme.space[2]}`};
outline: none;
::placeholder,
::-webkit-input-placeholder {
font-size: ${props => `${props.theme.fontSizes[2]}px`};
}
:-ms-input-placeholder {
font-size: ${props => `${props.theme.fontSizes[2]}px`};
}
`;
const Input = props => {
return ;
};
export default Input;
Double Exclamation !! Operator
What does the double exclamation !! operator mean?
The !! ensures the resulting type is a boolean (true or false).
javascript:alert(“foo”) –> foo
javascript:alert(!”foo”) –> false
javascript:alert(!!”foo”) –> true
javascript:alert(!!null) –> false
They do this to make sure $(‘row’) isn’t null.
It’s shorter to type than $(‘row’) != null ? true : false.