Homelab, Linux, JS & ABAP (~˘▾˘)~
 

[JavaScript] Objects

These are my notes while doing the course JavaScript Algorithms and Data Structures on https://www.freecodecamp.org. I highly recommend it if you prefer to try things directly rather than watching videos.


Objects are similar to arrays, except that instead of using indexes to access and modify their data, you access the data in objects through what are called properties. Objects are useful for storing data in a structured way, and can represent real world objects.

var myDog = {
    "name": "Dog",
    "legs": 4,
    "tails": 1,
    "friends": ["Max", "Matilda"]
};

Note: If your object has any non-string properties, JavaScript will automatically typecast them as strings.


There are two ways to access the properties of an object: dot notation (.) and bracket notation ([]), similar to an array.

var myObj = {
  prop1: "val1",
  prop2: "val2"
};

var prop1Dot = myObj.prop1; // val1
var prop2Dot = myObj.prop2; // val2

var prop1Bracket = myObj["prop1"]; // val1
var prop2Bracket = myObj["prop2"]; // val2

Append / Delete Properties with dot or bracket notation.

var myObj = {
  prop1: "val1",
  prop2: "val2"
};

ourDog.prop3 = "val3";
ourDog["prop4"] = "val4";

delete myObj.prop3;
delete myObj["prop4"];

Note: Bracket notation is required if your property has a space in it or if you want to use a variable to name the property.


Check if the property of a given object exists or not using the hasOwnProperty() method or the in keyword.

var myObj = {
  prop1: "val1",
  prop2: "val2"
};

myObj.hasOwnProperty("prop1"); // true
myObj.hasOwnProperty("prop3"); // false

'prob1' in myObj; // true
'prob3' in myObj; // false

JSON – an array of objects https://www.json.org/json-en.html

var myObj = [{
  prop1: "val1",
  prop2: "val2"
},
{
  prop1: "val1",
  prop2: "val2"
}];

console.log(JSON.stringify(myObj));

Generate an Array of All Object Keys

Using the Object.keys() method and passing in an object as the argument will return an array with strings representing each property in the object.

let users = {
  Max: {
    age: 27
  },
  Mira: {
    age: 32
  },
  Rich: {
    age: 48
  }
};

function getArrayOfUsers(obj) {
  return Object.keys(obj);
}

getArrayOfUsers(users); // [ 'Max', 'Mira', 'Rich' ]

Note: Also have look at ES6 which includes new object syntax for constructors, getters and setters etc.

[JavaScript] Regular Expressions (regex)

These are my notes while doing the course JavaScript Algorithms and Data Structures on https://www.freecodecamp.org. I highly recommend it if you prefer to try things directly rather than watching videos.


Test Method

let myString = "Hello, World!";
let myRegex = /Hello/;
let result = myRegex.test(myString);

Match Literal Strings

Search for multiple patterns.

let petString = "Max has a pet cat.";
let petRegex = /dog|cat|bird|fish/; 
let result = petRegex.test(petString);

Ignore Case While Matching using the i flag.

let petString = "Max has a pet cat.";
let petRegex = /max/i;
let result = petRegex.test(petString); //result true

Extract Matches

"Hello, World!".match(/Hello/);

Note: The .match syntax is the “opposite” of the .test method.


Find More Than the First Match

Using the g flag.

let testStr = "Repeat, Repeat, Repeat";
let repeatRegex = /Repeat/g;
testStr.match(repeatRegex); // Returns ["Repeat", "Repeat", "Repeat"]

Note: You can have multiple flags on your regex like /search/gi


Match Anything with Wildcard Period

The wildcard character: .

let exampleStr = "Let's have fun with regular expressions!";
let unRegex = /.un/;
let result = unRegex.test(exampleStr);

Match Single Character with Multiple Possibilities

let bigStr = "big";
let bagStr = "bag";
let bugStr = "bug";
let bogStr = "bog";
let bgRegex = /b[aiu]g/;
bigStr.match(bgRegex); // Returns ["big"]
bagStr.match(bgRegex); // Returns ["bag"]
bugStr.match(bgRegex); // Returns ["bug"]
bogStr.match(bgRegex); // Returns null

Inside a character set, you can define a range of characters to match using a hyphen character: -, i.e. to match lowercase letters a through e you would use [a-e] or to match any number through 0 to 5 use [0-5].
To create a negated character set, you place a caret character (^) after the opening bracket and before the characters you do not want to match. For example, /[^aeiou]/gi
Outside of a character set, the caret is used to search for patterns at the beginning of strings. /^firstWord/.
You can search the end of strings using the dollar sign character $ at the end of the regex. /lastWord$/


Match Characters that Occur Zero|One or More Times

Match a character (or group of characters) that appears:
one or more times in a row using the + character. For example, /a+/g would find a match in "aabc" and return ["aa"].
zero or more times in a row using the * character. For example, /go*/g would find a match in "gooooooal" and return ["goooooo"], but only return ["g"] in "guuuuuuual".


Find Characters with Lazy Matching

Finds the smallest possible part of the string that satisfies the regex pattern with ?. For example "titanic" matched against the adjusted regex of /t[a-z]*?i/ returns ["ti"].


Match All Letters and Numbers

The shortcut \w is equal to [A-Za-z0-9_]. This character class matches upper and lowercase letters plus numbers. Note, this character class also includes the underscore character (_).

let quoteSample = "The five boxing wizards jump quickly.";
let alphabetRegexV2 = /\w/g; 
let result = quoteSample.match(alphabetRegexV2).length; // result 31

You can search for the opposite of the \w with \W. This shortcut is the same as [^A-Za-z0-9_].


Match All Numbers

The shortcut to look for digit characters is \d, with a lowercase d. This is equal to the character class [0-9], which looks for a single character of any number between zero and nine.
The shortcut to look for non-digit characters is \D. This is equal to the character class [^0-9].


Exercise: Restrict Possible Usernames

You need to check all the usernames in a database. Here are some simple rules that users have to follow when creating their username.

  1. Usernames can only use alpha-numeric characters.
  2. The only numbers in the username have to be at the end. There can be zero or more of them at the end. Username cannot start with the number.
  3. Username letters can be lowercase and uppercase.
  4. Usernames have to be at least two characters long. A two-character username can only use alphabet letters as characters.
let username = "JackOfAllTrades";
let userCheck = /^[a-z][a-z]+\d*$|^[a-z]\d\d$/i; 
let result = userCheck.test(username);

Match Whitespace

You can search for whitespace using \s. Will also match return, tab, form feed, and new line characters. Similar to [ \r\t\f\n\v].

let whiteSpace = "Whitespace. Whitespace everywhere!"
let spaceRegex = /\s/g;
whiteSpace.match(spaceRegex); // Returns [" ", " "]

Search for non-whitespace using \S, Similar to the character class [^ \r\t\f\n\v]


Quantity Specifiers

Quantity specifiers are used with curly brackets ({ and }). You put two numbers between the curly brackets – for the lower and upper number of patterns.
For example, to match only the letter a appearing between 3 and 5 times in the string "aaaah", your regex would be /a{3,5}h/.
To only specify the lower number of patterns, keep the first number followed by a comma. /a{3,}h/
To specify a certain number of patterns, just have that one number between the curly brackets. /ha{3}h/


Check for All or None

You can specify the possible existence of an element with a question mark ?

let american = "color";
let british = "colour";
let rainbowRegex= /colou?r/;
rainbowRegex.test(american); // Returns true
rainbowRegex.test(british); // Returns true

Positive and Negative Lookahead

Lookaheads are patterns that tell JavaScript to look-ahead in your string to check for patterns further along.
A positive lookahead will look to make sure the element in the search pattern is there, but won’t actually match it. A positive lookahead is used as (?=...)
A negative lookahead will look to make sure the element in the search pattern is not there. A negative lookahead is used as (?!...)
A practical use of lookaheads is to check two or more patterns in one string. Here is a (naively) simple password checker that looks for between 3 and 6 characters and at least one number:

let password = "abc123";
let checkPass = /(?=\w{3,6})(?=\D*\d)/;
checkPass.test(password); // Returns true

Reuse Patterns Using Capture Groups

You can search for repeat substrings using capture groups. Parentheses, ( and ), are used to find repeat substrings. To specify where that repeat string will appear, you use a backslash (\) and then a number. This number starts at 1 and increases with each additional capture group you use.

let repeatStr = "regex regex";
let repeatRegex = /(\w+)\s\1/;
repeatRegex.test(repeatStr); // Returns true
repeatStr.match(repeatRegex); // Returns ["regex regex", "regex"]

Note: Using the .match() method on a string will return an array with the string it matches, along with its capture group.


Use Capture Groups to Search and Replace

Search and replace text in a string using .replace() on a string. The inputs for .replace() is first the regex pattern you want to search for. The second parameter is the string to replace the match or a function to do something.

let str = "one two three";
let fixRegex = /(\w+)\s(\w+)\s(\w+)/; 
let replaceText = "$3 $2 $1"; 
let result = str.replace(fixRegex, replaceText); //result "three two one"

Exercise: Remove Whitespace from Start and End

/* my solution -> selecting the String */
let hello = "   Hello, World!  ";
let wsRegex = /(\s+)(\w+,\s\w+!)(\s+)/i; 
let result = hello.replace(wsRegex, "$2"); 

/* sample solution -> selecting the Whitespace */
let hello = "   Hello, World!  ";
let wsRegex = /^\s+|\s+$/g; 
let result = hello.replace(wsRegex, "");

[JavaScript] ES6

These are my notes while doing the course JavaScript Algorithms and Data Structures on https://www.freecodecamp.org. I highly recommend it if you prefer to try things directly rather than watching videos.


let and const

Variables with the var keyword can be overwritten without an error. With E6 the keyword let was introduced to solve this potential issue.

var camper = 'James';
var camper = 'David'; //no error

let camper = 'James';
let camper = 'David'; // throws an error

"use strict";
x = 3.14; // throws an error because x is not declared

Note: The "use strict" enables Strict Mode, which catches common coding mistakes and “unsafe” actions.


const

Same features as let has + read-only.

const FAV_PET = "Cats";
FAV_PET = "Dogs"; // returns error

Note: Use uppercase variable identifiers for immutable values and lowercase or camelCase for mutable values (objects and arrays).

Objects (including arrays and functions) assigned to a variable using const are still mutable!
Using the const declaration only prevents reassignment of the variable identifier. You can not use the variable identifier to point to a different array, but the elements are mutable.

const s = [10, 11, 12];
s = [1, 2, 3]; // throws error, trying to assign a const
s[2] = 45; // works just as it would with an array declared with var or let
s.pop(45); //also works fine

Prevent Object Mutation with function Object.freeze()


Arrow Functions

If you don’t reuse a function you don’t need a name for it, especially when passing a function as an argument to another function.

var magic = function() {
  return new Date();
};

/* arrow function syntax */
const magic = () => {
  return new Date();
};

/* If there is no function body and only a return, omit the keyword return as well as the backets */
const magic = () => new Date();

Arrow Functions with Parameters

const doubler = (item) => item * 2;
doubler(6); // returns 12

/* If you have a single parameter, omit the parentheses */
const doubler = item => item * 2;

const multiplier = (item, multi) => item * multi;
multiplier(6, 2); // returns 12

Default Parameters

The default parameter is used when the argument is not specified (is undefined).

const hello = (name = "World") => "Hello " + name;

console.log(hello("Mars")); // Hello Mars
console.log(hello()); // Hello World

Rest Parameter

With the rest parameter, you can create functions that take a variable number of arguments. These arguments are stored in an array.

function howMany(...arguments) {
  return "You passed " + arguments.length + " arguments.";
}
console.log(howMany(0, 1, 2)); // You passed 3 arguments.

Spread Operator

The spread operator allows us to expand arrays and other expressions in places where multiple parameters or elements are expected. I.e. Math.max() expects comma-separated arguments, but not an array. The spread operator unpacks all contents of an array into a comma-separated list. To pick specific elements, better use array destructuring.

const array = [2, 99, 7, 4];

/* workaround in ES5 */
var max = Math.max.apply(null, array); // returns 99

/* ES6 */
const max = Math.max(...array); // returns 99

Destructuring Assignment

Destructuring assignment is special syntax for neatly assigning values taken directly from an object,

const person = { name: 'Max', age: 30 };

/* ES5 */
const name = person.name; // name = 'Max'
const age = person.age; // age = 30

/* ES6 */
const { name, age } = person; // name = 'Max', age = 30
// It even allows you to assign a new variable name
const { name: personName, age: personAge } = user; // personName = 'Max', personAge = 30

or from an array.

const [a, b,,, c] = [1, 2, 3, 4, 5, 6, 7];
console.log(a, b, c); // 1, 2, 5

// or collect the rest of the elements into a separate array
const [a, b, ...array] = [1, 2, 3, 4, 5, 7];
console.log(a, b); // 1, 2
console.log(array); // [3, 4, 5, 7]

Destructuring Assignment to Pass an Object as a Function’s Parameters.

const stats = {
  max: 56.78,
  standard_deviation: 4.34,
  median: 34.54,
  mode: 23.87,
  min: -0.75,
  average: 35.85
};

const half = ({max, min}) => (max + min) / 2.0; 

Template Literals

Template literal is a special type of string that makes creating complex strings easier.

const person = {
  name: "Zodiac Hasbro",
  age: 56
};

const greeting = `Hello, my name is ${person.name}!
I am ${person.age} years old.`;

console.log(greeting); // prints
// Hello, my name is Zodiac Hasbro!
// I am 56 years old.

Concise Object Literal Declarations

Short way to define object properties.

const createPerson = (name, age, gender) => {
  return {
    name: name,
    age: age,
    gender: gender
  };
};

/* Eliminates the redundancy of having to write x: x */
const createPerson = (name, age, gender) => ({
    name,
    age,
    gender
  });

Concise Declarative Functions

Remove the function keyword and colon when defining functions in objects.

/* ES5 function declaration */
const person = {
  name: "Max",
  sayHello: function() {
    return `Hello! My name is ${this.name}.`;
  }
};

/* ES6 */
const person = {
  name: "Max",
  sayHello() {
    return `Hello! My name is ${this.name}.`;
  }
};
person.sayHello();

class Syntax to Define a Constructor Function

New syntax to create objects, using the class keyword. The class syntax replaces the constructor function creation. The new keyword is used to instantiate an object.

/* ES5 */
var SpaceShuttle = function(targetPlanet){
  this.targetPlanet = targetPlanet;
}
var zeus = new SpaceShuttle('Mars');


/* ES6 */
class SpaceShuttle {
  constructor(targetPlanet) {
    this.targetPlanet = targetPlanet;
  }
}
const zeus = new SpaceShuttle('Mars');

Note: The class syntax should not be confused with a full class-based implementation of an object-oriented paradigm.


getters and setters to Control Access to an Object

class Thermostat {
    constructor(temperatureFahrenheit) {
        this._temperatureCelsius = 5/9 * (temperatureFahrenheit - 32);
    }
    //getter
    get temperature() {
        return this._temperatureCelsius;
    }
    //setter
    set temperature(updateTemperatureCelsius) {
        this._temperatureCelsius = updateTemperatureCelsius;
    }
}

const thermos = new Thermostat(76); // Setting in Fahrenheit scale
let temp = thermos.temperature; // 24.44 in Celsius
thermos.temperature = 26; // use setter
temp = thermos.temperature; // 26 in Celsius

Note: It is convention to precede the name of a private variable with an underscore _


Module Script

A way to easily share code among JavaScript files. Export parts of a file and import the parts you need, where you need them.
You need to create a script in your HTML document with a type of module.

<script type="module" src="string_functions.js"></script>
const uppercaseString = (string) => string.toUpperCase();
const lowercaseString = (string) => string.toLowerCase();

export {uppercaseString, lowercaseString};
/* import specific functions */
import { uppercaseString, lowercaseString } from './string_functions.js';

uppercaseString("hello");
lowercaseString("WORLD!");

/* import all */
import * as stringFunctions from './string_functions.js';
stringFunctions.uppercaseString("hello");
stringFunctions.lowercaseString("WORLD!");

Promise

Use it to make a promise to do something, usually asynchronously. Promise is a constructor function, so you need to use the new keyword to create one. It takes a function, as its argument, with two parameters – resolve and reject.
When you make a server request it takes some amount of time, and after it completes you usually want to do something with the response from the server. This can be achieved by using the then method. The then method is executed immediately after your promise is fulfilled with resolve.

const makeServerRequest = new Promise((resolve, reject) => {
  // responseFromServer represents a response from a server
  let responseFromServer;
    
  if(responseFromServer) {
    resolve("We got the data");
  } else {  
    reject("Data not received");
  }
});

makeServerRequest.then(result => {
  console.log(result);
})

makeServerRequest.catch(error => {
  console.log(error);
});

[JavaScript] Arrays

These are my notes while doing the course JavaScript Algorithms and Data Structures on https://www.freecodecamp.org. I highly recommend it if you prefer to try things directly rather than watching videos.


Note: In JavaScript arrays are technically a type of object. Therefore arrays are also capable of storing complex objects.

Array functions to manipulate arrays:

/* Modify Array Data with Indexes */
var myArray = [50,40,30];
myArray[0] = 15; // equals [15,40,30]


/* Access Multi-Dimensional Arrays with Indexes */
var myArray = [
  [1,2,3],
  [4,5,6],
  [7,8,9],
  [[10,11,12], 13, 14]
];
myArray[3]; // equals [[10,11,12], 13, 14]
myArray[3][0]; // equals [10,11,12]
myArray[3][0][1]; // equals 11


/* Manipulate Arrays with push() -> adding to the end */
var myArray = [1,2,3];
myArray.push(4); // myArray is now [1,2,3,4]


/* Manipulate Arrays with pop() -> removing last element */
var threeArr = [1, 4, 6];
var oneDown = threeArr.pop();
console.log(oneDown); // Returns 6
console.log(threeArr); // Returns [1, 4]


/* Manipulate Arrays with shift() -> removing first element */
var myArray = ["Stimpson", "J", ["cat"]];
var removedFromOurArray = myArray.shift();
console.log(removedFromOurArray); // Returns "Stimpson"
console.log(myArray); // Returns ["J", ["cat"]]


/* Manipulate Arrays with unshift() -> adding to the beginning */
var myArray = ["Stimpson", "J", "cat"];
myArray.shift(); // myArray now equals ["J", "cat"]
myArray.unshift("Happy"); // myArray now equals ["Happy", "J", "cat"]


/* Manipulate Arrays with concat() -> combine arrays into a new one without mutating the original arrays. */
var firstArray = [1, 2, 3];
var secondArray = [4, 5, 6];
var thirdArray = firstArray.concat(secondArray); // thirdArray now equals [ 1, 2, 3, 4, 5, 6 ]
/* Also useable to clone an array (will do a copy by reference!) */
var fourthArray = [].concat(firstArray); // FourthArray now equals [1, 2, 3]


/* Remove & Add Items using splice() -> remove any number of consecutive elements from anywhere in an array. */
/* First parameter: index */
/* Second parameter: number of elements to delete */
let array = ['today', 'was', 'not', 'so', 'great'];
array.splice(2, 2);  // array now equals ['today', 'was', 'great']
/* Third parameter: add elements to the array. Useful for quickly switching out an element, or a set of elements, for another. */
const numbers = [10, 11, 12, 12, 15];
numbers.splice(3, 1, 13, 14); // returns [ 10, 11, 12, 13, 14, 15 ]


/* Sort numbers in an array: array.sort(compareFunction) */ 
arr.sort((a, b) => a-b); // ascending
arr.sort((a, b) => b-a); // descending

Array functions that does not mutate the original array:

/* Copy Array Items Using slice() -> copies or extracts a given number of elements to a new array, leaving the array it is called upon untouched */
let weatherConditions = ['rain', 'snow', 'sleet', 'hail', 'clear'];
let todaysWeather = weatherConditions.slice(1, 3); // todaysWeather equals ['snow', 'sleet'];


/* Copy an Array with the Spread Operator -> allows to easily copy all of an array's elements. Syntax: ... */
let thisArray = [true, true, undefined, false, null];
let thatArray = [...thisArray]; // thatArray equals [true, true, undefined, false, null];


/* Combine Arrays with the Spread Operator */
let fragment = ['to', 'code'];
let sentence = ['learning', ...fragment, 'is', 'fun']; // sentence equals ['learning', 'to', 'code', 'is', 'fun']


/* The reduce() method reduces the array to a single value. It executes a provided function for each value of the array (from left-to-right).*/
/* First parameter: The initialValue, or the previously returned value of the function */
/* Second parameter: The value of the current element */
/* 0 is set as initialValue */
const args = [2, 4, 2];
const arraySum = args.reduce((sum, currentNum) => sum + currentNum, 0); // returns 8 


/* map() iterates over each item in an array and returns a new array containing the results of calling the callback function on each element */
const users = [
  { name: 'John', age: 34 },
  { name: 'Amy', age: 20 },
  { name: 'camperCat', age: 10 }
];
const names = users.map(user => user.name); // [ 'John', 'Amy', 'camperCat' ]

Checks:

/* indexOf() checks for the presence of an element -> takes element as parameter. Returns the position (index) or -1 if element does not exist */
let fruits = ['apples', 'pears', 'oranges', 'peaches', 'pears'];
fruits.indexOf('dates'); // returns -1
fruits.indexOf('oranges'); // returns 2
fruits.indexOf('pears'); // returns 1, the first index at which the element exists


/* every() checks if every element passes a particular test */
function checkPositive(arr) {
   return arr.every(num => num > 0); 
}
checkPositive([1, 2, 3, -4, 5]); // false


/* some() checks if any element passes a particular test. */
function checkPositive(arr) {
  return arr.some(num => num > 0); 
}
checkPositive([1, 2, 3, -4, 5]); // true

And there are several other build in methods like forEach(), filter(), etc.
https://www.w3schools.com/jsref/jsref_obj_array.asp

Note: As already mentioned, arrays are objects, therefore array functions are methods on the array object prototype, i.e. Array.prototype.push()

[JavaScript] Math & Numbers

/* generates a random decimal number between 0 (inclusive) and up to 1 (exclusive). */
Math.random()

/* Round the number down to its nearest whole number. */
Math.floor()

/* x to the power of y */
Math.pow(num, 2)

/* Pi */
Math.PI;

/* Square root */
Math.sqrt(16);

/* Parse a string and return as integer. */
var int = parseInt("020"); // returns 20

/* Parse a string and return as float. */
var float = parseFloat("8.55"); // returns 8.55

/* Check if number is not float */
function isInt(n) {
   return n % 1 === 0;
}

[JavaScript] Conditional (Ternary) Operator

Can be used as a one line if-else expression. Syntax:

condition ? expression-if-true : expression-if-false;

function checkEqual(a, b) {
    return a == b ? "Equal" : "Not Equal";
}

/* Chain them together to check for multiple conditions */
function checkSign(num) {
    return (num == 0) ? "zero"
        : (num > 0) ? "positive"
        : "negative";
}

/* If there is no "else", just write */
function checkEqual(a, b) {
    if (a == b) return "Equal";
}
console.log(checkEqual(1, "1"));

[JavaScript] Switch Statement

Note: Case values are tested with strict equality (===)

/* Default Option in Switch Statements */
var result = "";
switch (num) {
  case 1:
    result = "1";
    break;
  case 2:
    result = "2";
    break;
  default:
    result = "3 or more";
    break;
}

/* Multiple Identical Options in Switch Statements */
var result = "";
switch(val) {
  case 1:
  case 2:
  case 3:
    result = "1, 2, or 3";
    break;
  case 4:
    result = "4 alone";
}

[JavaScript] Iterate

While Loops

var myArr = [];
var i = 0;

while(i < 5) {
  myArr.push(i);
  i++;
}

For Loops

var myArr = [];

// for ([initialization]; [condition]; [final-expression])
for (var i = 0; i < 5; i++) {
  myArr.push(i);
}

Iterate through an Array with a For Loop

var myArr = [ 2, 3, 4, 5, 6];
var total = 0;

for (var i = 0; i < myArr.length; i++) {
    total += myArr[i];
}

Nesting For Loops

var myArr = [
  [1,2], [3,4], [5,6]
];

for (var i=0; i < myArr.length; i++) {
  for (var j=0; j < myArr[i].length; j++) {
    console.log(myArr[i][j]);
  }
}

For…In Loops

Iterate through all the keys within an object.

let users = {
  Max: {
    age: 27
  },
  Mira: {
    age: 32
  },
  Rich: {
    age: 48
  }
};

for (let user in users) {
  console.log(user); // logs: Max, Mira, Rich
  if (users[user].age > 40) {
      console.log(`${user} is old.`);
  }
} 

Do…While Loops

A do...while loop ensures that the code inside the loop will run at least once.

var myArr = [];
var i = 0;
do {
  myArr.push(i);
  i++;
} while (i < 5);

Replace Loops using Recursion

/* For Loop */
function multiply(arr, n) {
   var product = 1;
   for (var i = 0; i < n; i++) {
       product *= arr[i];
   }
   return product;
}

/* Replace For Loop with Recursion */
function multiply(arr, n) {
   if (n <= 0) {
     return 1;
   } else {
     return multiply(arr, n - 1) * arr[n - 1];
   }
}

Note: Recursive functions must have a base case when they return without calling the function again (in this example, when n <= 0), otherwise they can never finish executing.

/* Count to n */
function countup(n) {
  if (n < 1) {
    return [];
  } else {
    const countArray = countup(n - 1);
    countArray.push(n);
    return countArray;
  }
}

console.log(countup(5)); // [ 1, 2, 3, 4, 5 ]

Note: The push happens last, after the recursive call has returned. Thats why the value of n decreases, but the values in the final array are increasing.

/* Create a Range of Numbers */
function rangeOfNumbers(startNum, endNum) {
  if (startNum == endNum) {
    return [startNum];
  } else if (startNum < endNum) {
    const rangeArray = rangeOfNumbers(startNum + 1, endNum);
    rangeArray.unshift(startNum);
    return rangeArray;
  } 
};

console.log(rangeOfNumbers(5, 10)); // [ 5, 6, 7, 8, 9, 10 ]

[JavaScript] Functions

/* Basic Function */
function reusableFunction() {
  console.log("Hello World");
}
reusableFunction();


/* Passing Values to Functions with Arguments */
function functionWithArgs(arg1, arg2 ) {
    console.log(arg1 + arg2);
}
functionWithArgs(1, 2); //returns 3


/* Global vs. Local Scope in Functions 
It is possible to have both local and global variables with the same name. 
When you do this, the local variable takes precedence over the global variable. */
var outerWear = "T-Shirt";
function myOutfit() {
  var outerWear = "sweater"
  return outerWear;
}
myOutfit(); //returns "sweater"

[JavaScript] Comparsion Operators

/* Equality Operator (type conversion / type coercion) */
1   ==  1   // true
1   ==  2   // false
1   == '1'  // true
"3" ==  3   // true


/* Strict Equality Operator (no type conversion) */
3 ===  3   // true
3 === '3'  // false


/* Inequality Operator (type conversion) */
1 !=  2     // true
1 != "1"    // false
1 != '1'    // false
1 != true   // false
0 != false  // false

/* Strict Inequality Operator (no type conversion) */
3 !==  3   // false
3 !== '3'  // true
4 !==  3   // true

/*Greater Than Operator (type conversion) */
5   >  3   // true
7   > '3'  // true
2   >  3   // false
'1' >  9   // false

/* Greater Than Or Equal To Operator (type conversion) */ 
6   >=  6   // true
7   >= '3'  // true
2   >=  3   // false
'7' >=  9   // false

/* Less Than Operator (type conversion) */
2   < 5  // true
'3' < 7  // true
5   < 5  // false
3   < 2  // false
'8' < 4  // false

/* Less Than Or Equal To Operator (type conversion) */
4   <= 5  // true
'7' <= 7  // true
5   <= 5  // true
3   <= 2  // false
'8' <= 4  // false