# JavaScript 01: Vanilla JavaScript

***

## Javascript multiline string

```javascript
`x is a long
sentence in
one string`
```

TL;DR: backticks are awesome.

***

## Javascript OR

`||`

***

## Javascript: let vs const

`let` allows the variable to be reassigned multiple times.

`const` creates a variable that cannot be reassigned after it has been assigned a value.

***

## Javascript: array basic tricks

Check if variable is of type `Array.isArray()`

```javascript
if( Array.isArray(myVariable) ){
  // do array things
}
```

Add Array to Array

```javascript
arrayOne.push(...arrayTwo)
```

Array `forEach()`

```javascript
danceMoves.forEach( move => performDanceMove(<something>))
```

Array `forEach()` on Object keys

```javascript
const keys = Object.keys(events); // dynamically get all the properties of an object
keys.forEach( (eventKey) => {
  // do something
});
```

Array `filter()`

```javascript
myArray.filter(song => song !== action.payload);  // "song" is the current item, it get removed if equal to action.payload

const favRecipes = allRecipes.filter( (recipe) => {
  return recipe.id !== 18 // do something
})

const favoriteRecipes = state.favoriteRecipes.filter( (recipe) => {
  return recipe.id !== action.payload.id; 
})
```

Array `slice()`

```javascript
const removeItemAtIndex = (list, index) => {
 //const arrStart = list.slice(0,index);
 //const arrEnd = list.slice(index+1);
 return [ ...list.slice(0,index) , ...list.slice(index+1) ];
};
```

The spread syntax (`...`) and array methods such as `.map()`, `.slice()`, and `.filter()` can be used to immutably update the state of a complex app.

***

## Objects

Object creation

```javascript
const thought = {
  id: generateId(),
  text: text,
  expiresAt: getNewExpirationTime(),
};
```

Object: Add key-value pair

thought

Object: Create Shallow Copy/Clone

```javascript
const thought = { id: 345, text: "dreaming today" };

const thoughtClone = Object.assign({}, thought)
```

Object: Create Deep Copy/Clone

<https://lodash.com/docs/#cloneDeep>

***

## Javascript: `Promise` vs `Callback`

A `promise` is when the wife asks you to do the dishes and you say "sure honey I'll do that"

A `callback` is when you tell her "hey honey I finished those dishes"

An `await` is when she asks you to do the dishes and she's standing there in the kitchen tapping her foot

***

## What are the top 5 use cases for functions returning `Promises`?

Promises are the backbone of modern JavaScript.

1. Fetching data (HTTP requests / APIs) - probably the most common. Functions that return Promises let you handle **async network calls**.
2. Reading & writing files (Node.js) - I/O operations are async, so they return Promises.
3. Database queries - Most DB libraries (MongoDB, PostgreSQL, etc.) return Promises for queries.
4. Delays / timeouts - You can wrap setTimeout in a Promise to wait for something.
5. Parallel / batch async tasks - Functions returning Promises can be run in parallel with Promise.all, Promise.race, etc.

When you have multiple async operations that don’t depend on each other, you can run them at the same time instead of one after the other.

6. User interactions (events wrapped in Promises) - Sometimes you want to wait for a user action just once (e.g., button click, modal close).

Leaving a listener attached is sometimes okay, but wrapping it in a Promise:

* Automatically removes the listener after the first event.
* Prevents memory leaks.
* Makes async code cleaner (await).
* Lets you integrate it with other Promises (Promise.all, Promise.race).

7. Animations & transitions - You can wrap CSS/JS animations in Promises so they integrate with async code.
8. Geolocation & browser APIs - Many browser APIs (Clipboard, Geolocation, Notifications, etc.) use Promises.
9. Background jobs / workers - Web Workers or background tasks in Node often expose Promises.

For heavy tasks (image processing, data crunching, machine learning, etc.), you don’t want to freeze the main UI thread.

That’s what `Web Workers` (browser) or `Worker Threads` (Node.js) are for. They run in the background.

10. Retries, polling, & error handling - Functions that retry failed requests or poll for changes often return Promises.
11. Payment APIs – Stripe, PayPal, etc. return Promises for charges and tokens.
12. Authentication – login, logout, token refresh.
13. Hardware access – WebUSB, WebBluetooth, WebRTC calls.
14. Testing async code – most test runners accept functions returning Promises.
15. Build tooling – webpack, rollup, ESLint plugins often return Promises.
16. CI/CD scripts – deploy steps, running shell commands asynchronously.

explain further 5, 6, 9

***

## How do you return a Promise with a function?

Two options

1. Explicitly return a `Promise`

```
  function getData() {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve();
      }, 1000);
    });
  }
  getData().then(result => console.log(result));
```

2. Make the function `async` using `async` keyword

```
  async function getData() {
    return "Here’s your data!";
  }
  getData().then(result => console.log(result));
```

Even though it looks like it’s just returning a string, the function is async.

That means JavaScript automatically wraps the return value in a `Promise.resolve(...)`.

3. With `await` inside `async`

```
  async function fetchData() {
   let response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
   let data = await response.json();
   return data; // still returns a Promise
  }
  fetchData().then(todo => console.log(todo));
```

***

## Javascript: Iterate Over Object

```javascript
for (let itemName in cart) {
  // do something with itemName
}
```

<https://stackoverflow.com/a/43392879/759452>

***

## Javascript: ...

```javascript
const remindMeLater = (task) => {
  return () => {
    return remindMeTo(task);
  }
}

const reminder = remindMeLater('get groceries');
console.log( reminder() );
```

***

## Javascript: Switch Case

```javascript
function getMaxPrice(price: PriceBracket) {
  switch (price) {
    case PriceBracket.Low:
      return 10.0;
    case PriceBracket.Medium:
      return 20.0;
    case PriceBracket.High:
      return 30.0;
    default:
      throw new Error('Invalid PriceBracket value');
  }
}
```

***

## JS: Optional Chaining

The optional chaining (?.) operator accesses an object's property or calls a function. If the object accessed or function called using this operator is undefined or null, the expression short circuits and evaluates to undefined instead of throwing an error.

```javascript
obj?.prop
obj?.[expr]
func?.(args)
```

```javascript
const nestedProp = obj.first && obj.first.second;  // Without optional chaining
```

becomes

```javascript
const nestedProp = obj.first?.second; // With optional chaining
```

***

## JS: Optional Chaining For Method Calls

Optional Chaining for method calls can be much nicer for deeply-nested methods:

```javascript
if (foo && foo.bar && foo.bar.baz && foo.bar.baz.qux && foo.bar.baz.qux.doSomething) {
  foo.bar.baz.qux.doSomething();
}
```

vs:

```javascript
if (foo?.bar?.baz?.qux?.doSomething) {
  foo.bar.baz.qux.doSomething();
}
```

vs:

```javascript
foo?.bar?.baz?.qux?.doSomething?.();
```

***

## JS: Destructuring: Nested object and array

Example 1

```javascript
const obj = { prop1: x, prop2: y, prop3: z };
const { prop1: x, prop2: y, prop3: z } = obj;
// Equivalent to:
// const x = obj.prop1, y = obj.prop2, z = obj.prop3;
```

Example 2

```javascript
const metadata = {
  title: "Scratchpad",
  translations: [
    {
      locale: "de",
      title: "JavaScript-Umgebung",
    },
  ]
};

const {
  title: englishTitle, // rename
  translations: [
    {
      title: localeTitle, // rename
    },
  ],
} = metadata;

console.log(englishTitle); // "Scratchpad"
console.log(localeTitle); // "JavaScript-Umgebung"
```

***

## Backticks

ES6 feature, called template literals.

Use Cases:

* interpolate values into strings dynamically
* JSX syntax to inject values dynamically into the render method of the component
* allowed to split across multiple lines

Notice the extra $ Sign:

```javascript
<img className={`${borderColorClass ?? ''} black-border`} src={`/img/${profile.img[0]}`} />

<div className={`${backgroundColor} p-6 rounded-lg shadow-md`}></div>

<img src={`/images/properties/${property.images[0]}`} />
```

***

## Web Storage API: `sessionStorage` and `localStorage`

Web Storage API offers 2 mechanisms: sessionStorage and localStorage.

Allows to save data as key-value pairs in the browser for later use.

Data stored here will always be available to your Javascript code and cannot be accessed from the backend. Thus you will have to manually add it to your requests in a header for example.

This storage is only available to your app's domain and not to sub domains.

<https://developer.mozilla.org/en-US/docs/Web/API/Web\\_Storage\\_API>

***

## `localStorage` vs `sessionStorage`

Main difference is in data expiry:

* `sessionStorage`: Data available only for a session (until the browser or tab is closed).
* `localStorage`: Stores data with no expiration date, does not clear data when the browser closes; only gets cleared through JavaScript, or clearing the Browser cache/Locally Stored Data

***

## `localStorage`

Lifecycle: `localStorage` does not clear data when the browser closes.

Ideal for: persisting data not bound to the current browser tab.

UC: dark mode feature, persist to-do items, or persist a user’s form input values

How To:

1. `localStorage` allows you to store only string values
2. store object data to `localStorage`, convert it to a string - serialize it w JSON.stringify()
3. get object data from `localStorage`, convert string back to object data - deserialize it w JSON.parse()

Sources:

* <https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage>
* <https://blog.logrocket.com/storing-retrieving-javascript-objects-localstorage/>
* localStorage+react <https://blog.logrocket.com/using-localstorage-react-hooks/>

***

## Cookies

TODO

***

## How do we send cookies from the browser to the server?

read cookies with javascript and set the request header?

TODO

***

## How do we send cookies from the server to the browser?

set the response header?

TODO

***

## Event Syntax Equivalents

```javascript
const handleChange = (event) => setEmail(event.target.value);

const handleChange = ({target}) => setEmail(target.value);

const handleChange = (event) => {
  const newEmail = event.target.value;
  setEmail(newEmail);
}
```

***

## functions

```javascript
// Anonymous function — coz does not have a name i.e. function coolFun(){}
const greet = function () {
    console.log("Welcome to GeeksforGeeks!");
};
// ES6 introduced a new and shorter way of declaring an anonymous function, which is known as Arrow Functions
const greet = () => {
    console.log("Welcome to GeeksforGeeks!");
}
// with arg
const greet = (greeting) => {
    console.log(greeting);
}
```

***

## functions: one-liner arrow functions

```javascript
// Rule: expression is actually "returned" - great for callbacks
let func = (arg1, arg2, ..., argN) => expression;
// equivalent to
let func = function(arg1, arg2, ..., argN) {
  return expression;
};

// Example: with several args
let sum = (a, b) => a + b;
// equiv
let sum = function(a, b) {
  return a + b;
};
alert( sum(1, 2) ); // 3

// Example: with one arg — parenthesis can be removed
let multiTwo = n => n * 2;
// equiv
let multiTwo = function(n) {
  return n * 2;
};
alert( multiTwo(3) ); // 6

// Example: with no arg — parentheses must be present
let sayHi = () => alert("Hello!");
// equiv
let sayHi = function() {
  return alert("Hello!");
};
sayHi(); // alerts "Hello"
```

***

## functions: embedded one-liner arrow functions

```javascript
let students = ["John", "Pete", "Alice"];
// regular function
students.forEach(function(student) {
	alert(student);
});
// equiv
students.forEach(
	student => alert(student)
);
```

***

## functions: arrow functions multi-liners

Rule: just like regular functions, add curly braces and optionally add return

—— functions: return ——

```javascript
// If we want the returned expression to wrap across multiple lines, we should start it at the same line as return. 
// Or at least put the opening parentheses
const calculate = () => {
	const arbVal = 8;
    return (
    	1 + 2 +
    	arbVal
    );
}
```

***

## Self-Executing Anonymous Functions

```javascript
(function () {
    console.log("Welcome to GeeksforGeeks!");
})();
```

***

## Primitive vs Reference Type

<https://www.youtube.com/watch?v=9ooYYRLdg\\_g>

***
