A Non-noob Javascript Glossary for 2024, with Examples
Intro
Much like the JavaScript language, the JavaScript environment can sometimes feel confusing and counter-intuitive.
This non-exhaustive glossary highlights and expands on key concepts related to JavaScript. Its reading should provide the most benefit for programmers who are at least somewhat comfortable using javascript but still get confused with some aspects of the language or its ecosystem. This is a glossary for non-noobs, which doesn't mean it's just for the pros; you can expect explanations about the prototype chain in here, but not what is the definition of an array. It is also focused on JavaScript itself, so no particular attention to frameworks.
At the bottom of the page you will find an index with terms in alphabetical order that you can use to navigate the glossary back-and-forth.
Below is the glossary in no particular order; I tried to order everything at least somewhat logically, having relevant and/or interdependent concepts grouped nearby.
Glossary
ECMAScript
ECMAScript is the standard upon which JavaScript is based. Ever since JavaScript's runtime was confined to browsers, ECMAScript served as the rule book that serves as a foundational blueprint for JavaScript implementation in different domains. It provides a set of agreed-upon functionalities behaviors that implementations should adhere to improve consistency and interoperability of JavaScript code on its environments.
ECMAScript2015/ES6
Sixth edition of the ECMAScript standard, held in 2015 and considered to be the second major definition of the language (first one was in the third edition, held in 1999).
Its main purpose was to address some of the perceived shortcomings of JavaScript.
ES6 introduced widely-used features, the main ones being the let
variable definition that addresses hoisting issues, the class
keyword to abstract the prototype chain in a syntax more familiar and intuitive to developers coming from other languages, arrow functions, an unified module definition and the (Promise)[#promise] objects which simplify asynchronous programming.
Babel
Babel is an open-source JavaScript transpiler that allows developers to write their code using the latest ECMAScript standards and features, which it then converts into backward-compatible versions of JavaScript for use in various environments. Babel ensures that developers can leverage the newest enhancements in language specifications while maintaining broad compatibility with older browsers and platforms. It offers a range of plugins, presets, and polyfills to streamline development workflows, optimize code, and extend functionality while adhering to the evolving ECMAScript standards.
WASM (WebAssembly)
WebAssembly (WASM) is a low-level, assembly-like language with a compact binary format that provides fast performance and runs on modern web browsers. It allows code written in languages like C, C++, and Rust to run on the web at near-native speed. WASM is designed to work alongside JavaScript, allowing both to work together.
Node.js
Node.js is an open-source, cross-platform runtime environment for executing JavaScript code outside of a browser.
Even though it operates on a single thread using non-blocking Input/Output calls, it has an event-driven architecture and supports concurrency via events and callbacks, enabling it to handle numerous connections with high throughput and making viable the use of JavaScript in, among others, server-side applications.
It is important to mention that node.js wasn't the only or the first attempt to establish a JavaScript runtime outside of browsers. However, due to the great skill and effort of the programmers involved in creating node and JavaScript's growing maturity as a technology (node's first stable release cycle was in 2015, shortly after the definition of ES6 standards), it has arguably been the most successful.
Event-Driven Architecture (EDA)
Software pattern in which flow of the program is determined by ad hoc actions such as user actions, sensor outputs and messages from external programs.
In an EDA, there are typically event producers (which generate events) and event consumers (which react to events). Events are processed asynchronously, meaning the app can continue with other tasks and respond to other events while waiting for a response or completion of a task associated with a past event. This architecture is often associated with scalability strategies for environments which handle multiple concurrent actions and in systems that need to react to changes in real-time.
Other than node.js, examples of EDA systems are user interfaces (handling clicks, keyboard input and etc and triggering specific callbacks for actions), microservices (each communicating to and reacting to each other through events) and Internet of Things devices (for example, devices that handle sensor data changes or specific signals from within or outside the device).
In a nutshell, Event-Driven Architecture is a design paradigm centered around producing, detecting and reacting to events.
V8 Engine
The V8 engine is Google's open source high-performance JavaScript and WebAssembly engine, written in C++. It is used as a JavaScript runtime Chromium-based browsers (including Google Chrome itself) and node.js, among others. V8 compiles JavaScript directly to native machine code before executing it, optimizing code for performance; this process is known as just-in-time (JIT) compilation.
Other notable engines include SpiderMonkey, used in Mozilla, and JavaScriptCore, used in Safari. Mobile apps built in JavaScript often have their own engines, such as Hermes, which powers ReactNative apps.
Call Stack
The call stack is a mechanism for an interpreter (like the JavaScript engine) to keep track of its place in a script that calls multiple functions. When a function is called, the interpreter adds it to the call stack and then starts carrying out the function. Any functions that are called by that function are added to the call stack further up, and run where their calls are reached.
Just-In-Time Compilation
Just-In-Time (JIT) Compilation is a method of executing computer code that involves compilation during the execution of a program – at run time – rather than prior to execution. This means that the JavaScript code is compiled into machine code and executed immediately rather than being interpreted line-by-line, which improves the performance.
Object Oriented Programming Paradigm
Object-Oriented Programming (OOP) is a programming paradigm based on the concept of "objects," which can contain data and code: data in the form of fields (often known as attributes or properties), and code in the form of procedures (often known as methods). OOP models real-world entities as objects that have a state (data) and behavior (methods). It emphasizes the bundling of data with the methods that operate on that data and typically uses classes for defining and creating objects (i.e. a class is the general, abstract case, an object is a specific individual manifestation of the class).
Remember that JavaScript is a multi-paradigm language, so you'll often see both Object Oriented and Functional Programming JS code in the wild.
Class
A class in JavaScript is a type of function, but instead of using the keyword function
to initiate it, we use the keyword class
; this is an example of syntatic sugar added on top of JavaScript (from the ECMAScript 2015/ES6 standard onwards) to abstract certain JavaScript properties generally regarded as poorly thought out in retrospect, which means that you can forget about this fact most of the time.
In OOP terms, a class is a blueprint for creating objects (instances). A class encapsulates data for the object and methods to manipulate that data. Classes support inheritance, allowing you to create a new class that inherits properties and methods from an existing class.
Object
In JavaScript, an object is a standalone entity, with properties and type; it is usually the specific manifestation of a generalized class, though JavaScript also has the concept of object literals.
Think of it like a 'thing' with characteristics that describe or identify it. An object can be a variable container, where properties are variables and methods are functions that can access and modify these properties. Objects are created using curly braces {} with an optional list of properties.
Functional Programming Paradigm
Functional Programming (FP) is a programming paradigm where programs are constructed by applying and composing functions. It treats computation as the evaluation of functions and avoids changing state and mutable data, instead focusing on a series of input/output trees. FP emphasizes the use of pure/idempotent functions (i.e. functions that do not cause side effects, meaning that for the same input it will always produce the same output) and higher-order functions (functions that take other functions as their arguments).
'map' Functions
In JavaScript, map is a method of the Array prototype. It allows you to transform elements in an array. map takes a function as an argument and applies this function to each element in the array, then returns a new array with the transformed elements without mutating the original array. Mapping functions are a cornerstone of functional programming.
const numbers = [1, 2, 3, 4];
const squares = numbers.map(number => number * number);
console.log(numbers); // Output: [1, 2, 3, 4]
console.log(squares); // Output: [1, 4, 9, 16]
'reduce' Functions
A reducer function in JavaScript is used with the reduce method of the Array prototype. It processes each element of an array to produce a single value. It takes a callback function as an argument, which is called on each element of the array in sequence. This callback function takes an accumulator (which accumulates the callback's return values) and the current element being processed.
const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
console.log(sum); // Output: 10
undefined
, null
In JavaScript, undefined
and null
are both primitives, but they have different uses. undefined
is a variable that has been declared but not assigned a value (a reference error should be thrown when calling an unassigned variable). null
is an assignment value that represents a deliberate non-value and is indicative of a variable with no value.
let uninitializedVariable; // undefined: variable declared but not initialized
console.log(uninitializedVariable); // Output: undefined
let nullVariable = null; // null: explicitly set to 'no value'
console.log(nullVariable); // Output: null
Global Scope
Global scope refers to variables or functions that are accessible from any part of the JavaScript code. Variables defined outside any function, block, or module have global scope.
let globalVar = "I'm global"; // A global variable
function checkGlobalScope() {
console.log(globalVar); // Accessing the global variable
}
checkGlobalScope(); // Output: "I'm global"
Hoisting
Hoisting is JavaScript's default behavior of moving all declarations to the top of the current scope (either the global or a block scope). This means that you can use variables and functions before actually declaring them. This is also the reason why you should prefer declaring variables with let
over var
, as a hoisted let
will return a reference error if accessed before its declaration and a hoisted var
will return undefined
, potentially leading to hard to debug errors.
hoisted(); // Outputs: "Hello, World!"
function hoisted() {
console.log("Hello, World!");
}
'use strict' Directive
The 'use strict'
directive in JavaScript enables strict mode, which is basically a restricted version of JavaScript that will throw errors once it detects common mistakes that would otherwise silently fail and lead to hard to debug errors.
Among its restrictions, some notable ones are forbidding value assignment to undeclared variables, disabling redefinition of primitive types (like underfined
or NaN
), preventing duplicate names in object literals and disallowing the declaration of variables and functions inside eval
statements.
// Without strict mode
function foo() {
x = 10; // Accidentally global
}
// With strict mode
'use strict';
function foo() {
x = 10; // ReferenceError: x is not defined
}
'use strict';
undefined = 5; // TypeError
'use strict';
var obj = { p: 1, p: 2 }; // SyntaxError
'use strict';
eval('var x = 2');
alert(x); // ReferenceError: x is not defined
Function Expression
A function expression is a way to define a function in JavaScript by assigning a function directly to a variable. Unlike function declarations, function expressions are not hoisted and cannot be used before they are defined.
greet(); // reference error!
const greet = function() {
console.log("Hello, World!");
};
greet(); // Output: Hello, World!
Higher Order Functions
Higher order functions are functions that operate on other functions, either by taking them as arguments or by returning them. In JavaScript, functions are first-class objects, so they can be passed and returned just like any other value.
// A simple function
const double = x => x * 2;
// A higher-order function that takes a function and a value
const operate = (hoFunc, val) => {
return hoFunc(val);
};
console.log(operate(double, 5)); // Output: 10
Closures
Closures are a feature in JavaScript where an inner function has access to the outer (enclosing) function’s variables — a scope chain. The closure has three scope chains: it has access to its own scope, the outer function’s variables, and the global variables.
function outerFunction(outerVariable) {
return function innerFunction(innerVariable) {
// Closure: innerFunction has access to outerVariable
console.log(outerVariable, innerVariable);
};
}
const newFunction = outerFunction("outer");
newFunction("inner"); // Output: "outer inner"
Heap
The heap is a large region of memory used for dynamic memory allocation. In JavaScript, objects are allocated in a heap which is just a name to denote a large, mostly unstructured region of memory.
Pass by Value
"Pass by value" means that a copy of the original parameter value is passed to a narrower scope. Changes made in the other scope to the parameter have no impact in the original value.
All primitive types in JavaScript are passed by value. This includes:
- String
- Number
- Boolean
undefined
null
- Symbol (introduced in ES6)
- BigInt (introduced in ES2020)
let originalValue = 10;
function changeValue(value) {
value = 20; // Changing the value inside the function
}
changeValue(originalValue);
console.log(originalValue); // Output: 10 (original value remains unchanged)
Pass by Reference
"Pass by reference" means that instead of passing a copy of the actual value as a parameter to a different scope, a reference to the original data is passed. Therefore, changes made to the parameter produce side-effects in the original object.
In JavaScript, non-primitive types are passed by reference. This includes object, arrays and functions.
let originalObject = { value: 10 };
function changeObject(obj) {
obj.value = 20; // Changing the object's property
}
changeObject(originalObject);
console.log(originalObject.value); // Output: 20 (object is modified)
Property
A property in JavaScript is a characteristic of an object, often describing attributes associated with a data structure. Properties can be values or functions (methods). Objects in JavaScript are collections of key-value pairs, with the keys being the properties.
const objectWithProperty = {
myProperty: "value" // Object with a property
};
console.log(objectWithProperty.myProperty); // Output: "value"
'this' Keyword
The JavaScript this
keyword refers to the object it belongs to. It has different values depending on where it is used: In a method, this
refers to the owner object. Alone, this
refers to the global object. In a function, this
refers to the global object. In an event, this
refers to the element that received the event.
const object = {
property: "value",
method: function() {
console.log(this.property); // 'this' refers to the object
}
};
object.method(); // Output: "value"
'window' and 'global' Objects
In the context of browsers, the global object is window
, meaning all global JavaScript objects, functions, and variables automatically become members of the window object. Global variables are properties and global functions are methods of the window
object. This is not available outside of browser environments and is often used as a flag in node.js projects to flag wheter the current code is running in a browser or not.
The global
object would be the closest analogous to window
, but for a node.js environment. You might use global
to define variables or functions that you want available accross all modules in your application, but it will lack browser-only features like methods to manipulate the DOM
and properties of the current URL.
// In a browser environment
console.log(window.location.href); // Accesses the global 'window' object
// In Node.js
console.log(global.process.version); // Accesses the global 'global' object
bind
The bind()
method allows you to set the this
value for a function and returns a new function with the this
value set to the value passed, along with any provided arguments leading the arguments list. bind()
can also be used to create a new function with pre-filled arguments; this is known as partial application of a function.
// originalFunction: The function to be bound.
// thisArg: The value to be passed as `this` to the target function when the bound function is called.
// arg1, arg2, <...> : Arguments to be pre-filled in the bound function
const boundFunction = originalFunction.bind(thisArg, arg1, arg2, ...);
/* example */
function greet(greeting, punctuation) {
console.log(greeting + ", " + this.name + punctuation);
}
const person = {
name: "Alice"
};
const greetAlice = greet.bind(person, "Hello");
greetAlice("!"); // Output: "Hello, Alice!"
'arguments' Object
The arguments object is an array-like object accessible within functions in JavaScript, and contains the values of the arguments passed to that function. This object is useful for functions that need to handle an indeterminate number of arguments, or when you want to work with all arguments passed to the function without explicitly defining them as parameters.
Note that arguments
is an 'array-like' object and is not an array: it has a length
property and indexed elements, but it lacks array methods like forEach
, map
or reduce
.
function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
console.log(sum(1, 2, 3, 4)); // Output: 10
Destructuring Objects
One fundamental utility of objects is to structure data, i.e. to have aggregated key-value pairs (or ordered, numbered elements in the case of arrays) instead of a bunch of variables roaming around. Destructuring is the opposite process: unpacking structured key-value pairs from objects into free variable-name/variable-value ones. Some of its notable uses include extracting a subset of properties of an object and importing specific functionality from modules.
General use:
const person = {
name: 'John Doe',
age: 30,
profession: 'Developer'
};
// Destructuring the object into individual variables
const { name, age, profession } = person;
console.log(name); // Output: John Doe
console.log(age); // Output: 30
console.log(profession); // Output: Developer
Using object destructuring to import a subset of functionality from a large module:
import { useState } from 'react'; // imports only the useState hook instead of the whole react package
Spread Operator
The spread operator (...) allows an iterable such as an array or string to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected. It can also be used to spread object properties into a new object, like when combining objects. One of the common use-cases for the spread operator is when you need to transfer the key-value pairs of an object to tag-value pairs in a React or Svelte component.
Spread operator with arrays:
const numbers = [1, 2, 3];
const moreNumbers = [4, 5, 6];
// Combining arrays using the spread operator
const combined = [...numbers, ...moreNumbers];
console.log(combined); // Output: [1, 2, 3, 4, 5, 6]
Spread operator with objects:
const personDetails = {
name: 'John Doe',
age: 30
};
const contactDetails = {
email: 'john@example.com',
phone: '1234567890'
};
// Combining objects
const fullProfile = { ...personDetails, ...contactDetails };
console.log(fullProfile);
/* Output:
{
name: 'John Doe',
age: 30,
email: 'john@example.com',
phone: '1234567890'
}
*/
Spread operator in React:
function UserProfile({ name, age, location }) {
return (
<div>
<h1>{name}</h1>
<p>Age: {age}</p>
<p>Location: {location}</p>
</div>
);
}
const userInfo = {
name: 'Alice',
age: 30,
location: 'Wonderland'
};
function App() {
return (
<div>
{/* Using the spread operator to pass props */}
<UserProfile {...userInfo} />
</div>
);
}
Arrow Function
Arrow functions are a shorter syntax for writing function expressions. They do not have their own this
, do not have prototypes, cannot be used for constructors, and don't have an arguments
object. Arrow functions are best suited for non-method functions (meaning, functions that are not a property of an object).
const arrowFunction = () => {
console.log("This is an arrow function");
};
arrowFunction(); // Output: "This is an arrow function"
Anonymous Functions
Anonymous functions in JavaScript are functions that are defined without a name. They are often used as values and can be assigned to variables or passed as arguments to other functions. They are useful for creating quick, throwaway functions on the fly, and are often used as callback arguments.
setTimeout(function() {
console.log("Anonymous function executed");
}, 1000); // An anonymous function as a callback
Object Literal
An object literal is a comma-separated list of name-value pairs wrapped in curly braces. Object literals encapsulate data, enclosing it in a tidy package. This minimizes the use of global variables which can cause problems when combining code. They are similar to what in other languages might be called 'dictionaries' or 'hashes'.
const objectLiteral = {
property1: "value1",
property2: "value2"
};
console.log(objectLiteral.property1); // Output: "value1"
Object Constructor
An object constructor in JavaScript is a function that defines a type of object. It can be used with the new
keyword to create new objects of that type. The constructor is a template for creating similar objects with the same properties and methods.
function Car(make, model) {
this.make = make;
this.model = model;
}
const myCar = new Car("Toyota", "Corolla");
console.log(myCar.make); // Output: "Toyota"
Prototype Chain
The prototype chain is a feature in JavaScript that is used to build new types of objects based on existing ones. It is a mechanism for inheriting properties and methods from other objects.
When a property is accessed from an object, JavaScript will traverse up the prototype chain until it finds the property or reaches the end of the chain. The end of the chain, that is, the very first inheritor, is the null
prototype.
Every object can have exactly one prototype object, which means that multiple inheritance is not supported by either JavaScript or TypeScript.
Prototype constructors are not really used in everyday JavaScript development, however, it is the basis for the class
keyword and essential knowledge if you want to get deeper into the language.
const animal = {
dna: 'ATCG',
};
const cat = {
saying: 'meow',
}
Object.setPrototypeOf(cat, animal);
Object.getPrototypeOf(cat) === animal; // true
Object.getPrototypeOf(animal) === Object.prototype; // true
Object.getPrototypeOf(Object.prototype) === null; // true
Inheritance
Inheritance in JavaScript is a mechanism where one object can inherit the properties and methods of another. This is often used to create a hierarchy of types and share code. JavaScript implements inheritance through the prototype chain.
// Class-based inheritance
class Animal {
speak() {
return "I'm an animal";
}
}
class Dog extends Animal {
speak() {
return "Woof! Woof!";
}
}
const myDog = new Dog();
console.log(myDog.speak()); // Output: "Woof! Woof!"
// Prototype-based inheritance
function Animal() {}
Animal.prototype.speak = function() {
return "I'm an animal";
};
function Dog() {}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.speak = function() {
return "Woof! Woof!";
};
const myDog2 = new Dog();
console.log(myDog2.speak()); // Output: "Woof! Woof!"
Multiple Inheritance
Multiple inheritance is a feature in some object-oriented programming languages where a class can inherit characteristics and behaviors from more than one parent class. This concept allows a derived class to combine and exhibit the properties, methods, and behaviors of multiple base classes, potentially leading to greater functionality and code reuse.
However, multiple inheritance can also introduce complexity and hard to debug errors, notably with the "diamond problem" or "Deadly Diamond of Death", an ambiguity that arises when two classes B and C inherit from A, and class D inherits from both B and C, i.e. when a class inherits the same property from multiple different parent classes.
Some OOP languages like Java, C# and TypeScript don't support multiple inheritance, but implement strategies to achieve similar polymorphism, like for example interfaces.
Polymorphism
'Polymorphism' means 'multiple forms', and class polymorphism allows objects of different classes to be treated as objects of a common super class. It enables a single interface to represent different underlying types, allowing code to be more reusable.
For example, let's think of a website that has a 'Media' object; 'Media' can be browsed, receive comments and etc. 'Song', 'Book' and 'Movie' are child classes of 'Media', each of them will be played or rendered in the browser according to its own specific implementation but all of them will be able to be browsed, receive comments and etc; 'Media' here is the polymorphic clas while 'Song', 'Book' and 'Movie' are the specific ones.
Polymorphism for a class can be achieved in different ways. Multiple inheritance is one of these ways, but let's treat it as a non-option for the JavaScript world and focus instead on three other strategies: interfaces, composition and mixins.
Interfaces
An interface is basically a contract for classes. It specifies a set of methods and properties that a class must implement, without providing the implementation details. Interfaces allow different classes to be treated uniformaly based on a shared interface, making the code more flexible and extensible. See below an example in TypeScript, and note that JavaScript does not support interfaces natively:
/* typescript code */
// Interface for Address
interface Address {
street: string;
city: string;
zipCode: number;
}
// Interface for User
interface User {
name: string;
age: number;
address: Address; // Embedding the Address interface
greet(): string;
}
// Implementation
const user: User = {
name: "Alice",
age: 30,
address: {
street: "123 Maple St",
city: "Anytown",
zipCode: 12345
},
greet() {
return `Hello, my name is ${this.name} and I live at ${this.address.street}, ${this.address.city}.`;
}
};
Composition
Composition involves creating objects made of other objects rather than inheriting from parent objects. Composition is based on a "has-a" relationship rather than the "is-a" relationship of classical inheritance. For instance, instead of saying "a car is a vehicle," we say "a car has an engine."
Composition provides greater flexibility and easier maintainability. Changes in one part of the system are less likely to impact others, and behavior can be added or removed at runtime.
function createBird(name) {
return {
name,
fly() {
console.log(`${this.name} is flying.`);
}
};
}
function createSwimmer(name) {
return {
name,
swim() {
console.log(`${this.name} is swimming.`);
}
};
}
const duck = Object.assign({}, createBird('Ducky'), createSwimmer('Ducky'));
duck.fly(); // Ducky is flying.
duck.swim(); // Ducky is swimming.
Mixins and compositions are different: mixins are closer to inheritance where functionalities are added directly to the prototype chain, while composition is about aggregating functionalities by having instances of other objects. For example, a car's replaceable-whell system would be a composition, while its ability to ride would be a mixin.
Mixins
A mixin is a function that accepts a target object or class and adds functionality to it. Mixins provide a means to reuse a set of functionalities across multiple classes or objects.
const flying = {
fly() {
console.log(`${this.name} is flying.`);
}
};
const swimming = {
swim() {
console.log(`${this.name} is swimming.`);
}
};
function Duck(name) {
this.name = name;
}
Object.assign(Duck.prototype, flying, swimming);
const duck = new Duck('Ducky');
duck.fly(); // Ducky is flying.
duck.swim(); // Ducky is swimming.
Mixins and compositions are different: mixins are closer to inheritance where functionalities are added directly to the prototype chain, while composition is about aggregating functionalities by having instances of other objects. For example, a car's replaceable-whell system would be a composition, while its ability to ride would be a mixin.
Instance Method
An instance method is a function defined within a class that operates on the instances of that class, meaning it can be called on individual objects created from the class and usually accesses or modifies the data of those specific instances.
class MyClass {
instanceMethod() {
return "This is an instance method";
}
}
const myInstance = new MyClass();
console.log(myInstance.instanceMethod()); // Output: "This is an instance method"
Static Method
Static methods are defined on the class itself, and not on the prototype. That means they are called on the class, not on instances of the class. They are typically used for utility functions that don't require a specific object context.
class MyClass {
static staticMethod() {
return "This is a static method";
}
}
console.log(MyClass.staticMethod()); // Output: "This is a static method"
WeakMap & WeakSet
WeakMap and WeakSet are collections in JavaScript that only hold "weak" references to their elements. This means that if there are no other references to the stored object or value, they can be garbage collected. This is unlike regular Maps and Sets which hold strong references to their contents.
// Regular Map
let regularMap = new Map();
let objKey = { id: 1 };
regularMap.set(objKey, "Regular Map Value");
console.log(regularMap.get(objKey)); // Output: "Regular Map Value"
// WeakMap
let weakMap = new WeakMap();
let objWeakKey = { id: 2 };
weakMap.set(objWeakKey, "WeakMap Value");
console.log(weakMap.get(objWeakKey)); // Output: "WeakMap Value"
// WeakMap keys are weakly held, allowing for garbage collection if there's no other reference to the key object.
// Regular Set
let regularSet = new Set();
regularSet.add(objKey);
console.log(regularSet.has(objKey)); // Output: true
// WeakSet
let weakSet = new WeakSet();
weakSet.add(objWeakKey);
console.log(weakSet.has(objWeakKey)); // Output: true
// WeakSet elements are weakly held, similar to WeakMap.
Event Loop
The event loop is an architectural pattern used in JavaScript that continually checks the message queue for ad hoc messages (an event loop). When it finds one, it removes it from the queue and executes its corresponding callback. This mechanism allows JavaScript to perform non-blocking operations, despite being single-threaded.
Synchronous
Synchronous operations in JavaScript are those that block other operations from running until they complete. Synchronous code is executed in sequence – each statement waits for the previous statement to finish before executing.
Asynchronous
Asynchronous operations in JavaScript allow the program to be executed immediately where the synchronous operation will block further execution of the remaining code until it completes. This is essential for operations that rely on external operations or timers.
Thread Pool
A thread pool is a collection of threads that can be used to perform a number of tasks in the background. In JavaScript, particularly in environments like Node.js, a thread pool can handle tasks like file I/O, networking, or any other task that is I/O-bound asynchronously.
Single Threaded
JavaScript is traditionally single-threaded, meaning it processes one command at a time in a single sequence. This is important for understanding how JavaScript handles asynchronous operations, event handling, and concurrency.
Callback
A callback is a function passed into another function as an argument to be executed later. Callbacks are used to continue code execution after an asynchronous operation has completed.
function processData(data, callback) {
// Process the data (simulated with a timeout)
setTimeout(() => {
callback('Processed: ' + data);
}, 1000);
}
processData('Hello', result => {
console.log(result); // Output after 1 second: "Processed: Hello"
});
// A callback function is passed and executed after data processing.
Promise
A promise in JavaScript represents the eventual completion (or failure) of an asynchronous operation and its resulting value. Promises provide a cleaner, more robust way of handling asynchronous operations compared to traditional callback functions.
let promise = new Promise((resolve, reject) => {
// Asynchronous operation
let success = true; // Simulate success or failure
if (success) {
resolve('Operation succeeded');
} else {
reject('Operation failed');
}
});
// promise represents an asynchronous operation that will eventually complete.
Resolve
In the context of Promises, resolve
is a method that, when called, changes the status of the promise from "pending" to "fulfilled" and returns a value with which the promise was resolved.
let resolvedPromise = new Promise(resolve => {
resolve('Resolved value');
});
resolvedPromise.then(value => {
console.log(value); // Output: "Resolved value"
});
// 'resolve' is used to successfully complete a promise.
Reject
Reject is a method associated with promises. When reject is called, the promise's status changes from "pending" to "rejected," indicating that the operation failed and typically returns a reason or error as to why the promise was rejected.
let rejectedPromise = new Promise((resolve, reject) => {
reject('Rejected value');
});
rejectedPromise.catch(reason => {
console.log(reason); // Output: "Rejected value"
});
// 'reject' is used to fail a promise.
Then/Catch
In promises, then
is used to schedule a callback to be executed when the promise is successfully resolved. catch
is used to schedule a callback to be executed when the promise is rejected. They are methods for handling the fulfillment and rejection of a promise, respectively.
let asyncOperation = new Promise((resolve, reject) => {
let success = true;
if (success) {
resolve('Success');
} else {
reject('Error');
}
});
asyncOperation.then(result => {
console.log(result); // Runs if promise resolved: "Success"
}).catch(error => {
console.log(error); // Runs if promise rejected
});
// 'then' and 'catch' handle resolved and rejected promises, respectively.
Async/Await
async/await
is syntactic sugar built on top of promises in JavaScript that allows you to write asynchronous code that looks and behaves a bit more like synchronous code, halting the execution of the programing until the promise of the asynchronous statement marked with await
is solved or rejected. Note that the function must be declared as an async
function in order to support await
statements.
async function fetchData() {
try {
let response = await fetch('https://api.example.com/data');
let data = await response.json();
console.log(data);
} catch (error) {
console.error('Error fetching data:', error);
}
}
// 'async' function returns a promise, and 'await' waits for the promise to settle.
ES Modules
ES Modules are a module system in JavaScript that allows you to modularize your code into separate files. This system provides a standard way to import and export values between files, making code organization and reuse more straightforward.
Default & Named Import/Export
In ES Modules, a default export is a single value or entity that is exported from the module. Named exports allow multiple named values to be exported from the module. Import statements can correspondingly import these default or named exports into the current file.
// In a module file (module.js)
export default function defaultFunction() { /* ... */ }
export function namedFunction() { /* ... */ }
export const namedConstant = 'value';
// In another file
import defaultFunction, { namedFunction, namedConstant } from './module.js';
// Default imports are imported without braces, named imports with braces.
package.json
package.json
is a file used in Node.js applications. It holds metadata relevant to the project and it is used for managing the project's dependencies, scripts, version and a whole lot more.
DOM (Document Object Model)
The DOM is a programming interface for HTML and XML documents. It represents the page so that programs can change the document structure, style, and content. The DOM represents the document as nodes and objects; that way, programming languages can interact with the page.
Document
In the context of the DOM, the document object is the root node of the HTML document and the entry point to the content of the page. It represents the whole web page and can be used to access and manipulate the content, structure, and styles of the web page.
Components
Components are reusable, encapsulated elements that can be used to build dynamic and interactive web applications. They are a fundamental concept in many JavaScript frameworks and libraries, helping developers manage and reuse code efficiently.
Data Binding
Data binding is a technique for synchronizing data between a source (like a JavaScript object) and a destination (like HTML UI elements). It simplifies how you display and interact with data in applications, particularly in frameworks like Angular, Vue, or React.
Module Bundling
Module bundling is the process of taking modules written as separate files and combining them into a single file. This single file can then be loaded onto a web page. Tools like Webpack and Rollup are commonly used for module bundling.
Network Waterfall
Network waterfall refers to the sequence of network requests and how they are processed by the browser. It's a visualization found in browser's development tools that shows the order, timing, and dependencies of network requests.
Dynamic Imports
Dynamic imports in JavaScript are a way to load modules asynchronously and on-demand. This can improve performance by splitting code into smaller chunks and loading them only when needed, rather than loading all scripts at the start.
async function loadModule() {
let module = await import('./module.js');
module.defaultFunction();
module.namedFunction();
}
// Dynamic import() returns a promise for the module, allowing you to import modules dynamically.
Typescript
Typescript is an open-source language that transpiles into JavaScript. It's meant to be "strictly a superset" (meaning that all valid JavaScript code should be valid TypeScript code) and its reason for existence is to address perceived JavaScript pitfalls such as a hacky OOP implementation and unintuitive type system in javascript which can lead to unexpected behavior and hard to debug errors. TypeScript, among others, adds strict types to JavaScript, has a more traditional syntax for OOP and offers strict null checking to avoid unintentional setting of null
or undefined
.
JSDoc
JSDoc is a popular documentation syntax for JavaScript, used to annotate and describe the structure of JavaScript code. It's essentially a way to add comments to the code that can be easily understood and parsed by documentation generators to produce nicely formatted documentation pages. Some people claim it's a good lightweight alternative to TypeScript for libraries and smaller projects.
/**
* Represents a book.
* @constructor
* @param {string} title - The title of the book.
* @param {string} author - The author of the book.
*/
function Book(title, author) {
this.title = title;
this.author = author;
}
Test Driven Development
Test-Driven Development (or TDD) is a software development methodology that involves writing tests first and implementing features second. It is particularly effective when building on top of large codebases, once the product is somewhat established and the development directions are more obvious and less flexible.
Tests have three main categories: Unit Tests, Functional/Integration Tests and End-to-End(E2E) Tests.
Unit Tests
Unit tests are the smallest and most foundational type of software testing. They focus on testing individual components or functions in isolation from the rest of the application. The goal is to ensure that each component functions correctly as a standalone unit. Testing a function that takes an input, makes calculations and produces an output is an example of unit testing.
They are often the quickest to execute and won't involve external modules or systems (like databases or APIs).
Popular libraries for unit testing include Mocha and Jest, with Vitest recently gaining ground.
Functional/Integration Tests
Functional and integration tests are mid-level tests that focus on the interaction between different parts of the application. Integration tests check how different modules work together, while functional tests focus on the business requirements of the application. Testing the interaction of an user auth service with the database is an example of functional/integration test.
Their main reason of existence is to ensure different parts of the application work together as expected. It can involve testing the interaction of two or more modules, APIs and database interactions.
Mocha, Jest and Vitest can also be used for integration tests. Other famous libraries include Cypress (more known for E2E tests, can be used for integration tests especially in web apps) and Supertest, which is mostly known for testing HTTP interfaces.
End-to-End (E2E) Tests
E2E tests simulate real user scenarios from start to finish. They are high-level tests that evaluate the entire application's flow and are typically executed in an environment that mimics the production environment as much as possible.
These are the most complex and time-consuming tests and usually should only be executed once all other tests have passed. Testing the entire process of an user signing up, logging in, interacting with the app and then logging out is an example of E2E tests.
Cypress, PhantomJS (deprecated in 2018), Playwright (the de-facto successor of PhantomJS) and Selenium are examples of libraries often used in E2E tests.
Playwright and Selenium have notable differences:
- Playwright interacts with browser engines and works as a headless browser and has an uniform API even when representing different browsers.
- Selenium uses the WebDriver protocol to communicate with different browsers and will often involve the browser itself. While Playwright is considered lighter and faster than Selenium, Selenium is still considered more adequate to test apps that should focus on older browser support, and is one of the de-facto tools to automate browser actions programmatically.
Glossary Index
- Anonymous Functions
- 'arguments' Object
- Arrow Function
- Asynchronous
- Babel
- Bind
- Callback
- Class
- Closures
- Components
- Composition
- Data Binding
- Default & Named Import/Export
- Destructuring Objects
- DOM (Document Object Model)
- Document
- Dynamic Imports
- ECMAScript
- ECMAScript2015/ES6
- End-to-End (E2E) Tests
- ES Modules
- Event Loop
- Event-Driven Architecture (EDA)
- Function Expression
- Functional Programming Paradigm
- Functional/Integration Tests
- Global Scope
- Heap
- Higher Order Functions
- Hoisting
- Inheritance
- Instance Method
- Interfaces
- JSDoc
- Just-In-Time Compilation
- 'map' Functions
- Mixins
- Module Bundling
- Multiple Inheritance
- Network Waterfall
- Node.js
- null, undefined
- Object
- Object Constructor
- Object Literal
- Object Oriented Programming Paradigm
- Package.json
- Pass by Reference
- Pass by Value
- Polymorphism
- Promise
- Prototype Chain
- 'reduce' Functions
- Reject
- Resolve
- Single Threaded
- Spread Operator
- Static Method
- Synchronous
- Then/Catch
- Thread Pool
- TypeScript
- Unit Tests
- 'use strict' Directive
- V8 Engine
- WASM (WebAssembly)
- WeakMap & WeakSet
- Test Driven Development
- this Keyword
- window and global Objects
Top comments (0)