JavaScript – JS & the DOM

Creating and inserting elements

  • createElement()
  • insertAdjacentHTML()
const newElement = document.createElement('div');
newElement.classList.add('newClass');
message.innerHTML =  'My HTML content';

header.append(message); // or prepend, or before, or after.

message.remove(); // remove element

Other methods etc:

// Styles

message.style.backgroundColor = '#232323'; // use camelCase - sets inline style
getComputedStyle(message).height;

Number.parseFloat(getComputedStyle(message).height, 10) // Gets numeric value of height

document.documentElement.style.setProperty('--color-primary', 'orangered'); // Sets root style variables

// Attributes
myButton.alt; myButton.src; myButton.className;
myButton.getAttribute('customAttribute');
myButton.dataset.versionNumber // gets data-version-number

Smooth Scroll

const btnScrollTo = document.querySelector('.btn-scroll-to');
const section1 = document.querySelector('#section--1');

btnScrollTo.addEventListener('click', function(e) {
  const s1coords = section1.getBoundingClientRect();
}

window.scrollTo({
 left: s1coords.left,
 top: s1coords.top + window.pageYOffset);
 behaviour: 'smooth'
});

// MODERN BROWSERS
section1.scrollIntoView({behaviour: 'smooth'});

// Viewport
document.documentElement.clientHeight document.documentElement.clientWidth

More Events & EventHandlers

const mouseEnterFunction = function(e) {// do something}

message.addEventListener('mouseenter', mouseEnterFunction); // allows you to add multiple event listeners.

// Alternatively - old version
message.onmouseenter = function (e) {};

// Remove
setTimeout(() => message.removeEventListener('mouseenter', mouseEnterFunction), 2000);

Bubbling & Capturing

Event is initially captured at root. Capturing phase goes through all the child elements to the target phase and the passes back (bubbling phase).

JavaScript: Timers

There are two types of timers: setTimeout and setInterval.

setTimeout()

setTimeout( () => console.log('show this after 3 seconds'), 3000);

The code will continue to be read after the setTimeout, it will run the timer in the background while it continues the code.

Timer can be cleared before executed using clearTimeout()

setInterval()

Creates a timed loop.

setInterval(function () {
  const now = new Date();
  console.log(now);
}, 1000);

Example Timer countdown

const startLogoutTimer = function() {
  const tick = function() {
    const min = String(Math.tunc(time / 60).padStart(2,0);
    const sec = String(time % 60).padStart(2,0); // remainder literal

    // In each call, print the remaining time to UI
    labelTimer.textContent = `${min}:${sec}`;

    // when - seconds, stop timer and log out user
    if(time === 0) {
      clearInterval(timer)
    }

    // Decrease by 1s
    time--;

  }

  // Set time to 5 minutes
  let time = 100;
  
  // Call the timer every second
  tick()
  const startTimer = setInterval(tick , 1000}
}

JavaScript – Dates

New Date()

Get’s current date, or pass a string or seconds passed since UNIX time 1/1/70 01:00

Date components have methods

const future = new Date(2037, 10, 19, 15, 23)
future.getFullYear();
future.getMonth();
future.getDate();
future.getDay();
future.getHours();
future.getMinutes()
future.getSeconds()
future.getISOString()
future.getTime(); // get timestamp

future.setFullYear(2040) // Modifies object

Operations with Dates

Convert date to a Number (+ or Number()) you can then perform maths on dates.

const calcDaysPassed = (date1, date2) => Math.abs(date2 - date1) / (1000 * 60 * 60 * 24);

Internationalizing Dates (Intl)

const now = new Date();
const options = {
 hour: 'numeric',
 minute: 'numeric',
 day: 'numeric',
 month: 'long',
 year: 'numeric',
 weekday: 'long'
}

new Intl.DateTimeFormat('en-US', options).format(now); // use ISO language code

const locale = navigator.language // Get ISO code from user's browser

Internationalizing Numbers (Intl)

new Intl.NumberFormat('en-US').format(num);

const options = {
  style: 'currency', // unit percent or currancy
  unit: 'celsius',
  currency: 'EUR'  // Not defined by locale so needs to be implied
  useGrouping: false // removes seperators
}

Javascript – Numbers

Numbers are binary base in javascript

+ works the same as Number():

Number('23')
+('23)

Number.parseInt(string, redex)

Turns string into integer if it starts with a number (removing any other characters in the string. Redex not neccessary

Number.parseInt('20px', 10) // returns 20
Number.parseInt('e20', 10) // returns NaN

Number.parseFloat(string, redex)

parseFloat is used if the number has a decimal place.

Number.isNaN(string)

Boolean to check if it is not a number

Number.isFinite(), Number.isInteger()

Better to use than isNaN. To check if it is a number as it can check if numbers are divided by 0.

Math

Math.sqrt*(); Square root
Math.max(array) // Returns maximum number in array (does string to number converstion)
Math.min(array) // Returns minimum in array

Math.PI + Number.parseFloat(radius) ++2)

//Random
Math.trunc.random() * 6) + 1); // gets a number between 1 and 6

// Random Function
const randomInt = (min, max) => Math.floor(random() * (min-max + 1) + min)
console.log(randomInt(10,20));

// Rounding Integers
Math.trunc(23.3) // removes the decimal values
Math.round() // round to nearest
Math.ceil() // round up
Math.floor() // round down

// Rounding decimals
(value).toFixed(nummber of decimal places) // !!! Returns String
+(2.345).toFixed(2) // returns 2.34

Remainder operator

returns the remainder of a division

5 % 2 // returns 1

Numeric Seperator

Use _, js will ignore it and convert the number fully.

BigInt

JS has 53 bytes for integers, so there is a limit to the highest number that can be used

Number.MAX_SAFE_INTEGER

Use n at the end of a very lager number or use BigInt()

Cannot mix BigInts with regular numbers (except on < or >) (convert number to bigInt). Math operations will not work either.

Javascript – Functions

Passing by value vs Passing by reference.

Javascript only has passing by value.

First Class and Higher Order Functions

First-Class Functions

  • JS treats functions as first-class citizens
  • This means that functions are simply values
  • Functions are just another “type” of object

Therefore they can be stored in objects and passed as parameters in other functions.

There are methods on functions (such as .bind())

Higher-Order Function

  • A function that receives another function as an argument, that returns a new function or both
  • This is only possible because of first-class functions
btnClose addEventListener('click', greet) // higher order function (addEventListener); first-class function (greet)

const myFunction = function(str, fn) // Callback function

Callback Functions

Allow us to create abstraction.

Vital part of the JavaScript

Call, Apply & Bind Methods

.call() is a method that can be applied to the function which sets the ‘this’ keyword (passed in the first argument).

.apply(thisArg, argsArray) is the same as above however it requires an array as the second argument.

…however with the spreadoperator there is no need to use the .apply method, just use .call(thisArg, ...argsArray) as it does the same thing.

The bind() method works like the .call() method but returns a new function. The new function is bound to the new object. You can also pass arguments after the thisArg to set the default parameters (partial application).

The bind method is useful when used with Event Listeners

lufthansa.planes = 300;
lufthansa.buyPlane = function() {
 console.log(this);
 this.planes++;
 console.log(this.planes);
};

// NaN
document.querySelector('button.buy').addEventListener('click', lufthansa.buyPlane) // this would be the buy button and therefore not work

// 301
document.querySelector('button.buy').addEventListener('click', lufthansa.buyPlane.bind(lufthansa);

Partial application

const addTax = (rate, value) => value + value * rate;

const ukTax = addTax.bind(null, 0.2); // this sets the value to a default

Coding challenge

'use strict';

///////////////////////////////////////
// Coding Challenge #1

/* 
Let's build a simple poll app!

A poll has a question, an array of options from which people can choose, and an array with the number of replies for each option. This data is stored in the starter object below.

Here are your tasks:

1. Create a method called 'registerNewAnswer' on the 'poll' object. The method does 2 things:
  1.1. Display a prompt window for the user to input the number of the selected option. The prompt should look like this:
        What is your favourite programming language?
        0: JavaScript
        1: Python
        2: Rust
        3: C++
        (Write option number)
  
  1.2. Based on the input number, update the answers array. For example, if the option is 3, increase the value AT POSITION 3 of the array by 1. Make sure to check if the input is a number and if the number makes sense (e.g answer 52 wouldn't make sense, right?)
2. Call this method whenever the user clicks the "Answer poll" button.
3. Create a method 'displayResults' which displays the poll results. The method takes a string as an input (called 'type'), which can be either 'string' or 'array'. If type is 'array', simply display the results array as it is, using console.log(). This should be the default option. If type is 'string', display a string like "Poll results are 13, 2, 4, 1". 
4. Run the 'displayResults' method at the end of each 'registerNewAnswer' method call.

HINT: Use many of the tools you learned about in this and the last section 😉

BONUS: Use the 'displayResults' method to display the 2 arrays in the test data. Use both the 'array' and the 'string' option. Do NOT put the arrays in the poll object! So what shoud the this keyword look like in this situation?

BONUS TEST DATA 1: [5, 2, 3]
BONUS TEST DATA 2: [1, 5, 3, 9, 6, 1]

GOOD LUCK 😀
*/

const poll = {
  question: 'What is your favourite programming language?',
  options: ['0: JavaScript', '1: Python', '2: Rust', '3: C++'],
  // This generates [0, 0, 0, 0]. More in the next section 😃
  answers: new Array(4).fill(0),
  registerNewAnswer() {
    let response = Number(
      prompt(
        this.question +
          '\n' +
          this.options.join('\n') +
          '\n(Write option number)'
      )
    );
    console.log(response);
    if (response >= this.options.length || response === NaN) {
      alert('Write option number');
      this.registerNewAnswer();
    } else {
      // update answers array
      this.answers[response]++;
      this.displayResults(this.answers);
    }
  },
  displayResults(type = 'array') {
    if (type === 'array') {
      console.log(this.answers);
    } else {
      console.log(`Poll results are ${this.answers.join(',')}`);
    }
  },
};

document
  .querySelector('.poll')
  .addEventListener('click', poll.registerNewAnswer.bind(poll));

const pollResponses = [5, 2, 3];

poll.displayResults.call({ answers: pollResponses }, 'string');

Immediately Invoked Function Expression (IIFE)

(function() {console.log('one time function')})();

(() = console.log('one time function'))();

All data inside IIFE is private and encapsulated.

Closures

A closure makes the function remember all the variables that were created at the function’s birthplace. If a variable is reachable via closure then it is not garbage collected from the Heap.

A closure gives a function access to all the variables of its parent function even after that parent function has returned. The function keeps a reference to its outer scope, which preserves the scope chain throughout time.

const secureBooking = function () {
  let passengerCount = 0;
  return function () {
    passengerCount++;
    console.log(`${passengerCount}passengers`);
  };
};

const booker = secureBooking();
booker();
booker();  // passengerCount still increments because closure.

console.dir(booker); // will show closure in the scopes

JavaScript overview

High-Level

Low-level languages like C need a dev to manage resources manually. JS is high-level so does not have to worry as system resource management happens automatically (abstractions).

+ easy to use and learn
– not as fast or optimised

Garbage-collected

Automatically clears unused objects from memory

Interpreted or Just-in-time compiled

ones and zeros (machine-code) via compiling / interpretation via the javascript engine. The engine compiles the source code to machine code and then immediately executes it without putting it in a portable file. Faster than compiling it line by line.

STEPS:

  • Parsing (AST) goes through the code and turns it into a tree
  • Compilation – turns it into machine code
  • Execution – (happens in the call stack) – Code is reoptimised during execution.

Multi-paradigm

More than one way to skin a cat. Imperative / declarative.

  • Procedural programming (linear)
  • Object-oriented programming (OOP)
  • Functional programming (FP)

Prototype-based object-oriented

Template/blueprint.

First-class functions

Functions used as variables. Can be passed to other functions.

Dynamic

Dynamically typed. Variable datatypes not assigned manually, js assigns them. A bit buggy – Typescript resolves

Non-blocking event loop

Concurrency model – JS engine handles multiples tasks at the same time although runs in one single thread. Event loops avoid long running tasks blocking.

JS ENGINE

Engine executes JS code. All browsers have their own engines. Chrome uses V8 (also powers node JS) for example.

All engines have a call stack and a heap.

CALL STACK
Is where code is executed.

HEAP
Is where objects are stored.

Javascript runtime in the browser

Runtime = is everything in the browser required to run javascript: engine, web APIs (accessed through global window), callback queue (click, timer, data)

Execution Concept

  • Variable environment
  • scope chain
  • this keyword

3 types of Scope

GLOBAL, FUNCTION, BLOCK (ES6)

Global Scope

These variables are declared outside of function and block and are accessible anywhere.

Function Scope (local scope)

These variables only accessible inside function.

Block Scope

Everything within curly braces (if or while loops). Only let or const variables (not var wehich is function-scoped). Functions are block scoped (in strict mode)

Scope Chain

Variable Lookup. A scope has access to variable from all outer (parent) scopes.

Hoisting

Hoisting makes some types of variables accessible/ usable in the code before they are actually declared (lifted to the top of the scope)

Hoisted: function dec & var, function expressions and arrows (depends on declared with let or const)

TEMPORAL DEAD ZONE

Modifying local Hosts file

  • Launch Terminal, type sudo nano /private/etc/hosts and press Return. You’ll need to also enter your admin password to execute it, as with all sudo commands.
  • You will now have the hosts file open in the Nano editor. Use the arrow keys on your keyboard, to navigate and edit the file.
  • Like with the Windows method above you should just add the desired IP followed by the host name (or domain name).
  • Press Control-O to save the file.
  • Use your Web browser to test the changes and flush the cache with dscacheutil -flushcache if they still haven’t taken into effect.

Adding AOS scrolling animation to WordPress

Add aos.scss to sass/assets folder and import in child-theme.scss

Add aos.js to src/js/

Add path to gulpfile.js

Add AOS.init to custom-javascript.js:

AOS.init({
delay: 150, // values from 0 to 3000, with step 50ms
duration: 1000,
mirror: true
});