Home

JavaScript

JavaScript is the only language that can be run in the browser.

Comments

// Inline comment
/*
    Multi-line comment
    No nested multi-line comments
*/

Primitive Data Types

Sets

This is useful to get ride of duplicates in an array.

const array = [1, 2, 3, 4, 1, 2]
const removedDuplicates = [...new Set(array)]

Variables

var - Can be used through your whole function or program if declared outside a function.

let - Only used within the scope of where you declared it

const - Variable that can never change. Block-scope - You can still do array functions like .pop or .push

function example() {
  var x = 10; // function scope
  let y = 20; // block scope

  if (true) {
    var x = 30; // same variable, modifies the outer x
    let y = 40; // different variable, block-scoped
    console.log(x); // 30
    console.log(y); // 40
  }

  console.log(x); // 30
  console.log(y); // 20 (outer y, unchanged)
}

example();

Var allows for hoisting which isn’t recommended

console.log(a)
var a = 1
// This won't throw an error

// This is the same as
var a
console.log(a) // undefined
a = 1

Strings

Strings can start with “s, ‘s, or `s

Escape sequences: \”, \’, \`, \ \

+s can be used to concatenate strings

Strings are immutable. Once a string is created its value cannot be changed. If the value is changed what is happening is that a new string is being made and assigned.

String Functions

Concatenation with numbers

When you use the + keyword with a string and a number, the number is converted to a string and they are concatenated.

10 + '10' // '1010'
'10' + 10 // '1010

Arrays

Arrays allow you to store several pieces of data in the same place. Elements can be any data type and arrays are mutable.

Array Functions

const fruits = ["Banana", "Orange", "Apple", "Mango"]
fruits.splice(2, 0, "Lemon", "Kiwi")
console.log(fruits)
//Outputs: [ "Banana", "Orange", "Lemon", "Kiwi", "Apple", "Mango" ]

// Removes 1 element from an array
fruits = ["Banana", "Orange", "Apple", "Mango"]
fruits.splice(1, 1)
console.log(fruits)
//Outputs: [ "Banana", "Apple", "Mango" ]
// Keeps all the even numbers
let numbers = [1, 3, 4, 5, 5, 2]
numbers = numbers.filter((element) => {
    return element % 2 === 0
})
console.log(numbers)
const prices = [10, 20, 30, 40]
const totalPrice = prices.reduce((total, price) => {
    return total + price
}, 0)
console.log(totalPrice)

// As apposed to using a forEach
let totalPrice = 0
prices.forEach(price => {
    totalPrice += price
})
console.log(totalPrice)
const numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]

// Sorts least to greatest
numbers.sort((a, b) => a - b)
console.log(numbers); // Output: [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]

// Sorts greatest to least
numbers.sort((a, b) => b - a)
console.log(numbers); // Output: [9, 6, 5, 5, 5, 4, 3, 3, 2, 1, 1]
const numbers = [1, 2, 3, 4, 5]
const hasEven = numbers.some((number) => {
  return number % 2 === 0
})

For of

Used to loop through each element in an array.

This is better than using .forEach because this still allows you to break and return from the loop.

const myArray = [1, 2, 3, 4, 5]

for(const value of myArray){
  console.log(value)
}

In order to get the index you have to use .entries()

const myArray = [1, 2, 3, 4, 5]

for(const [i, value] of myArray.entries()){
  console.log(i, value)
}

Equality Operators

3 === 3 // true
3 === '3' // false
3 == 3 // true
3 == '3' // true

Switch Block

let x = 10
switch(x) {
    case 1:
        console.log("This is a 1.")
        break
    case 2:
        console.log("This is a 2.")
        break
    case 3: {//New scope
        console.log("This is a 3.")
        break
    }
    default:
        console.log("This is greater than 2.")
        break
}

You can create a new scope in a case block using ‘{}’s which will prevent variable naming conflicts.

Functions

function func_name1(arg1, arg2) {}

const func_name2 = function(arg1, arg2) {}

const func_name3 = (arg1, arg2) => {}

const func_name4 = arg1 => {}

// Rest operator. Used to allow a function to have a variable number of args.
const func_name4 = (...args) => {
    console.log(args[0], args[1])
}

You can put default arguments into function

function func_name(array = [], max = Math.max(...arg1)){
    // Default arguments
}

You can directly return results with the arrow function. You don’t need the {}s as long as its on the same line.

const test = () => 5 // function returns 5

This Keyword

function regularFunction(){
    console.log(this)
}

const pointerFunction = () => {
    console.log(this)
}

const obj = {
    regular: regularFunction,
    pointer: pointerFunction,
    pointerHere: () => {
        console.log(this)
    },
    regularHere: function(){
        console.log(this)
    }
}

obj.regular() // "this" refers to "obj"
obj.regularHere() // "this" refers to "obj"
regularFunction() // "this" refers to "window"

obj.pointer() // "this" refers to "window"
obj.pointerHere() // "this" refers to "window"
pointerFunction() // "this" refers to "window"

Pointer functions inherit this from their surroundings when they are created/defined.

The function keyword inherits this when it is called.

(function() {
    console.log("Function that ran immediately")
})()

Tagged Templates

You can pass template literals into functions without the need of ()s

function myFunction(string, values){
  console.log(string) // An array with ["Hello, ", "!"]
  console.log(values) // The value of "World"
}

const name = "World"
myFunction`Hello, ${name}!`

Logical Or for Fallbacks

You can have fallback values incase your first value is falsy(null, undefined, 0, empty string, etc).

// Setting a variable
const variable = A || B || C
// Arguments into functions
func(A || B || C)
/*
If A is falsy then use B
If B is falsy then use C
*/

&& and ?? for Assignment

Logical and for Assignment

The Logical And can be used to conditionally assign a variable based upon the condition.

If the condition is true it assigns the variable to the valueIfTrue.

If the condition is falsy it assigns the variable to the value of condition.

const valueIfTrue = "value"

const condition = true
const variable = condition && valueIfTrue
consol.log(accessLevel) // "value"

const condition = false
const variable = condition && valueIfTrue
consol.log(accessLevel) // false

const condition = undefined
const variable = condition && valueIfTrue
consol.log(accessLevel) // undefined

Nullish coalescing operator ??

If the nullish coalescing operator is the opposite of &&.

If the condition is null or undefined it assigns the variable to the valueIfFalse.

If the condition is not null or undefined it assigns the condition.

const valueIfNullOrUndefined = "value"

const condition = "truthy condition"
const variable = condition ?? valueIfNullOrUndefined
consol.log(accessLevel) // "truthy condition"

const condition = false
const variable = condition ?? valueIfNullOrUndefined
consol.log(accessLevel) // "value"

Useful Functions

   
console.log(“x is “ + x) Prints to the console.
console.log(“x is”, x) Prints to the console. “x is x”
prompt(“Message”) Shows a pop up with message and allowing user input.
alert(“Message”) Shows an alert to the user. No user input.
confirm(“Message”) Shows message to user and takes user input as true or false.
Math.PI 3.141592653589793
Math.abs(num) Absolute value
Math.random() Returns a random floating point num between 0 and 1. Can return a 0, but not a 1.
Math.floor(num) Rounds down to the nearest whole number
Math.floor(Math.random() * (num + 1)) Picks a random integer from 0 to num.
Math.ceil(num) Rounds up to the nearest whole number
.toFixed(number of decimal places) Rounds to the number of decimal places.
parseInt(str) or parseInt(str, base num) Converts a string to an int. If it can’t then it returns NaN
.toString() Convert a data type to a string.
Math.pow(A, B) or A ** B A to the power of B. A^B

Printing with color

Name String
Reset \x1b[0m
Bright \x1b[1m
Dim \x1b[2m
Underscore \x1b[4m
Blink \x1b[5m
Reverse \x1b[7m
Hidden \x1b[8m
FgBlack \x1b[30m
FgRed \x1b[31m
FgGreen \x1b[32m
FgYellow \x1b[33m
FgBlue \x1b[34m
FgMagenta \x1b[35m
FgCyan \x1b[36m
FgWhite \x1b[37m
FgGray \x1b[90m
BgBlack \x1b[40m
BgRed \x1b[41m
BgGreen \x1b[42m
BgYellow \x1b[43m
BgBlue \x1b[44m
BgMagenta \x1b[45m
BgCyan \x1b[46m
BgWhite \x1b[47m
BgGray \x1b[100m

Sending requests

XMLHttpRequest

const req = XMLHttpRequest()
req.open("GET"/*HTTP Method*/, "http://test.com"/*URL */) // Prepares an http request to be sent
req.withCredentials = true // Include cookies, authorization headers, or TLS client certificates
req.onload = () => {
    console.log(req.response)
    // Probably need to convert JSON to obj
}
req.send()

Fetch

Used to fetch data from a server. Returns a promise of the response.

fetch("URL")
.then(response => response.json()) // asynchronously returns an object from the json string
.then(data => {
    console.log(data)
})
.catch(error => {
    console.log(error)
})

You can specify the headers that fetch uses.

fetch("URL", {
    method: "POST",
    headers: {
        "Content-Type": "application/json"
    },
    body: JSON.stringify({ key1: "value1", key2: "value2"})
})
    .then(response => response.json()) // asynchronously returns an object from the json string
    .then(data => {
        console.log(data)
    })
    .catch(error => {
        console.log(error)
    })

Optional Fetch Argument

method: Description
GET Gets data from the server.
PUT Updates data in the server.
POST Creates new data in the server.
DELETE Deletes data in the server.
credentials: Description
same-origin Cookies/credentials only in request when same origin.
include Cookies/credentials stored in request regardless of origin.
omit Excludes cookies and credentials

Origin means the same URL, protocol, domain(.com, .net, etc), and port.

cache: Description
reload Stop caching of data by the browser for that fetch.
redirect: Description
follow Automatically follows redirects.
manual Can manually handle redirects.
error Error when there are redirects.

headers: are used to send additional information.

headers: {
    'Content-Type': 'application/json'
}

body: is where the data you want to send is stored such as JSON.

Example:

fetch('api/request', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
    },
    body: JSON.stringify(json),
})

Axios

Axios is a library which builds off of XMLHttpRequest to make it more convenient to use.

Objects

Objects are used to store an unordered list of properties to describe one thing.

Literal object notation is an object created with key-value pairs.

let dynamicKey = "key"

let testObj = {
    "A food": "hamburger",
    "drink": "water",
    [dynamicKey]: "value"
}

let test2Obj = {
    food: "hamburger",
    drink: "water",
}

console.log(testObj.drink) // water
// if the key contains a space then you must use this syntax
console.log(testObj["A food"]) // hamburger
// Both of these syntaxes work
let obj = {
    function1: function(){},
    function2(){}
}
const object = {
    test1: test1,
    test2: test2,
}
// Shorthand form
const object = {
    test1,
    test2,
}
const object = {
    key1: "value1",
    key2: "value2"
}
const array = ["ele1", "ele2"]

const { key1, key2 } = object
// or
const { key1: value1, key2: value2} = object
const [ var1, var2 ] = array

console.log(key1) // value1
console.log(key2) // value2
console.log(value1) // value1
console.log(value2) // value2
console.log(var1) // ele1
console.log(var2) // ele2

Updating values in Object

let obj = {
    key1: "value1",
    key2: "value2",
    key3: "value3"
}

function updateObj(obj, key, value){
    return {...obj, [key]: value}
    // this is equivalant to
    const newObj = {...obj}
    newObj.[key] = value
    return newObj
}

console.log(updateObj(obj, "key3", "valueThree"))
/*
Output:
{
    key1: "value1",
    key2: "value2",
    key3: "valueThree"
}
*/

For In

const object = { a: 1, b: 2, c: 3 }

for (const property in object) {
  console.log(property + ": " + object[property])
}
// "a: 1"
// "b: 2"
// "c: 3"

JavaScript Object Notation(JSON)

const json = '{"first name": "Ryan", "last name": "Sheehy"}'
const obj = JSON.parse(json, (key, value) => {
    if(key === "last name"){
        return "Mr. " + value
    }
    return value
})
console.log(obj) // "first name": "Ryan", "last name": "Mr. Sheehy"

Spread Operator

const numbersOne = [1, 2, 3]
const numbersTwo = [4, 5, 6]
const numbersCombined = [...numbersOne, ...numbersTwo] // [1, 2, 3, 4, 5, 6]

const numbers = [1, 2, 3, 4, 5, 6]
const [one, two, ...rest] = numbers
console.log(one) // 1
console.log(two) // 2
console.log(rest) // 3, 4, 5, 6

const obj1 = {
  firstName: "Ryan",
  lastName: "Sheehy",
}
const obj2 = {
  firstName: "Ryan",
  lastName: "Sheehy",
}
const obj3 = {...obj1, ...obj2}

It can be used to create an array from something that isn’t an array. [...nonArray]

Object to Array

Object.values(obj) converts the obj to an array with their values in the array.

Optional Chaining

Optionals chaining allows you to only access a field if the previous field is there. Otherwise it will return undefined.

let car = {
  make: "Toyota",
  model: "Camry",
  engine: {
    type: "V6",
    horsepower: 270
  }
}

let horsepower = car?.engine?.horsepower
// If there is a car value then get the engine field
    // If there is an engine field get the horsepower field in that engine object
// If any of these are false then return undefined

Template Literals

Used to make complete string with embedded JS.

let person = {
    name: "Ryan Sheehy",
    age: "21",
}
console.log(`Hello, my name is ${person.name}!
I am ${person.age} years old.`)

Import and Export

Use export to export the var/function - Ex: export const name = "Ryan Sheehy" - There can be a default export for a file. There can only be 1 default export.

import { name } from "./filepath"
// If it is a .js file you don't have to put .js at the end

//Import everything
import * as objectName from "./filepath"

let x = 10
default export x

// In order to import the default export you use
import Name from "./filepath"

In the browser you can send info via the window global variable.

// Exporting
function test(){console.log("Test")}
window.test = test

// Importing
window.test()

Errors

Error Handling/Try Catch

Error handling is used to keep the code running even when there is an error.

try{
    // Code that may throw an error
    if( variable ){
        throw "Custom error message." // The "Custom error message." is in error and not error.name or error.message
        throw new Error("A new error") // This error gets caught by the catch block
    }
}catch(error) {
    // These are the only 2 keys in an error
    console.log(error.name)
    console.log(error.message)
}finally{
    // Code that runs after the try catch regardless of what the try catch does
}

Throwing Errors

Errors stop the execution of the code. You can throw a custom error by doing

throw new Error("Name of error")

Promises

Used to handle asynchronous(code can be run in parallel) operations. Can only return either a resolve or a reject.

Returning a new promise is most commonly used to convert a async callback function to an async/await.

async function promise(){
    let x = true
    return new Promise((resolve, reject) => {
        setTimeout(() => {/*Callback function*/
            if(x){
                resolve("Success")
            }else{
                reject("Failed")
            }
        }, 1000)
    })
}

promise().then((message) => {
    // then runs if the promise returns a resolve
    console.log(message) // "Success"
}).catch((message) => {
    // catch runs if the promise returns a reject
    console.log(message) // "Failed"
})

Promise.all, Promise.race, Promise.allSettled, Promise.any

Promise.all type of functions allow you to run async function in parallel instead of 1 at a time. This makes things faster.

Short circuiting is .

const response1 = await promise1()
const response2 = await promise2()
const response3 = await promise3()
// These are ran synchronously and take a long time.

const responses = await Promise.all([promise1(), promise2(), promise3()])
console.log(responses) // this returns an array of all the responses. The promises are ran in parallel

// It is recommended to use Promise.allSettled and then manually check if any of the resolves were rejected
const responses = await Promise.allSettled([promise1(), promise2(), promise3()])
console.log(responses) // Returns an array of objects with fields of status and value/reason.
// { status: "fulfilled", value: "result" }
// { status: "rejected", reason: "Reason for the error" }
const errors = responses.filter((r) => r.status === "rejected")
const successes = responses.filter((r) => r.status === "fulfilled").map((r) => r.value)

Short circuit just means it returns the result.

Name Description
Promise.allSettled Returns all the results even if they were rejected
Promise.all If any of the input values are rejected it throws an error and doesn’t return any of the other results.
Promise.race When the first input value is settled(resolved or rejected) it returns the result.
Promise.any When the first input value is resolved it returns the result.

Async/Await

Used to make promises easier to work with. Only works with asynchronous functions. Await waits for the Promise to resolve.

All async function return a promise. It is recommended that if you manually return a new promise then you put it in an async function.

If a child function returns a promise and you are calling the parent function that you want to await then you have to make both the child and the parent async.

function childFunction() {
  let x = true
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if(x){
        resolve("Sub-function resolved");
      }else{
        reject("Sub-function resolved");
      }
    }, 1000);
  });
}

async function parentFunction() {
  await subFunction();
}

async function main(){
  await parentFunction()
}

mainFunction().then(() => {
  console.log("Main function completed");
});


async func_name = () => {
    try{
        let variable = await promise_function()
        // The code will wait until the promise_function returns.
        let variable2 = await promise_function2()
    }catch(error){
        // If either promise_function or promise_function2 returns an error
    }
}

If a sub function returns a promise and you want to await it you have to make all functions async.

DOM Manipulation

The DOM is the Document Object Model.

The window is an object that have internal functions and data that can be accessed. document is an object part of the window and is the DOM. document allows JavaScript to access different elements of the HTML page.

Accessing Elements

   
document.getElementById(‘id’) Returns element with the id
document.getElementsByClassName(‘class’) Returns a collection of elements with the class
document.getElementsByTagName(‘tag’) Returns a collection of elements with the tag/element name
document.querySelector(‘selector’) Returns the first element with the CSS selector
document.querySelectorAll(‘selector’) Returns a collection of element with the CSS selector

The selector in querySelector cannot start with a number therefore ids and classes should preferably start with letters.

You can use :scope to reference the current element that you are querying on

const div = document.querySelector("div")
const divDirectChild = div.querySelectorAll(":scope > *") // Gets any direct children of the div

Modifying Elements

   
element.textContent = ‘text’ Sets text content of the element
element.innerHTML = ‘html’ Sets the html content of the element
element.value = ‘value’ Sets the value content of the element
element.setAttribute(‘attribute’, ‘value’) Sets the attribute of the element
element.getAttribute(‘attribute’) Gets the attribute of the element
element.style.property = ‘value’ Sets the CSS style property of the element
element.classList.add(‘class’) Adds a CSS class to the element
element.classList.remove(‘class’) Removes a CSS class on the element
element.classList.toggle(‘class’) Toggles the presence of a CSS class on the element
element.dataset.name = “name” Searches the html attributes for data-name and sets its contents to name.

Creating and Appending Elements

   
document.createElement(‘tag’) Creates a new element with the specified tag. Tag shoudn’t have <>s
element.appendChild(newChild) Appends a new child element to the given parent element
element.append(child) Appends a new child element. Very similar to appendChild
parentElement.insertBefore(newChild, referenceChild) Inserts a new child element before a specified reference element
parentElement.removeChild(childElement) Removes a specified child element from its parent
element.remove() Removes that element form the dom.

Insert Adjacent Element

element.insertAdjacentElement("position", newElement) or element.insertAdjacentHTML("position", "html")

Position Name Description
afterbegin First child
afterend After element
beforebegin Before element
beforeend Last child

Event Handling

   
element.addEventListener(‘event’, eventFunction) Attaches an event listener to the element
element.removeEventListener(‘event’, eventFunction) Removes an event listener from the element
event.preventDefault() Prevents the default event for an element. Certain elements have default events.
event.stopPropagation() Only have to worry if you have clickable elements inside clickable elements in the html.
event.target Get the dom element which called the event.
event.target.tagName Get the HTML type of dom element. This is in all caps. Ex: "TEXTAREA"
// To dynamically add listeners to dynamically added elements.
    // You cannot get the element when the element isn't created in the DOM
  document.querySelector("element already created by the dom").addEventListener("click", function(event){
    if(event.target.className.includes("dynamically created element's class")){
      //You can also use ids
      //Your event code here
    }
  })

Commonly Used Events

Event Description
click Element is clicked.
dblclick Element is double clicked.
load Fires when a resource and its dependent resources have finished loading.
mouseover Triggered when the mouse pointer enters an element.
mouseout Triggered when the mouse pointer leaves an element.
keydown Fired when a key is pressed down. eventFunction should have an event and the key is event.key
keyup Fired when a key is released. eventFunction should have an event and the key is event.key
submit Fired when a form is submitted. Button needs type=”submit” Also submits with the enter key.
change Triggered when the value of an element changes.
resize Triggered when the browser window is resized.
input Fired when the value of an input element changes.
contextmenu Triggered when the right mouse button is pressed.
transitionend Triggered when a CSS transition ends.
error Triggered when an error occurs during loading of an external file.

Default Events

Custom Events

Sending Custom Event
const customEvent = new CustomEvent("customEvent", {
    detail: {
        key: "value"
    }
})

document.dispatchEvent(customEvent)
Receiving Custom Event
document.addEventListener("customEvent", (event) => {
    console.log(event.detail.key)
})

Traversing the DOM

   
element.parentNode Returns the parent element of the current element
element.childNodes Returns a collection of child nodes of the current element
element.firstChild Returns the first child element of the current element
element.lastChild Returns the last child element of the current element
element.nextSibling Returns the next sibling element of the current element
element.previousSibling Returns the previous sibling element of the current element
element.children[index] Gets the child of the element at the index.

This

The this keyword is used to refer to the current object.

console.log(this) // This will print the window
let planet = {
    name = "Earth",
    printName = () => {
        console.log(this.name) // Earth
    },
}

Timing

   
setTimeout(function, ms) The function runs after the delay time in milliseconds. Other code can run in the background.
let interval = setInterval(function, ms) Runs the function every milliseconds. Other code can run in the background.
clearInterval(interval) Stops the interval.

1000 Milliseconds = 1 Second

+/-/++/– Operators

let variable = 5
let result1 = ++variable // variable becomes 6 and result1 becomes 6
let result2 = --variable // variable becomes 5 and result2 becomes 5
let result3 = variable++ // result3 become 5 and then variable becomes 6
let result4 = variable-- // result4 becomes 6 and then variable becomes 5
console.log(+"3" + +"5") // 8
    // The +s in front of the string converts it to a num and then those numbers are added together
console.log(-"3" - -"5") // 2
    // The -s in front of the string converts it to a num, but negates it and then those numbers are subtracted from one another.
console.log(-"-3" + -"5") // -2

Local/Session Storage

Local storage is information stored locally on the browser.

Session storage is information stored locally to that tab.

In incognito/private window it creates a new localStorage and removes it when the window is deleted.

5megabytes max for local storage.

localStorage.setItem("key", "value")

localStorage.getItem("key")
    // Returns null if nothing is found

localStorage.removeItem("key")

localStorage.clear()
    // Removes all local storage for your site

Common APIs

   
jQuery Makes HTML document traversal and manipulation, event handling, animation, and Ajax easier to use.
day.js Dates and Calendars
bootstrap Front-end framework.
jQuery UI Makes manipulating things easier. Can work with bootstrap.
Axios ajax in jQuery, but without the jQuery.

Dayjs

Provides more powerful formatting than the inbuilt Date() in JS

var today = dayjs()
today.format('MMM D, YYYY')
today.format('[This is the day: ] ddd')

Unix time is the number of seconds from Jan 1st, 1970(epoch time).

URL of Webpage

Use document.location to get properties of the current webpage’s URL.

You can get everything after the ? in the URL(query string) by doing document.location.search

Redirect URL

document.location.href = newURL

document.location.href = "/new-page"
// or
document.location.href = "https://www.newwebsite.com"

Reload page

location.reload()

Regex

Used to match patterns.

function validate(input){
    // Does string start with the word regex
        const pattern = /^(regex).*/gm
    if(input.match(pattern)){
        // Matches the regex
    }else{
        // Doesn't match the regex
    }
}

or

function validate(input){
    const pattern = new RegExp("^(regex).*")
    if(pattern.test(input)){
        // Matches the regex
    }else{
        // Doesn't match the regex
    }
}

Object Oriented

Class Constructors

You can create objects with object literals or using the new keyword on classes/constructor functions

class Vehicle {
    #private_var
    constructor(name, private){
        this.name = name
        this.#private_var = private
    }

    get private_var(){
        return this.#private_var
    }

    set private_var(private_var){
        this.#private_var = private_var
    }
}

Constructor functions

function Car(name, model, year){
    Vehicle.call(this, name)
    const privateVariable = "Test"
    this.model = model // The this.model variable is automatically created for the object
    this.year = year
    this.info = function () {
        console.log(this)
    }
}

Using classes

class Car extends Vehicle {
    constructor(name, model, year){
        super(name) // super is the contractor of the parent
            // This will allow you to use this.vehicleConstructorArg1
        this.model = model
        this.year = year
    }

    getAge(){return 2023 - this.year}

    static test(){
        console.log("Test")
    }
}

Prototype

Adds a variable or function to a class or constructor function.

Car.prototype.moreInfo = () => {console.log("moreInfo")}

This can be used to have inheritance with constructor functions.

Debugging

Just put debugger in your js code and in your inspect element it should allow you to debug

Labels

Labels are useful when you have nested for loops and you want to break out of both for loops.

You can use break label or continue label

outerLoop: for (let i = 0; i < 5; i++) {
  for (let j = 0; j < 5; j++) {
    if (i === 2 && j === 2) {
      break outerLoop // Breaks out of the outer loop
    }
    console.log(i, j)
  }
}

Symbols

All symbols are unique, guaranteed by javascript runtime.

To create a symbol do Symbol() or Symbol("description")

In order to create a symbol across the global symbol registry do Symbol.for("globalKey"). In order to access this symbol in other places in your code you can use Symbol.keyFor("globalKey")

Symbol.iterator

The iterator protocol requires the field of Symbol.iterator to return an object with a next() function which returns an object with value and done properties.

All arrays automatically have a Symbol.iterator so you can iterate on them.

let array = [1, 2, 3, 4]
let iterator = array[Symbol.iterator]()
console.log(iterator.next()) // { value: 1, done: false }
console.log(iterator.next()) // { value: 2, done: false }
console.log(iterator.next()) // { value: 3, done: false }
console.log(iterator.next()) // { done: true }

Adding Symbol.iterator to object

In order to use a for of loop with any object, that object needs a Symbol.iterator function as a property.

This Symbol.iterator function returns an object with a callback next function property.

const iterableObj = {
    data: [1, 2, 3, 4],
    [Symbol.iterator]: function(){
        let index = 0
        return {
            next: () => { // Use the error function so the `this` keyword doesn't get reset.
                if(index < this.data.length){
                    return { value: this.data[index++], done: false }
                }else{
                    return { done: true }
                }
            }
        }
    }
}

for(const value of iterableObj){
    console.log(value)
}

Generator functions

Generator functions allow you to create iterators.

To create a generator function use function* generatorFunc(){}.

function* generatorFunc(){
    yield 1
    yield 2
    yield 3
    yield 4
}

const iterator = generatorFunc()
console.log(iterator.next()) // { value: 1, done: false }
console.log(iterator.next()) // { value: 2, done: false }
console.log(iterator.next()) // { value: 3, done: false }
console.log(iterator.next()) // { value: 4, done: false }
console.log(iterator.next()) // { done: true }

Async iterators

Async iterators allow you to execute a list of async tasks sequentially. Await for first promise, await for 2nd promise, etc.

The async iterator protocol requires the field of Symbol.asyncIterator to return an object with a next() function which returns a promise whcih resolves with an object with the properties of value and done.

async function asyncFunc(arg){
    // Some async code
}

const asyncArray = [
    asyncFunc(1),
    asyncFunc(2),
    asyncFunc(3)
]

for await (const result of asyncArray){ // A loop that pauses and await for the next result to finish
    console.log(result)
}
const asyncIterableObj = {
    data: [asyncFunc(1), asyncFunc(2), asyncFunc(3)],
    [Symbol.asyncIterator](){
        let index = 0
        return {
            next: () => {
                return new Promise((resolve, reject) => {
                    if(index < this.data.length){
                        resolve({ value: this.data[index++], done: false })
                    }else{
                        resolve({ done: true })
                    }
                })
            }
        }
    }
}

UUIDs

You can generate a new uuid with crypto.randomUUID().

The probability of a UUID collision is so low, that it can be ignored.