Coding Notes

JavaScript

By Rae

JavaScript

  • Conditionals
  • Loops
  • Functions
  • Fetch

Notes

  • Script tags in HTML are where you can write JS. add src="filename" to link js file to HTML file.
  • console.log() to log to console.
  • JS reads top to bottom. Can't access things before they're initialized.
  • To create a function function functionName() {}
  • Function is command.
  • Run is call or invoke.
  • innerText gets/sets the text inside the element called. Can't read spaces.
  • textContent gets/sets the text inside the element called. It can read spaces.
  • When it's a string VS a number the string always wins.
  • You can use an escape character (/) to display a " in a string surounded by "".
  • Name elements you grab elementPurposeEl.
  • let creates the element, it can and will be changed later.
  • const creates the element, it can't be changed later.
  • use `` when you need to add variables to text.
  • You can't use the same name for functions as in an element.
  • Event Listeners
    • container.addEventListener('listenerOfChoice', function{})
    • Using onclick in HTML is less ideal then using the event listener.
    • click
    • dblclick
    • change
    • Events I have never used.
  • Operator precedence is PEMDAS in JS.
  • ++ is self plus one.
  • += is self plus the oposite of the equal sign.
  • === means strictly equal
  • == is less strict. It converts numbers into strings if necessary.
  • = means it will become.
  • An empty string "" is a falsey value.
  • Expressions passed into conditions are translated into booleans. if (const === 5){ //runs if const === 5 (truthy) //ignores if const !==5 (falsey) }
  • Arrays
    • Arrays are stored in [].
    • They start at 0.
    • To call an array item do arrayName[0 (for first item), 1, 2, 3, -1 (for last item)].
    • arrayName.length counts the number of items in an array, starting at one, which is why in a for (let i = 0; i < array.length; i++){} i is less than not less then or equal to.
    • An array is a complex data type.
    • arrayName.push(newItem) adds content to the end of an array.
    • arrayName.pop() removes the last item of an array.
  • The i for loop, for (let i = 0; i < maxAmountOfLoop; i++){} will iterate through an array and represent each item as i. To get i of the array, use arrayName[i]
  • If you need a element from function1 use a parameter in function2 and call function2 in function1. function function1(){ const var1 = 'string'; function2(var1); } function function2(var){ var }
  • Object
    • let objectName = { "key": "value" }
    • Turn an objects values into an array by using Object.values(objectName).
    • Turn an objects keys into an array by using Object.keys(objectName)
    • Turn an object into an array of arrays by using Object.entries(objectName)
  • Grabbing Elements
    • .append(element) adds the string or object to whatever you're appending to.
    • getElementbyID('id') will get a single element with the unique id you provided. If more than one element has that id (id's should be unique) it will get the first it finds.
    • The querySelector('#id') is more dynamic. You have to be more specific and identify the element how you would in CSS (with . or # before the name if applicable). It will return the first item with the parameter you entered. This is unique because it can grab psudo selectors.
    • getElementsbyClassName('class') will return an object-like array of all the child elements that have that class name.
  • The Dialog Tag
    • dialog.show() opens a non-modal dialog.
    • dialog.showModal() opens a modal.
    • dialog.close() closes the dialog.
    • To close the dialog when clicking outside the dialog box: dialog.addEventListener("click", e=> { const dialogDimentions = dialog.getBoundingClientRect() if ( // clicking outside the dialog clientX < dialogDimensions.left || e.clientX > dialogDimensions.right || e.clientY < dialogDimensions.top || e.clientY > dialogDimensions.bottom || // clicking the cancel button e.target.id === "cancel-dialog-btn" ){ dialog.close() } })
  • setTimeout()
    • A method that delays the execution of the code inside it for the entered time.
    • setTimeout(function(){ what you don't want to fire }, number of miliseconds you want to delay by)
    • setTimeout(functionName, 3000, 'functionParameter', 'second parameter')
    • To stop a timeout before it runs it's code you can use const timer = setTimeout(functionName, 3000, 'param') document.getElementById('stopBtn').addEventListener('click', function(){ clearTimeout(timer) })
  • element.style
    • Targets an element's style.
    • elementName.style.what you want to change = "what you want to change it to"
    • elementName.style.display = 'none' to change the elements display to none, reguardless of entered CSS.
  • To override the form information being pushed into the URL query screen, formElement.addEventListener('submit', function(event){ event.preventDefault(); })
  • Any button in a form will submit by default. To stop this change the type. type="reset, submit, button" to anything but submit.
  • Disabling Elements
    • Controlling when elements are usable.
    • To disable on page load add disabled to HTML tag. <button disabled>
    • To disable after load, set disabled to true. document.getElementById('id').disabled = true
  • Class List
    • element.classList.action('className') some actions are toggle, remove, and add.
    • Just element.classList will return the entire class list of the element.
    • element.classList.toggle('className') switches the usage of the classlist back and forth.
    • element.classList.remove('className') will remove className from the elements class list.
    • element.classList.add('className') will add className to the elements class list.
  • for of
    • A nicer way of iterating.
    • for (let item of itemsObjArr) { console.log(itemsObjArr[item]) }
    • Iterates over object data structures.
    • Iterates over the values of an iterable object. (examples of iterable objects include arrays, strings).
  • for in
    • for (let item in items){ console.log(items[item]) }
    • Iterates over object data structures.
    • iterates over all enumerable property keys of an object.
  • The Includes Method
    • A method for checking if an array holds a given value.
    • An easy method for beginners.
    • Returns a boolean.
    • arr.includes(value) would return true or false.
  • Get the event in an event listener
    • container.addEventListener('click', function(event){ console.log(event.target) }) will log the event target, which is the entire tag.
    • If you log just event, you will see PointerEvent{ isTrusted: boolean } as the log.
    • The target will show the most exact location it can (p.className#idName).
    • An empty area in the container will return a string.
    • event.target.id would return just the id of what was clicked.
    • Adding .parentElement to the end of what your selecting (event.target.id).parentElement will return the parent element of the element that had an event. So if this is the HTML <div class="parent-element"> <div id="childElement"></div> </div> , then in the JS this event.target.id.parentElement, if the child element is selected, it would return <div class="parent-element">.
  • Writing Big Numbers in JS
    • You can add a numeric seperator, _, between numbers in the code to make it more readable and it will display without it. const longNumber = 9_007_199_254_740_991 console.log(longNumber)//returns 9007199254740991 console.log(typeof longNumber)//returns number
    • 9007199254740991 is the highest number js can calculate without losing precision.
    • For numbers bigger than 9007199254740991 you can use BigInt(). const longerNumber = 9007199254740991345n console.log(typeof longerNumber) // returns bigint, not number .
    • BigInt() is a constructor.
    • const longerNumber = BigInt(9_007_199_254_740_991_345) console.log(typeof longerNumber) // returns bigint console.log(longerNumber) // returns 9007199254740990976 . They cannot Math, you cannot convert a BigInt value to a number. It is useful in contexts requiring precise handling of large integers, such as cryptography, or when interacting with databases that use large integer identifiers.
  • Parent Element
    • .parentElement
    • Add to the end of an element to find its parent element.
    • childElement.parentElement would return the parent element of the selected child element.
  • Console Log Static Method
  • To get wether or not a checkbox/radio was checked, get the element and add .checked, element.checked will return a boolean. const isChecked = document.querySelector('input[type="radio"]:checked').value will grab the radio element if it is checked.
  • The Filter Method
    • oldArray.filter(function(arrayItemName, index, array){return true})
    • Getting only the elements we want from an array.
    • Creates a new array.
  • The foreach() Method
    • A method for iterating over arrays.
    • arrayName.foreach(function(arrayItemName, index) {})
    • Does not return a new array.
    • Use .forEach() if you don't need to create a new array.
  • Data Attributes
    • Sorting Extra Information in HTML Elements.
    • Often written in documents as data-*, the star representing the name you choose.
    • data-unique-name = "data"
    • To call it in js, as an event, it will be under target, in dataset, so it would be event.target.dataset.dataAttributeName(without data).
    • Great way to relate items to an id, without re-using an id.
    • Does not have to be unique.
    • If you use capital letters when assinging the data attribute, make them lowercase in js. It is best to just avoid uppercase letters.
    • If you use cabob-case when asigning the data attribute, you will need to make it camalCase in js. This is the best practice for multi-word attributes.
  • Copying Objects and Arrays
    • When you copy them in JS you are making a shallow copy.
    • To make a real copy, you make a deep copy.
  • To switch the value of a boolean (false to true, true to false) write boolean = !boolean
  • Using else if instead of another if, will prevent the system from reading unused code if it was already true in the first if.
  • Conditionally Render CSS
    • Giving elements different classes under different conditions.
    • let boolean = false; thingToClick.addEventListener('click', function(element){ boolean = !boolean; if(boolean){ booleanClass = 'className'; }; let booleanHTML = <div class="${booleanClass}">></div> });
  • UUID
    • Universally Unique Identifiers
    • A string of 36 characters.
    • Often used to identify pieces of data.
    • Highly likely to be globally unique.
    • Also known as GUID, or Globally Unique Identifier.
    • You can have a UUID created with a CDN
      • One of the most popular tools for generating UUIDS is UUID JS. To copy this, go to the readme, select the CDN Builds link, copy the import, paste it in your project (test it). Make sure your html has type="module" in the script tag. Return the uuidv4 function (you can rename that) as a function uuidv4()
  • arrayName.unshift(element) adds the element to the beginning of the array.
  • Object Destructuring
    • Extract properties from objects.
    • It enables us to extract properties from objects into distinct variables.
    • Helps keep your code DRY.
    • const {propertyVariableName, propertyVariableName2, propertyVariableName3} = objectName console.log(`display this ${propertyVariableName}'s value`)
  • The .map() Method
    • Iterating over arrays.
    • const newArray = oldArray.map(function(nameValues, index) { //iterates through each array value //index will return the index of each value })
    • could be stored in a function instead of a const.
    • Use .map() if you need to make use of the new array it returns
  • The .join() Method
    • Strings from arrays.
    • Concatenates elements of an array into a string.
    • You choose how elements are separated.
    • It returns the new string.
    • console.log(arrayName.join('what you want between each value'))
    • To have no seperator just keep an empty string, there will be no space between them though.
  • All methods must end with parenthesis.
  • To find out what type an element is put typeof before it. It will return if it's a string, boolean, ect. console.log(typeof booleanEl) would return boolean.
  • You can only chain onto a method if it returns an array.
  • The For Loop
    • break and continue can be use within for loops.
    • for (let i = 0; i < arr.length; i++){} is a common for loop.
    • for (let i = 0; i < arr.length; i++){ if (arr.key < 5){break} if (arr.key > 5 {continue} console.log('this will not run if the arr.key is greater than or less than five')) }
  • Various Array Methods
    • arr.every(function(arrItem){ return arrItem >= 30 }) Every array item will be subject to the code within the function, and you will get a boolean true or false response. It will only return true if every item is true.
    • .some(function(arrItem){ return arrItem >= 30 }) Every array item will be subject to the code within the funciton, and you will get a boolean true or false response. It will return true if one or more items are true.
    • arr.find(function(arrItem){ return arrItem > 30 }) Every array item will be subject to the code within the function until one is true, you will get the items content as a response. If none are true, then it will return undefined.
    • .findIndex(function(arrItem){ return arrItem > 30 }) Every array item will be subject to the code within the function until one is true, you will get the items index number as a response. If no item is true, it will return -1.
    • arr.indexOf(arrItemContent) Every array item will be tested for the content until one is found with it, then it will return that items index number.
    • arr.at(-1) Takes a positive or negative integer and returns the item at that index. Negative integers will count back from the end of the array.
  • Replace Method
    • text.replace(pattern, replacement)
    • const text = "hello how are you?" text.replace('h', 'H') will return 'Hello how are you', changing the first h but not the second.
  • ReplaceAll Method
    • text.replaceAll(pattern, replacement)
    • const text = "hello! how are you this morning?" text.replaceAll('h', 'H') will return 'Hello! How are you tHis morning', changing the all h to H.
    • To avoid the above problem of capitalizing letters within words you can use regex (regular expression). This is a sequence of characters that specifies a match pattern in text. /[a-zA-Z1-9]/ will find any number 1-9 and any letter, lower or uppercasea-z. /^\d{5} (-\d{4})?$/ will validate US zip codes. In this case you would do text.replaceAll(/\b(h)\b/g, 'H')
    • You can also use functions in the replaceAll. const text = "I love you with all my heart!" console.log(text.replaceAll(/\b(love|heart)\b/g, function(match){ return `${match} <3` })) will log "I love <3 you with all my heart <3".
  • RegExp
    • \d = any number between 1 and 9
    • . = any single character
    • [abc] = will match a, b or c
    • [^abc] = all but a, b or c
    • [0-6] = will match any single 0, 1, 2, 3, 4, 5 or 6
    • [^a-p] = will match q through z
    • \w = includes any single alphanumeric character plus the underscore
    • [a-z] is different then [A-Z]
    • a{3} = aaa
    • [wxy]{5} = any sequence with exactly 5 characters that are either w, x or y
    • .{2,6} = matches any sequence that is between 2 and 6 characters long
    • \d = any single digit between 0 and 9
    • a* = 0 or more of a
    • ab?c = abc or ac (b is optional)
    • _ = a space
    • \t = tab
    • \n = new line
    • \r = return
    • \s = any white space
    • \S = no white space
    • g = g flag = global = looking for all instances, not just one. Needed if you are using replace all after the ending /
    • i = i falg = case insensitive =
    • regexp has a test method that returns a boolean. regex.test(text)
    • There is a RegExp Constructor. const textText = "hello world" const regex = new RegExp(testText, 'gi')
  • hasOwn/hasOwnProperty
    • hasOwn is more modern.
    • Object.hasOwn(objectName, 'propertyName'), static method,
    • objectName.hasOwnProperty('propertyName')
    • Tells you weather the property is on the object.
  • Value/Reference
    • Primitives, strings, numbers and booleans are passed by value.
    • Objects and arrays are passed by reference.
    • There are two ways to copy arrays, Deep Copy and Shallow Copy.
    • Shallow Copy creates a new object or array but only at the first level. For nested objects or arrays, a shallow copy Will still hold references to the original nested objects or arrays.
    • Deep copy copies the entire array or object.
    • To one element with a given id use getElementByid('idName').
    • To grab all elements with a given class use getElementsByClassName('className').
  • You can usually get rid of an else if you are returning in the if.
  • Function Expressions
    • Different Syntax and Behavior.
    • Are not hoisted (cleaner).
    • const name = function(parameter){}
  • Arrow Functions
    • Ultra Consise functions.
    • One parameter: const name = parameter => { return stuff } or const name = (parameter) => { return stuff }
    • No parameter: const name = () => {}
    • Multiple parameters: const name = (parameter1, parameter2) => { return stuff}
    • You have to add the curly braces and return keyword when there's more complex logic, but when it's one simple line of code you don't need the curly braces and return keyword.
    • If you don't return anything it is undefined.
  • Import and Export
    • Name Export
      • To rename what you're importing ad an as import { oldName as newName } from 'fileLocation'
      • To import multiple things from one file, use a comma import { oneThing, secondThing } from 'fileLocation' You must export them both, but if you do you have to name every name export that is passed in that import.
      • To export multiple exports export { exportNameOne, exportName2} or export function(){} exports the function.
    • Default Export
      • export default function(param1, param2){ //code stuff }
      • Gives you the advantage of calling this function whatever you want. Renaming the function can cause confustion and make code less readable. import nameYouWant from './fileLocation.js'
      • You can only have one default export from a file.
    • Anytime you use the import or export in JS you have to add type="module" to the HTML JS file reference.
  • The .reduce() Method
    • Returns only one thing from an array.
    • Takes in a function.
    • Iterates through the array given the parameters till it has combined all values. arrayName.reduce(function(total, currentElementb ){})
    • Must use return keyword.
    • To get a value of an array
    • Written as arrow function const totalOfArray = arrayName.reduce( (param1, param2) => param1 + param2, );
    • When using objects and returning numbers with a reduce method const total = array.reduce(function(total, currentElementb){ return total + currentElementb.numbersKey }, 0) The 0 will set the default start of the total to be 0, instead of an object.
  • Default Parameters
    • Protection against bugs.
    • function functionName(arrayName, secondParam = defaultValue){}
    • The defulat will only be used when you don't pass in an argument when calling the function.
  • The Ternary Operator
    • An alternative to if/else (sometimes).
    • condition(true or false value) ? expression(executes if true) : expression(executes if false)
    • condition ? ifTrue : condition ? ifTrue : else
    • Complex login is not easy to read with a ternary operator.
  • The Rest Parameter
    • Catching the rest of the arguments.
    • function functionName(parameter, ...restParameterName){ //iterates through restParameterName as many times as there are parameters for it. } functionName('param1', 'param2', 'param3', 'param4', 'param5',) //Would go through function for all entered params 1-5
    • Taking in the REST of the arguments (get it).
    • The rest parameter must go last.
  • The Spread Operator
    • Expanding and joining arrays.
    • const arrayOne = ['arrayStuff1', 'arrayStuff2', 'arrayStuff3'] console.log(...arrayOne) //logs arrayStuff1 arrayStuff2 arrayStuff3
    • Really good way of making a copy of an array const arrayOne = ['arrayStuff1', 'arrayStuff2', 'arrayStuff3'] const arrayOneCopy = [...arrayOne] console.log(arrayOneCopy) //logs ['arrayStuff1', 'arrayStuff2', 'arrayStuff3']
    • Useful for combining arrays in a new array const arrayOne = ['arrayStuff1', 'arrayStuff2', 'arrayStuff3'] const arrayTwo = ['array2Stuff1', 'array2Stuff2', 'array2Stuff3'] const arrayThree = ['array3Stuff1', 'array3Stuff2', 'array3Stuff3'] const combinedArrays = [...arrayOne, ...arrayTwo, ...arrayThree] console.log(combinedArrays) //logs ['arrayStuff1', 'arrayStuff2', 'arrayStuff3', 'array2Stuff1', 'array2Stuff2', 'array2Stuff3', 'array3Stuff1', 'array3Stuff2', 'array3Stuff3']
    • Shallow Copy
  • To find the highest number of a list of numbers use Math.max(numberlist).
  • To find the loweset number of a list of numbers use Math.min(numberlist).
  • Short-Circuit
    • More concise code for conditional logic.
    • The logical OR operator ||. Evaluates from left to right and stops evaulating once it finds something truthy. const arrayName = { key1: 'value1' //key2: 'value2' } const variable = array.key2 || 'That key does not exist' console.log(variable) //logs 'That key does not exist'
    • The logical AND operator &&. Evaluates from left to right and if the stuff on the left is true, executes the stuff on the right const exampleArray = { key1: 'value1' } exampleArray.key1 === 'value1' && console.log('This is ran') //logs 'This is ran' exampleArray.key1 === 'value2' && console.log('This is not ran') //nothing is logged
    • Nullish Coalescing Operator, ??, returns the right hand operator truthy value if the left hand operator is null or undefined.
    • Optional Chaining, ?., adds optional additions to your chain. const library = { sections: { fantasy: [ {title: 'The Long Way to a Small, Angry Planet'} ] } } console.log(library?.sections?.fantasy[0]?.title) Would log 'The Long Way to a Small, Angry Planet'. If anything is wrong, it will log undefined, instead of throwing an error.
  • Switch Statements
    • Select one of many code blocks to execute.
    • function functionName(parameter){ switch(parameter){ case 'parameter possiblity'; //the following code will only run if the case is correct break //won't run the code below case 'another possibility': //the following code will only run if the case is correct break default: //runs if none of the cases are true } }
    • The last item (default or case) does not need a break.
  • Constructors
    • Constructors have two main categories, Inbuilt and Custom.
    • Inbuilt Constructors provide objects in various predetermined formats, like Date Objects and Error Objects, and Objects for each data type.
    • Custom Constructors are constructors we design ourselves to provide objects for our own specific purposes.
    • The Date Constructor
      • An inbuilt constructor.
      • To use the Date() constructor const nameofThing = new Date() //returns an object //return example: 2024-06-27T22:42:07.898Z //To make it more readable put nameofThing.toString() //return example: Thu Jun 27 2024 16:43:55 GMT-0600 (Mountain Daylight Time) //gives exact date and time of where you are
      • To return the current year use new Date().getFullYear()
      • luxon makes working with dates and times easier.
    • The Error Constructor
      • throw new Error('Your error here') The throw keyword will stop all the code after your throw from running.
      • Code will continue running after your error console.log(new Error('Your error here'))
    • The Object Constructor new Object() will create a new object. Much better to use the litteral {}
    • String()
    • Number()
    • Array()
    • Boolean()
  • The Error() Constructor
    • throw new Error('error text')
    • throw will stop all following code from executing.
  • Other Constructors are String() Number() Array() Object() Boolean() but they are rarely used.
  • You can add a function to within an object and access it. const objectName = {key1: 'value1', key2: 'value2', key3: function(){}} objectName.key3()
  • this can be used within an object to refer to the object name instead of typing it out. If you are using an arrow function within the object using this will refer to what's beyond the function (window).
  • Classes
    • Templates for objects.
    • class NameofClass { constructor(param1, param2){ this.param1 = param1 this.param2 = param2 } fuctionName() { } } const thingName = new NameofClass('param1', param2) thingName.functionName()
    • needs to be constructor. cannot be called anything else
    • Biggest difference from Constructor is classes are not hoisted.
  • Debugging
    • Suntax and Logic Errors
      • SyntaxError: missing ) after argument list means not enough )
      • SyntaxError: Unexpected token ')' means not enough )s
      • TypeError: varName.value.addEventListener is not a function means js is expected a value from a function, but can't find it.
      • ReferenceError: VarName is not defined means you probably mispelled it, or it isn't define there.
      • To learn more about errors
    • To intentionally throw an error function functionName(parameter){ try { if (typeof parameter === 'number'){ console.log(parameter) } else { throw new ReferenceError('Error Message') } } catch (err) { console.log('Error: ' + err) } } functionName('String') //logs "Error: ReferenceError: Error Message"
    • Helpful Debugging Tool
      • In inspector (ctrl/cmnd + i), find Sourches, Breakpoints (Run code until a breakpoint, allowing you to see what happens up to that point. Great to execute code step by step until you find the problem.) , Watchers (Monitor the values of variables or expressions overtime as you step through your code. useful to see how and when a value changes during your code.).
    • Go to this doc to learn more advanced debugging skills.
  • setInterval()
    • Makes code repeatedly execute and regular intervals.
    • const intervalTimer = setInterval(function(){ //do code clearInterval(intervalTimer) }, 1000)
  • JS Runtime Environment (the V8 Engine)
    • The Heap - handles memory allocations so we don't have to.
    • The Call Stack - where code executes - As js is single threaded, the call stack can only excecute one piece of code at a time in its single thread.
    • Js is helped by WebAPIs, task queue, and event loop, all are not a part of the js language.
    • JS can multi-task (.setTimeout(), .setInterval(), fetching data across the network, promises).
    • The webAPI is what counts for timeouts and intervals. After the time is done it passes the code to the Task Queue, which will send the code at the top of the queue to the call stack once it is empty.
    • If code is complex, the execution of setTimout and setInterval will take longer. It will never take the exact ms you put in, just slliiiiightly above it. Unoticable.
  • performance.now() is a really super accurate timestamp.
  • ++Pre-increment, just move the increment opperator to the front of your expression.return ++count. The pre-increment operator increments the variable's value before the result of the increment is used in an expression.
  • --Pre-decrement, just move the decrement opperator to the front of your expression.return --loss. The pre-decrement operator decreases the variable's value before the result of the decrement is used in an expression.
  • Number Separators will separate out the digits into chunks
  • Object.assign()
    • Makes a shadow copy of an object.
    • Copies properties from a source object to a target object
    • Returns the new version of the target object.
    • const source = {key: 'value', keyObj: {'value2', 'value2', 'value3'}} const target = {} Object.assign(target, source) source.keyObj[0] = 'value1' console.log(target) will log {key: 'value', keyObj: {'value1', 'value2', 'value3'}}.
  • structuredClone()
    • Makes a deep copy.
    • const source = {key: 'value', keyObj: {'value2', 'value2', 'value3'}} const target = structuredClone(source) source.keyObj[0] = 'value1' console.log(target) will log {key: 'value', keyObj: {'value2', 'value2', 'value3'}}.
  • this
    • const obj = { key1: 'value1', key2: 'value2', key3: function(){ console.log(this) } obj.key3() } will log {key1: 'value1', key2: 'value2', key3: ƒ()}. If you use an arrow function it will log out "window" instead.
  • The .bind() method
    • const obj = { key1: 'value1', key2: 'value2', key3: function(){ console.log(this) } } const objDetails = obj.key3.bind(obj) logs out {key1: 'value1', key2: 'value2', key3: ƒ()}
  • Creating Funcitons
    • Factory Functions
      • A normal funciton that returns an object.
      • function functionName(param1, param2){ return { param1: param1, param2: param2, anotherFunction(){ console.log(this) } } }
      • Object property value shorthand is used to write params only once. function functionName(param1, param2){ return { param1, param2 } }
      • Pros to factory functions: The syntax is familiar and easy to read.
      • Cons to factory functions: Less performant, and No inheritance.
    • Constructor Functions
      • function Functionname(param1, param2){ this.param1 = param1 this.param2 = param2 this.anotherFunction = function() { console.log(this) } }
      • You provide the properties and methods.
      • function Constructor(name1, name2){ this.name1 = name1 this.name2 = name2 this.function = function(){} } const newObj = new Constructor('name1', 'name2') newObj.function()
    • Form Data Constructor Function
      • FormData(formElement)
      • Returns all inputed data as an object.
      • Is a constructor function.
      • const formElementData = new FormData(formElement)
      • To see what the object holds use formElementData.get(nameData)
    • Classes
      • Templates for objects
      • class Classname { constructor(param1, param2){ this.param1 = param1 this.param2 = param2 } functionName(){ console.log(this.param1) } } const instance = new Classname('param1', 'param2') instance.functionName()
      • Classes are not hoisted
  • .call()
    • function functionName(param1) { console.log(`${this.key1} ${this.key2} ${param1}`) } const instance = { key1: 'value1', key2: 'value2' } functionName.call(instance, 'param1')
  • .apply()
    • Takes an array of arguments
    • function functionName(param1) { console.log(`${this.key1} ${this.key2} ${param1}`) } const instance = { key1: 'value1', key2: 'value2' } functionName.apply(instance, ['param1'])
  • Inheritance
    • The Prototype Chain is the order in which things can be inherited by Objects. The top one inherits from Object.
    • Polymorphism an object can override inheritance, adapting for specific needs. It allows methods to have different implementations on different objects. An object can override a method it inherits, adapting it for specific needs.
    • const firstObj = { key1: '', key2: '', key3: '', key4: function(){} } const secondObj = { key5: ;;, }
    • Inheritance with constructor functions
      • The call method is used to call a function with a specified 'this' value and arguments.
      • function Parentconstructor(param1, param2, param3){ this.param1 = param1 this.param2 = param2 this.param3 - param3 this.functionName = function(){ return `${param1}, ${param2}, ${param3}` } } function Childconstructor(param1, param2, param3, param4){ Parentconstructor.call(this, param1, param2, param3) this.param4 = param4 } Childconstructor.prototype = Object.create(Parentconstructor.prototype) Childconstructor.prototype.constructor = Childconstructor prototype is by default a reference to the base Object or Object Object.
    • Overriding Inherited Methods on Constructor Functions
      • function Parentconstructor(param1, param2, param3){ this.param1 = param1 this.param2 = param2 this.param3 - param3 this.functionName = function(){ return `${param1}, ${param2}, ${param3}` } } Parentconstructor.prototype.newFunctionName = function() { return 'stuff' } function Childconstructor(param1, param2, param3, param4){ Parentconstructor.call(this, param1, param2, param3) this.param4 = param4 } Childconstructor.prototype = Object.create(Parentconstructor.prototype) Childconstructor.prototype.constructor = Childconstructor Childconstructor.prototype.newFunctionName = function() { const varName = Parentconstructor.prototype.getDetails.call(this) } newFunctionName will be overridable.
    • Inheritance with Class Syntax
      • class Parentclass { constructor(param1, param2, param3) { this.param1 = param1 this.param2 = param2 this.param3 = param3 } functionName() { return `param1: ${this.param1}, param2: ${this.param2}, param3: ${this.param3}` } } class Childclass extends Parentclass { constructor(param1, param2, param3, param4) { super(param1, param2, param3) this.param4 = param4 } functionName(){ const superName = super.functionName() return `${superName} param4: ${param4}` } } const class = new Childclass('param1', 'param2', 'param3', 'param4')
      • The 'super' keyword is used to do two things, access properties on the superclass's prototype and invoke the superclass's constructor.
  • Static Methods and Properties
    • Creating an object that is not available on the instances.
    • class ClassName { static staticName = 0 constructor(param1) { this.param1 = param1 ClassName.staticName++ } static staticFunctionName() { return ClassName.staticName } } console.log(ClassName.staticFunctionName())
  • Private Fields
    • Not properties of this in the same way public properties are.
    • class ClassName { #privateProperty constructor(privateProperty, param2){ this.#privateProperty = privateProperty this.param2 = param2 } } const variable = new ClassName('privateProperty', 'param2') variable would log out ClassName {param2: param2}
    • Access Private field with getters and setters
      • Getter: class ClassName { #privateProperty constructor(privateProperty, param2){ this.#privateProperty = privateProperty this.param2 = param2 } get privateProperty(){ return this.#privateProperty } } const variable = new ClassName('privateProperty', 'param2') logging variable.privateProperty will give you privateProperty
      • Still can't be modified so access is controlled.
      • Setter: class ClassName { #privateProperty constructor(privateProperty, param2){ this.#privateProperty = privateProperty this.param2 = param2 } get privateProperty(){ return this.#privateProperty } set privateProperty(newPrivateProperty){ if (typeof newPrivateProperty !== 'string' || newPrivateProperty.length >= 0){ throw new Error('newPrivateProperty is not valid') } this.#privateProperty = newPrivateProperty } } const variable = new ClassName('privateProperty', 'param2') variable.privateProperty = 'newPrivateProperty'
      • Can be modified.
  • Symbols
    • A primitive data type
    • An immutable identifier used as a property key in objects.
    • Each symbol is unique
    • A bit like UUIDs/GUIDs, but built in to js.
    • const symbolVar = Symbol('description'), you don't use a new keyword, and the description does not effect it's uniqueness.
    • To store a symbol in an Object const objName = { key1: 'value1', [Symbol('description')]: 'value2' } or const symbolVar = Symbol('description') const objName = { key1: 'value1', [symbolVar]: 'key2' } or (most common) const symbolVar = Symbol('description') const objName = { key1: 'value1', } objName[symbolVar] = 'key2'
    • You won't be able to see the symbol unless you specifically ask for the symbol like console.log(objName[symbolVar])
    • Used to add properties to objects without the risk of property name conflicts.
    • Symbols are not 100% private.
    • Misuse or overuse of symbols can lead to the confusion or coplexity in code maintenance.
  • Map Object
    • Has nothing to do with the array map method.
    • The map object holes key/value pairs just like a regular object.
    • Map Object Benefits
      • Use other data types as keys const objOne = { key1: "value1", key2: "value2" } const mapObj = new Map() mapObj.set(objOne, 10000) logs the map object, key as objOnes content and the value as 10000
      • Iterate with a forEach const objOne = { key1: "value1", key2: "value2" } const objTwo = { key1: "value3", key2: "value4" } const objThree = { key1: "value5", key2: "value6" } const mapObj = new Map() mapObj.set(objOne, 10000) mapObj.set(objTwo, 10200) mapObj.set(objThree, 9800) mapObj.forEach((value, key)=>console.log(key.key1, value)) would log value1 10000 value3 10200 value5 9800
      • Has a size property (similar to length property) console.log(mapObj.size) would log 3
      • You can access an individual property using the get method console.log(mapObj.get(objOne)) would log 10000
      • To delete a property console.log(mapObj.delete(objOne)) would log true and delete objOne
      • The has method will check if a property exists console.log(mapObj.has(objThree)) would log true.
      • Insertion Order is fixed and guaranteed.
  • Set Object
    • A set object stores unique values as individual items, not key/value pairs. It's a bit like an array but with each it4em unique - no duplicates.
    • const duplicatesArr = ['value1', 'value2', 'value3', 'value1', 'value2'] const noDuplicatesArr = new Set(duplicatesArr) console.log(noDuplicatesArr) logs Set(3) {'value1', 'value2', 'value3'}
    • You can use a forEach on a set. Not all array methods though. To use all array methods, you have to convert it back to an array.
    • Insurtion order is maintained.
    • You can use noDuplicatesArr.add('value4') to add to the Object.
    • You can use noDuplicatesArr.delte('value4') to delet from the Object.
    • You can use noDuplicatesArr.has('value4') to see if it exists in the Object.
    • You can use noDuplicatesArr.clear() to remove everything from the Object.
    • Learn more about the set Object and it's other methods!
    • Many of the methods do not have wide browser support.
  • Closures
    • Helps you access variables defined within a funciton, outside of said funciton.
    • function outerFunction(param) { const outerVariable = 'I am from the outer function' function innerFunction() { console.log(outerVariable) console.log(param) } return innerFunction } const closure = outerFunction('I am an argument') closure() logs I am from the outer function I am an argument.
  • IIFEs
    • Effectively self calling.
    • To immediately run a function wrap the function in () and end it in ().
    • (function() { function stuff })()
    • (async function(param) { function stuff })('param')
  • Recursion
    • Function calling itself
    • Recursive Function
    • To reverse a number function countdown(count) { console.log(count) if (count = 0) { return count } countdown(count - 1) } countdown(5) logs 5 4 3 2 1 0
    • Unwind to return the final value.
    • To reverse a string function reverseStr(str){ if (str.length <= 0){ return str; } else { return reverseStr(str.slice(1)) + str.slice(0, 1); } }
  • Currying
    • function functionName(param1){ return function(param2){ return function(param3){ return `${param1} ${param2} ${param3}` } } } const with1 = functionName(param1) const with2And1 = with1(param2) const with3And2And1 = with2And1(param3) console.log(with3And2And1) logs param1 param2 param3
    • function functionName(param1){ return function(param2){ return function(param3){ return `${param1} ${param2} ${param3}` } } } const with3And2And1 = with2And1(param1)(param2)(param3) console.log(with3And2And1) logs param1 param2 param3
    • Written as an arrow function const functionName = param1 => param2 => param3 => `${param1} ${param2} ${param3}`
    • Why Curry a Function?
      • Allows for partial application, which allows you to fix some arguments and defer the rest. This is useful when you repeatedly call a function with some of the same arguments.
      • const functionName = param1 => param2 => param3 => `${param1} ${param2} ${param3}` const onlyTwoParams = functionName(param1)(param2) const thirdParam1 = onlyTwoParams(param3) const thirdParam2 = onlyTwoParams(param4) const thirdParam3 = onlyTwoParams(param5) console.log(thirdParam1) console.log(thirdParam2) console.log(thirdParam3) logs param1 param2 param3 and param1 param2 param4 and param1 param2 param5
  • Throttling
    • Reduces Unecessary code execution.
    • Ensures a function is called at most once in a specific period of time.
    • When an event continuously triggers, throttling will call the function only at regular intervals, ignoring any additional triggers.
    • Put a throttle on a resize event handler function handleResize(e){ console.log('resize happened on event' + e) } function throttle(func, delay){ let throttleTimeout = null return function() { if(!throttleTimeout){ func() throttleTimeout = setTImeout(() => { throttleTimeout = null }, delay) } } } const throttleHandleResize = throttle(handleResize, 1000) window.addEventListener('resize', throttleHandleResize)
    • Add an event to the throttle function handleResize(e){ console.log('resize happened on event: ' + e) } function throttle(func, delay) { let throttleTimeout = null return (...args)=> { if(!throttleTimeout) { func(...args) throttleTimeout = setTimeout(()=> { throttleTimeout = null }, delay) } } } const throttledHandleResize = throttle(handleResize, 1000) window.addEventListener('resize', throttledHandleResize)
  • Debouncing
    • Reduces Unecessary code execution.
    • Ensures a function is called only after a certain period has passsed since the last triggering event.
    • When an event continuously fires, debouncing will delay the function call until after the event has stopped for a specified duration.
    • Use debouncing with an input change event listener function debounce(func, delay) { let debounceTimer return (...args) => { clearTimeout(debounceTimer) debounceTimer = setTimeout(()=> { func.apply(...args) }, delay) } } function handleInput(e) { console.log('Input detected from element with id ' + e.target.id) } document.getElementById('name-input').addEventListener('input', debounce(handleInput, 500))
  • Generators
    • Common use cases
      • Async operations
      • Handling state
      • Lazy evaluation
    • Using lazy evaluation const slidesArr = [ "1", "2", "3", "4", "5" ] function* generator(arr) { for (const item of arr) { yield item } } const slideGenerator = generator(slidesArr) document.getElementById('nextSlideBtn').addEventListener('click', () => { const result = slideGenerator.next() if (!result.done) { console.log(result.value) } else { console.log('That is the end!') } }) logs 1 2 3 4 5 That is the end!
    • The return keyword can stop a generator yeilding. const slidesArr = [ "1", "2", "3", "MALFUNCTION", "4", "5" ] function* generator(arr) { for (const item of arr) { if (item === 'MALFUNCTION') { return } else { yield item } } } const slideGenerator = generator(slidesArr) document.getElementById('nextSlideBtn').addEventListener('click', () => { const result = slideGenerator.next() if (!result.done) { console.log(result.value) } else { console.log('That is the end!') } }) logs 1 2 3 That is the end!
  • Functions are a first class object in js.
  • To clear a form, use form reset form.reset()
  • Async JavaScript
    • Code that can be run out of order. Allows a lengthy operation to start, but finish at a later time without blocking other code from running in the meantime.
    • JavaScript isn't truly asynchronous, but rather has 'callback' mechanisms in place to run commands in a different order to make things more efficient.
    • 'Single-threaded' meands only one command can run at a time.
    • function callback() { console.log('ran') } document.getElementById('button').addEventListener('click', callback)
    • function callback(){ console.log('ran') } setTimeout(callback, 2000)
    • function returnStuff(param) { return param.thing } const newArray = oldArray.filter(returnStuff)
  • Promises
    • There are three promising states.
    • Pending is one state, it means the promise has yet to be completed.
    • Following pending, is a Fullfilled state, it means the promise was completed as promised.
    • Alternatively, after pending can be the Regected state, which means the promise was not completed as promised.
    • .then() returns a promise, you can use this for promise chaining.
    • .then() is a method that will take in a callback function.
    • When a promise (fetch) is fulfilled it will start running the .then() block.
  • To get the children of an element for (const child of myElement.children) { console.log(child) }
  • Async and Await
    • Introduced in ECMAScript 2017 (ES8)
    • Makes asynchronous code appear to be synchronous.
    • async goes before the function
    • await goes before a method/function that returns a promise.
    • async function functionName() { await function or method that normallyreturns a promise }
    • async function functionName() { const name = await function or method that normallyreturns a promise }
    • You can put async before an arrow funciton.
  • To get the exact time without the date use const time = new Date().toLocaleTimeString('en-us', {timeStyle: 'short'})
  • To tell if a string starts with something specific you can use the startsWith method: string.startsWith('test'). It will return true or false.