javascript

JavaScript

September 01, 2022

JavaScript

Yuri Kim


JavaScript

The primary programming language of the web, primarily used for adding functionality to websites. JavaScript is a general purpose multi-paradigm programming language with dynamic typing

__

Paradigm

A style of programming. Oftentimes languages are built with a specific paradigm in mind, but JavaScript is known as a multi-paradigm language, because it allows for programming in a variety of paradigms. Some of the major paradigms of JavaScript include:

  • Event-driven: Functions can be made to respond to events, such as when a user clicks on an element or scrolls down the page.
  • Functional: Functions can be written as "pure functions", meaning functions that always have the same output for a given set of arguments and never produce side effects. Additionally, JavaScript supports first-class functions and higher-order functions. This means that functions can be treated as normal values, passed as arguments to other functions and returned from functions.
  • Object-oriented: Objects can be created as custom data stores and they can be made to inherit from each other.
  • Imperative: Programs can be written by explicitly describing the control flow, such as with loops and conditionals.
  • Declarative: Programs can be written by describing the desired output with implicit control flow. Oftentimes this is associated with functional programming (e.g. using the forEach function to loop over an array instead of a for loop)

__

Primitive

The most basic data types of a language. In JavaScript, there are 7 primitive types:

  • Number: Numeric values, including integers and decimal values.
  • BigInt: Integers too large to store in a number.
  • Boolean: A binary value of true or false.
  • String: A sequence of characters.
  • Symbol: A dynamically generated unique value.
  • Null: A nonexistent value.
  • Undefined: A value that has not been set.

JavaScript has a typeof operator that can get the type of a value as a lowercase string. However, do be aware that this function does have some special casing. For example, typeof function will return "function" even though functions are just objects.

__
__

Variables and Scoping

let

A keyword for declaring a block-scoped variable that cannot be accessed before initialization.

__

var

A keyword for declaring a function-scoped variable that is automatically initialized to undefined when it is hoisted.

__

const

A keyword for declaring a constant value. Constants have the same behavior as variables declared with let, except they cannot be reassigned.

__

Block Scope

The behavior of a variable that is only accessible inside of the block it was defined. Most of the time, the block will simply be the nearest pair of curly braces to the declaration.

__

Function Scope

The behavior of a variable that is accessible anywhere inside of the function it was defined.

__

Hoisting

The process by which the JavaScript engine moves variable declarations to the top of their scope, allocating memory for them before reaching the line of code where they are declared. For variables declared with var, they are initialized to undefined until reaching the line of code that initializes the variable. For variables declared with let or const, the variable is not initialized and thus cannot be accessed before the line of code that initializes it.

console.log(varNum); // undefined console.log(letNum); // reference error var varNum = 5; let letNum = 5; console.log(varNum); // 5 console.log(letNum); // 5
__
__

Arrays

A data structure for storing lists of information.

__

Arrays are mutable and can contain data of different types. While these are just standard objects, they have a special syntax for easily creating and updating them

const arr = [1, 2, 3]; console.log(arr[1]); // 2
__
__

Objects

The base non-primitive data structure of JavaScript used to store key-value pairs. Object keys are usually strings, but they can also be symbols. Values on the other hand can be any type. Objects are usually declared with the object literal syntax:

const website = { name: 'AlgoExpert', domain: 'algoexpert.io' };
__

Symbol

A primitive value in JavaScript used for unique values.

  • A symbol is created using the Symbol(description) function, which returns a unique symbol. Even if two symbols have the same description, they will still be considered unique.
  • While symbols created using the Symbol(description) function are completely unique, symbols can also be created using Symbol.for(key). This works the same way, except two calls to this function with the same key will return the same symbol, based on a global symbol registry.
__
__

Equality and Type Coercion

Loose Equality

The most basic equality operator in JavaScript using ==. Loose equality compares values regardless of types following these steps:

  • If both values are either null or undefined, return true.
  • Convert all booleans to numbers. True converts to 1 and false converts to 0.
  • If comparing a number to a string, convert the string to a number.
  • If comparing an object to a string, convert the object using its toString() or valueOf() methods.
  • If the types are the same, follow the same rules as strict equality.
__

In general, strict equality should be preferred due to it being easier to predict. However, loose equality can be useful for checking against null and undefined at once with value == null.

__

Strict Equality

A JavaScript equality operator using ===. Strict equality compares both values and types following these steps:

  • If either value is NaN, return false.
  • If the values have different types, return false.
  • If both values are null or both values are undefined, return true.
  • If both values are objects, return true if they are the same object. False otherwise.
  • If both values are of the same primitive type, return true if the values are the same. False otherwise.
__
__

Syntactic Sugar and Modern JavaScript

Arrow Function

A more concise function syntax, particularly useful for replacing short anonymous functions. The basic syntax for an arrow function is:

(param1, param2) => { doSomething(param1, param2); return 'hello world'; }

However, if an arrow function only requires one line, then the curly braces and return keyword can be removed. Additionally, when these are used inline such as for a call to the array map function, the semicolon must be removed. Finally, if there is only one parameter, the parentheses around the parameter can also be removed. For example, this code will create an array with the values doubled:

[1, 2, 3, 4].map(num => num * 2);

There are a few constraints to arrow functions which will be explored throughout the crash course. The most important of these is that arrow functions do not have their own this binding. Additionally, arrow functions cannot be used as constructors or generators.

__

Destructuring Assignment

A JavaScript syntax for saving values from an array or object in variables. For example:

const [first, second] = [1, 2, 3]; console.log(first); // 1 console.log(second); // 2 const { name } = { name: 'Conner' }; console.log(name); // 'Conner'

When destructuring an object, fields can also be renamed, for example:

const { name: firstName } = { name: 'Conner' }; console.log(firstName); // 'Conner'

Destructuring can also be used in a function parameter, for example:

function printName({ name }) { console.log(name); }
__

Rest Operator

A JavaScript operator using ... for condensing multiple elements into a single array. This uses the same syntax as the spread operator, but functionally is essentially the opposite.

__

Rest syntax can be used in both arrays and objects to get all of the values not being destructured:

const arr = [1, 2, 3, 4]; const [first, second, ...rest] = arr; // rest is [3, 4] const obj = { key1: 1, key2: 2, key3: 3, key4: 4 }; const { key1, key2, ...rest } = obj; // rest is { key3: 3, key4: 4 } };

Moreover, rest syntax can be used for function parameters to accept an infinite number of arguments, which are accessible as an array:

function myFunc(...myArguments) { console.log(myArguments); } myFunc(1, 2, 3, 4); // logs [1, 2, 3, 4]
__

Spread Operator

A JavaScript operator using ... for expanding iterables into individual elements. For example myFunction(...myArray) would pass each value in myArray as individual arguments to myFunction.

  • The spread syntax can also be used to combine two arrays, for example, [...arr1, ...arr2] would make a single array with all of the values of both arrays. Similarly, objects can be spread as well
  • For example, {key: 'value', ...otherObj} would add all of the fields from the other object into this object. Moreover, {...obj} can be used as a shallow clone of an object, since it creates a new object with the same fields.
__

Template Literal

Strings created using backticks `` that allow for inlining expressions rather than needing concatenation. Inlined expressions use the syntax ${expression}. For example, Hello ${name} would have the same output as 'Hello' + name.

  • Template literals also allow for tagging to write a function that defines custom behavior for the template literals. Tagging can be read about further in the MDN documentation, but it doesn't tend to be used too often.
__

Null Coalescing

Also referred to as nullish coalescing, an operator using ?? for providing a default value if a value is null. If the value on the left side of the operator is not null or undefined, that value is used. Otherwise, the value on the right side of the operator is used. For example:

const num = null ?? 1234; // 1234 const num2 = undefined ?? 1234; // 1234 const num3 = 5678 ?? 1234; // 5678 const num4 = '' ?? 1234; // ''

Optional Chaining

A JavaScript operator using ?. for reading object properties without throwing an error if the object is null. For example, person?.company?.website will act the same as person.company.website, however if any values in the chain are null or undefined, it will return undefined rather than throwing an error.

__

Short Circuit Evaluation

A method of utilizing the evaluation order of JavaScript to conditionally run code. This usually uses the && operator, because for it to return true, both the left and right expressions must be true. Since the browser runs code from left to right, if it encounters false on the left side, it does not even run the code on the right side. Thus, this can be used to conditionally run code:

true && myFunc(); // calls myFunc() false && myFunc(); // doesn't call myFunc()

Less commonly, short circuit evaluation can also be used with the || operator. Since this operator only needs one expression to be true, if the left side is true then the right side will not be evaluated. This is essentially the opposite of the behavior with &&. For example:

true || myFunc(); // doesn't call myFunc() false || myFunc(); // calls myFunc()
__
__

Connecting JavaScript to HTML

<script>

The HTML tag for adding JavaScript to the document. Usually the <script> appears in the <head> with no children. Instead of children, it usually has the src attribute set to the path of a JavaScript file.

__

By default, scripts block the browser from continuing to parse and render the rest of the DOM until the script has finished downloading and executing. However, there are two boolean attributes that can change this behavior:

  • defer: Fetch the script asynchronously without blocking the page. Only execute the script after the DOM has finished being parsed.
  • async: Fetch the script asynchronously without blocking the page. Whenever the script is ready, stop parsing the DOM and execute the script. This is usually only for scripts that do not need access to the DOM, because otherwise the behavior will be inconsistent based on how quickly the script downloaded.
__

Alternatively, scripts were traditionally placed at the bottom of the <body> to ensure the DOM finished loading before running the script. However, this is usually slower than using the defer attribute, since the script will not be downloaded until reaching the script tag at the end of the body.

DOM Manipulation

Using JavaScript to change the content, structure or styles of the page. There are a lot of functions and properties related to DOM manipulation, but these are some of the more common ones:

Getting Elements:

  • document.getElementById(id): Gets a single element based on its id attribute.
  • document.querySelector(cssSelector): Gets a single element based on a CSS selector. If multiple elements match the selector, returns the first one.
  • document.querySelectorAll(cssSelector): Gets all elements matching a CSS selector as a NodeList.
  • document.getElementsByTagName(tagName): Gets all elements with a specific HTML tag as an HTMLCollection.
  • document.getElementsByClassName(className): Gets all elements with a specific class as an HTMLCollection.

Setting Attributes:

  • element.style.property: Sets a CSS property using inline styles, although CSS classes should usually be preferred. The style object will only contain inline styles, not those set with CSS.
  • element.setAttribute('attribute', 'value'): Sets an HTML attribute to a specific value.
  • element.textContent: The text content of an element, including that of any children. Note: this is slightly different from element.innerText, which only gets text that is actually rendered and element.innerHTML which gets the entire HTML code as a string.
  • element.attribute: An alternative to the setAttribute function, attributes can be directly edited via their property name. For example, element.value would get the value attribute of the element.
  • element.classList: An object for updating CSS classes. Specifically, this contains 3 primary functions: add(className), remove(className) and toggle(className).

Adding And Removing Elements:

  • document.createElement(tagName): Creates a new HTML element.
  • document.createTextNode(text): Creates a text node as an alternative to setting textContent.
  • document.createDocumentFragment(): Creates a document fragment, which is useful for appending multiple elements at once after a loop.
  • element.appendChild(element): Appends an element to the end of the contents of another element.
  • element.append(node1, node2, ...): Appends 1 or more nodes (elements or text) to the end of the contents of another element.
  • element.prepend(node1, node2, ...): Prepends 1 or more nodes (elements or text) to the beginning of the contents of another element.
  • element.remove(): Removes the element from the DOM.

Sizes and Scrolling:

  • window.innerWidth: The width of the browser window.
  • window.innerHeight: The height of the browser window.
  • window.getComputedStyle(element): Gets styles as they are currently rendered on the page, converted to pixels.
  • element.clientHeight: The height of visible content and padding.
  • element.offsetHeight: The height of visible content, padding, borders and scrollbars.
  • element.scrollHeight: The height of all content and padding, including content scrolled out of view.
  • element.offsetTop: The distance from the outer top border of the element to the inner top border of the nearest positioned parent.
  • element.scrollIntoView(): Scrolls the container so the element is in view.
  • element.scrollTo(optionsObj): Scrolls the element to a specified top value in the options object. Additionally, behavior: 'smooth' will create a smooth transition.

Event-Driven Programming

A programming paradigm where code runs as a response to events, usually initiated by the user.

  • To create an event listener, use element.addEventListener(eventName, callback, useCapture). If the third argument is true, the callback will fire during the capturing phase rather than the default bubbling phase.
  • Additionally, addEventListener can be called with an options object as the third parameter instead of the useCapture boolean. This object can contain the following possible values:
    • capture: The same as the boolean argument option; true for capturing, false for bubbling.
    • once: If true, automatically removes the event listener after the event fires once.
    • passive: If true, indicates to the browser that event.preventDefault() will not be called. This is useful for the browser to optimize performance, particularly with mobile scrolling events such as touchstart and touchmove to indicate to the browser that scrolling will not be cancelled.
    • signal: An AbortSignal, usually coming from an AbortController. If the signal's abort() method is called, the event listener will be removed.
__

To remove an event listener, call element.removeEventListener(eventName, callback, useCapture) or element.removeEventListener(eventName, callback, optionsObj) with the exact same parameters as were used to create the event listener.

Event Propagation

The process by which an event travels through the DOM to call event listeners on nested elements. Event propagation consists of 3 phases:

  • Capturing: The event travels down from the root of the document to the event target.
  • Target: The event fires on the event target.
  • Bubbling: The event travels up from the event target to the root of the document.

At any point in the propagation process, an event listener can call event.stopPropagation(), which will stop the propagation process.

__

Event Delegation

The process of using a single event listener on a parent element to manually delegate events to children, rather than using event listeners on each child.

  • Event delegation takes advantage of event propagation. For example, after clicking on a button, that event will bubble up to the parent container.
  • In the event a container has many children that all have similar event listeners, event delegation can make substantial performance improvements by lowering the total number of active event listeners. The event.target property can then be used to determine which child was the source of the event.
__
__

Promises

An object used for asynchronous operations. These objects have a state of either pending, fulfilled or rejected.

  • A Promise is created with the Promise() constructor, which takes in a callback function, oftentimes called the executor. This callback function has two callback functions as parameters:
    • resolve(value): Fulfills the Promise and sets its value.
    • reject(error): Rejects the Promise and sets an error message.
  • The Promise object has three primary functions:
    • then(fulfilledFn rejectedFn): Calls fulfilledFn if the Promise is fulfilled and rejectedFn if it is rejected. Returns a new fulfilled Promise with the return value of the callback function.
    • catch(rejectedFn): Calls rejectedFn if the Promise is rejected. returns a new fulfilled Promise with the return value of the callback function.
    • finally(callback): Calls the callback function whenever the Promise is settled (fulfilled or rejected).
  • Since these functions all return a new Promise, they can be chained together, such as promise.then(doX).then(doY).catch(handleError).finally(doZ).

async function

A function declared using the async keyword, causing the function to implicitly return a Promise and allowing for usage of the await keyword.

Asynchronous functions are primarily an alternative syntax to chaining calls to Promise.then.

__

await

A keyword indicating that JavaScript should wait for a Promise to settle before continuing execution of the code. Traditionally this is only available in async functions, but it can also be used at the top level of modules.

__
__

Working with the Server

fetch

A JavaScript function for making network requests.

  • fetch(url) returns a pending Promise. Once the network request completes, the promise will either resolve or reject. Any response other than a network error will result in a resolved Promise. The url parameter can be either a string or a URL object.
__

This function can also take an options object as a second parameter. These are some of the more common options to use:

  • method: The request method as a string, such as 'GET' or 'POST'.
  • body: The body of the request, oftentimes used to pass FormData.
  • headers: Headers to be added to the network request, oftentimes by creating a Headers object, although a standard object can be used as well.
  • signal: An AbortSignal, usually coming from an AbortController. If the signal's abort() method is called, the request will be aborted.
__

When the request comes back from the server, the Promise returned by fetch will resolve to a Response object. This object has a variety of properties and methods for interacting with the network response. These are some of the most useful ones:

  • response.text(): Returns a Promise with a text representation of the response body.
  • response.json(): Returns a Promise with an object representation of the response body.
  • response.status: A number representation of the response status code. A successful request will be in the 200-299 range, most commonly 200.
  • response.ok: A boolean representation of the response status code. A successful request in the 200-299 range will be true, everything else evaluates to false.
  • response.headers: A Headers object containing the headers included with the response.

Timers and Intervals

setInterval

  • A JavaScript function for calling a function repeatedly over an interval.
  • For example, setInterval(myFunction, 1000); would call myFunction every second (however this could take longer if other code needs to finish running).
  • This function returns an ID, and the interval can be cancelled by calling clearInterval(intervalID);

setTimeout

  • A JavaScript function for delaying execution of a callback function.
  • For example, setTimeout(myFunction, 1000); would call myFunction after 1 second (however this could take longer if other code needs to finish running).
  • This function returns an ID, and the timeout can be cancelled by calling clearTimeout(timeoutID);

requestAnimationFrame

  • A JavaScript function for calling a callback function before the next browser repaint. These are oftentimes used for animations to update the animation every frame.
  • For example, requestAnimationFrame(myFunction); would call myFunction before the next repaint.
  • This function returns an ID, and the callback can be cancelled by calling cancelAnimationFrame(animationFrameID);

Closures

Closure

A function along with a saved reference to the lexical environment it was defined in. Simply put, this means functions have access to all of the variables in scope at the time of definition, even if the parent function has returned.

__

Lexical Environment

An internal data structure used for keeping track of identifiers (variable and function names) and their values. A lexical environment stores all of the locally available identifiers as well as a reference to the parent environment.

__

Lexical Scoping

The scoping system in JavaScript that ensures all code blocks have access to all identifiers in their parent environment. When an identifier is not defined locally, JavaScript will look to the parent environment for it. If it is still not found there, it will look in grandparent's environment and so on before looking in the global environment.

__
__

This

A JavaScript keyword for referencing the context in which the current code is running.

__

The value of this is determined at runtime. In the browser, it will follow these general rules:

  • At the top level of a file (the global context), this refers to the global object, which is the window.
  • In a standard function without strict mode, this refers to the global object, which is the window.
  • In a standard function in strict mode, this is undefined.
  • In an object method, this refers to that object.
  • In a constructor function, this refers to the object being constructed.
  • When using event listeners, the object being listened to will be bound to this, assuming a standard function was used. For example, element.addEventlistener('click', func) would bind element to this inside of func.
__

Arrow functions do not create their own this context, instead they retain the value of the enclosing context. Three functions for binding the value of this to functions:

  • func.bind(thisArg): Returns a new function with thisArg bound to this.
  • func.call(thisArg, x, y): Calls func(x, y) with thisArg bound to this.
  • func.apply(thisArg, [x, y]): Calls func(x, y) with thisArg bound to this.

Classes

Prototypal Inheritance

The inheritance model used in JavaScript. The key difference between prototypal inheritance and classical inheritance is that in prototypal inheritance objects only inherit from other objects, rather than using class blueprints.

__

Prototype Chain

The chain of inheritance created through object prototypes. When a property does not exist on an object, JavaScript will look to its prototype. If it doesn't exist on that object, it will look to its prototype and so on until the chain ends with a null prototype.

__

Internally, the prototype is stored on the [[Prototype]] property, but we cannot directly access this property. Instead, we have a few alternative ways to get and set prototypes:

  • obj.__proto__: Although being deprecated, this property was the original way to get and set the prototype of an object and is still useful for debugging.
  • Object.getPrototypeOf(obj): Returns the prototype object of obj.
  • Object.setPrototypeOf(obj, proto): Sets the prototype object of obj to proto.
  • Object.create(proto): Creates a new object with the prototype set to proto.
__

Function Constructor

A function intended to be used to construct an object using the new operator.

  • When the new operator is used, a new object is created automatically. The prototype of the new object is then set to the prototype property of the constructor function (remember functions are just objects). Finally, the constructor function is called with the new object bound to this.
  • By default the prototype property of the function will simply be an object with its constructor property set to the function itself. However, this can be changed, for example:
function Person(name) { this.name = name; } // This object will become the [[Prototype]] of // any objects resulting from a new Person() call Person.prototype = { constructor: Person, isHuman: true } const clement = new Person('Clement'); console.log(clement.isHuman); // true, comes from the prototype object.
__

Class

A JavaScript syntax to emulate that of classical inheritance, although for the most part it is syntactic sugar on top of function constructors (classes are actually just functions under the hood):

class Person { static isHuman = true; // public static field #age; // private instance field constructor(name, age) { this.name = name; // public instance field this.#age = age; } // instance method speak() { console.log('Hello this is ' + this.name); } // instance getter function get age() { return this.#age; } // instance setter function set age(value) { this.#age = value; } } const conner = new Person('Conner', 24); conner.speak(); // logs "Hello this Conner" console.log(conner.age); // calls getter function, logs 24 conner.age = 25; // Calls setter function console.log(conner.#age); // Error cannot access private field console.log(conner.name); // "Conner" console.log(conner.isHuman); // undefined console.log(Person.isHuman); // true

Classes can also extend other classes, which internally creates a prototype chain. In the class constructor, super can be used to call the parent constructor. super.method() can also be used in the class to call parent classes:

class Child extends Person { constructor(name, age, grade) { super(name, age); this.grade = grade; } }
__
__

Currying

The process of transforming a function to treat its parameters as a sequence of individual function calls that each take one parameter. For example, func(a, b, c) would become func(a)(b)(c).

__

Currying is achieved by creating functions that return other functions, taking advantage of closures:

function curriedSum(a) { return function(b) { return a + b; }; }

This could then be used to create partial versions of this function, for example an "add four" function:

const addFour = curriedSum(4); addFour(10); // 14
__
__

Generators

An iterable object created by using a generator function.

generator function is defined using function*. Then each yield results in another item being added to the iterable generator object.

The generator object has three methods:

  • next(value): Returns an object with the next value in the iterator and a done boolean. Optionally passes a value back into the generator function.
  • return(value): Adds a passed in argument to the iterable results and ends iteration.
  • throw(error): Throws an error, stopping code execution unless the error is caught.
function* genNumbers() { const x = yield 1; yield x + 2; yield 3; } const generatorObj = genNumbers(); console.log(generatorObj.next().value); // 1 console.log(generatorObj.next(3).value); // 5 console.log(generatorObj.return(7).value); // 7 console.log(generatorObj.next().value); // undefined
__
__

Modules

JavaScript code that runs in isolation, without polluting the global namespace.

__

Traditionally modules were implemented using immediately invoked function expressions, but in modern JavaScript there is a type="module" attribute that can be added to script tags. This attribute will have a few key effects:

  • Identifiers at the top level will be scoped to the file rather than globally.
  • The file will be in strict mode by default.
  • The await keyword can be used at the top level.
  • The script will be deferred by default.
__

Modules can then access each other by using the import and export keywords. For example:

// File 1: export const num = 10; // File 2: import { num } from 'file1.js';
__

Immediately Invoked Function Expression

IIFE, a function that is immediately called after its definition. This can be useful for a variety of purposes, most notably to create a function scope to isolate code with.

__

There are a few ways to define an IIFE, but the most common is using an anonymous or arrow function. This function is then wrapped in parentheses, which causes it to be treated as an expression. Finally, () is added to call the function. For example:

(function() { console.log('Wahoo!'); })();
__
__

The Event Loop

JavaScript Engine

A program used to execute JavaScript code.

__

These engines can differ a lot in implementation across browsers, but for the most part they contain two primary components:

  • Heap: Used for memory allocation to store objects. This can be thought of as a largely unstructured data store.
  • Call Stack: A stack data structure used to keep track of the currently executing function. Each function call pushes a stack frame onto the stack, which contains information about the function and its local variables. When a function ends, it is popped off the stack. When the stack is empty, there is no code currently running.
__

JavaScript Runtime Environment

The larger environment that JavaScript is executed in. In the browser, this environment provides access to a variety of web APIs. These APIs include the functions for timers, HTTP requests, DOM manipulation and much more.

__

Event Loop

The concurrency model within JavaScript. This is a constantly running loop within the browser, roughly following this algorithm:

  • Remove one task from the task queue.
  • Execute code until the call stack is empty.
  • Execute microtasks one at a time until the microtask queue is empty.
  • Render any changes to the DOM.
  • Go to step one.
__

Task Queue

A queue data structure for storing asynchronous callbacks to be added to the call stack. This queue is also known as the "Message Queue", "Callback Queue" or "Macrotask Queue".

  • Web APIs move callbacks into the task queue, where they wait for the call stack to be empty before executing.
__

Microtask Queue

A queue data structure, similar to the task queue, used for storing microtasks.

  • Microtasks are primarily used for callback functions passed to promise.then(), promise.catch() and promise.finally() as well as their async/await equivalents. Additionally, microtasks can be manually queued using the queueMicrotask() function.
  • Microtasks can be considered to have a higher priority than standard tasks, since the entire microtask queue must be empty before the browser will move on to a task.
__

Chunking

A process for preventing slow functions from clogging the call stack and thus making the entire page unresponsive. The core idea of chunking is to take large tasks and split them up into smaller ones.

  • In practice, chunking is usually achieved by using setTimeout after some number of iterations, forcing future chunks to move to the end of the task queue.
__
__

Web Workers

Web Worker

  • A browser API for running scripts in a separate thread from the main execution thread.
  • A worker object is created with the Worker(filePath) constructor function. The argument to this function is a path to another JavaScript file that will run in a separate thread.
  • Workers can send messages back and forth with the main thread via the postMessage(message) method and the onmessage event. For example:
// main JavaScript file const worker = new Worker('worker.js'); worker.postMessage('hello'); worker.addEventListener('message', (event) => { console.log(event.data); // 'world' }); // worker.js postMessage('world'); addEventListener('message', (event) => { console.log(event.data); // 'hello' });

In general, most workers are dedicated workers, meaning they can only communicate with the script that created them. However, a SharedWorker can also be created to share a worker with multiple tabs or iframes. That said, SharedWorkers still do not have widespread support across browsers.

__
__

Browser Storage

Cookies

The simplest form of browser storage, comprised of string key-value pairs. Cookies are most often set by the server to store information such as the logged in user account, however they can also be created via the document.cookie JavaScript property.

__

Local Storage

Part of the web storage API, a system for storing information in the browser without any expiration date. Values can be added to local storage with localStorage.setItem('key', 'value'), and the value can be retrieved with localStorage.getItem('key').

__

Session Storage

Part of the web storage API, a system for storing information in the browser that expires at the end of a session. Values can be added to session storage with sessionStorage.setItem('key', 'value'), and the value can be retrieved with sessionStorage.getItem('key').

__

IndexedDB

A browser API for storing complex objects. IndexedDB uses object stores, which are similar to tables in relational databases. Each object in the object store must then have a unique key used to identify it.

__
__

Data Structures with JavaScript

Map

A built-in JavaScript class for holding key-value pairs. While similar to standard objects, maps have a few key differences:

  • Map keys can be of any type, while object keys must be strings or symbols.
  • Maps maintain insertion order for iteration, while objects do not.
  • Maps cannot easily be converted to JSON, while objects can.
  • Objects oftentimes utilize the prototype chain for inheritance, while Maps cannot do this.
__

Set

A built-in JavaScript class for holding unique values of any type. Values are considered unique if they are different primitives or references to different objects (this means that two different objects with the same contents are considered unique from each other). Values in Sets are kept in insertion order for when the Set is iterated over.

__

WeakMap

A built-in JavaScript class for holding key-value pairs similar to the Map class. There are two primary differences between Map and WeakMap:

  • WeakMap can only have objects as keys, primitive values cannot be added as keys.
  • WeakMaps hold "weak" references to objects, meaning that they do not prevent the objects from being garbage collected. If no other references to an object exist, it can be garbage collected and automatically removed from the WeakMap. As a result, WeakMaps cannot be iterated over.
__

WeakSet

A built-in JavaScript class for holding unique values similar to the Set class. However, a WeakSet acts just like a WeakMap, meaning that the values must all be objects, and references to those objects are "weakly" held.

__
__

JavaScript Frameworks

JavaScript Library

A collection of pre-written JavaScript code, usually in the form of functions that can be called throughout other projects to simplify the development process.

__

JavaScript Framework

A collection of pre-written JavaScript code that provides some additional structure to a project. It is often said that frameworks are more "opinionated" than libraries, or that frameworks generally call your code as opposed to your code calling a library.

__
__

TypeScript

A superset of JavaScript adding static typing. The primary purpose of using TypeScript is to prevent bugs related to incorrect types and to improve the development workflow. Since browsers only understand standard JavaScript, TypeScript is compiled back into JavaScript.

__

Debugging Strategies

A set of tooling provided by the browser to simplify the process of debugging frontend code. For example, Chrome comes with the Chrome DevTools.

__
__

Writing Clean JavaScript

Autoformatter

A program that automatically formats code based on a set of rules, making it easy to maintain stylistic consistency. Prettier is the most common autoformatter, but there are other alternatives as well.

__

Style Guide

A document describing the preferred coding style for a project or organization used to promote clean and consistent code. Many style guides, such as the Google JavaScript Style Guide , are open source.