JavaScript Concepts That Every Web Developer Should Know

Call Stack

The call stack serves as a data structure utilized by the JavaScript interpreter to monitor the functions that are currently executing within a program. Functions in JavaScript are executed in the sequence in which they are invoked. As a Last In, First Out (LIFO) stack, the most recently added function to the call stack will be the first one to be executed.

The call stack constitutes a component of an execution context as outlined by the ECMAScript Specification. Whenever a function is called, it generates a new execution context that is pushed onto the top of the stack. Once the function has finished executing, the associated context is popped off the stack and the execution process continues. This mechanism is vital for synchronous code execution, as it ensures that each function call must be completed before the subsequent function can commence.

Primitive Types

According to the ECMAScript specification, the JavaScript language encompasses six primitive data types: string, number, bigint, boolean, undefined, and symbol. These types are immutable, meaning their values cannot be altered. Additionally, null is classified as a distinct primitive type that represents a null value, indicating a deliberate lack of any object value.

Primitive types are directly assigned to variables, and when you execute operations on these primitive types, you are interacting with the actual values themselves. Primitives lack properties and methods, prompting JavaScript to automatically encapsulate primitive values within a wrapper object.

Value Types and Reference Types

According to ECMAScript, value types are directly held in the memory location that the variable points to. This includes types such as number, string, boolean, undefined, bigint, symbol, and null. When a value type is assigned to a variable, the actual value is stored in that variable's location.

Implicit, Explicit, Nominal, Structuring and Duck Typing

According to ECMAScript specification ECMA-262, JavaScript is a dynamically typed language because types are associated with values rather than variables and type checking is done at run time. JavaScript has a few different strategies for dealing with types:

  • Implicit Typing (or Type Coercion): This is when JavaScript itself decides to convert one data type to another if it is needed. When performing operations, the language may convert one data type to another e.g. string to number in case of JavaScript. This can make some code easier, but it can also produce unexpected results if it not handled carefully.
  • Explicit Typing: It is different from implicit typing as it is a code which converts a value from one type to another using functions like Number, String or Boolean.
  • Nominal Typing: JavaScript itself does not implement nominal typing. But TypeScript , a superset of JavaScript, includes this feature that helps check type errors at the time of development.
  • Structuring Typing: This type system is based on the structure or properties of the data. JavaScript is a structurally typed language, meaning two objects are compatible as long as they share the same structure (i.e., the same set of properties and methods).
  • Duck Typing: In this style, the suitability of an object is determined by the presence of certain properties and methods rather than the actual type of the object. Duck typing is one of the most employed typing systems you will find in JavaScript as an object type is determined by the properties an object has not what they are declared as.
  • == vs === vs typeof

In fact, JavaScript has a strict (===) and loose (==) equality operator per the ECMAScript Specification, so the operator between these two values behaves differently. Here's a breakdown:

  • == (Loose Equality): This operator compares two values, but before that it will convert both values to the same type. When the values that you use are different types, JavaScript will try to treat either of the values as the same type before comparing them, which can often return unexpected results.
  • === (Strict Equality): This operator compares value and type with no type coercion If the types of the two values do not match, the comparison will give false.
  • typeof Operator: This operator is used to check type of a variable. Although consistent, it has some quirks, for instance, typeof null returns a string with "object" because of a historical bug of messenger JS implementation.
  • Function Scope, Block Scope and Lexical Scope

The ECMAScript specification outlines three key types of scope:

  • Function Scope: If you declare a variable in a method with var, then it will only be available in that method. This scope prevents variables being accessed out of the function where they were declared.
  • Block Scope: Variables declared using let and const have a block scope i.e. Which means, they are only available in the particular block {} in which they are declared (Like loops, or conditionals).
  • Lexical Scope: Describes how variable access is evaluated based on the variables' location in memory. Functions are lexically scoped, which means they can access variables that were declared in the scope where they were defined.
  • Expression vs Statement

An expression yields a value, whereas a statement instructs the program to perform an action, such as variable assignment or controlling the program's flow. Function declarations are hoisted, enabling them to be invoked prior to their actual definition in the code. In contrast, function expressions do not permit invocation before they have been defined.

IIFE, Modules, and Namespaces

An Immediately Invoked Function Expression (IIFE) is a function that executes immediately upon its definition. IIFEs are capable of establishing a local scope and implementing a module pattern, which aids in reducing the risk of contaminating the global namespace. JavaScript Modules allow programmers to organize their code into reusable components, utilizing import and export statements to facilitate sharing with other files. Additionally, namespaces offer a mechanism for categorizing related functions, variables, and objects under a singular, distinctive name, thereby helping to prevent naming collisions.

Message Queue and Event Loop

The Message Queue and the Event Loop are fundamental components that enable the asynchronous programming paradigm in JavaScript. When a request is made to the message queue, the event loop continuously inspects the queue to identify tasks that need to be performed. It is this event loop that transforms JavaScript into a non-blocking runtime environment, as it persistently observes both the call stack and the message queue for the following asynchronous operations.

setTimeout, setInterval, and requestAnimationFrame

  • setTimeout: This is used to run a specific part of code, or a callback function, after a defined set time (in milliseconds). This is used for doing things that should happen after a short delay, like displaying a message, performing an action after a set wait time. JavaScript is single-threaded and event-driven, so the timeout will never be accurate.
  • setInterval: It runs a piece of code, or a callback function, continuously at specified intervals (in milliseconds). It is well-suited for operations that are to happen periodically, such as a clock update or a data polling. This is good to use, but if used inefficiently, it can harm the performance of the site.
  • requestAnimationFrame: This function allows you to perform actions before the next browser repaint and it synchronizes the execution with the refresh rate of the screen. Usually this is used for animations, it is faster than setTimeout or setInteraval and it provides smooth visuals. This one is more efficient compared to the other two as it automatically adapts to the display frame rate and stops when the browser tab is not in focus.
  • JavaScript Engines

JavaScript engines are software applications designed to interpret and execute JavaScript code. Notable examples of these engines include Google V8, utilized by Chrome and Node.js, as well as Mozilla's SpiderMonkey, which is integrated into Firefox. These engines employ Just-In-Time (JIT) compilation techniques to enhance code execution efficiency by transforming JavaScript into machine code, thereby achieving superior performance.

Bitwise Operators, Typed Arrays, and Array Buffers

  • Bitwise Operators: Such as bitwise operators represent operations on binary format numbers in the form of bits (0s and 1s). Some of the common operators are AND (&), AND (|), XOR (^), NOT (~). They are commonly used for basic operations such as flag setting, masking, and bit toggling, providing low-level, binary efficient data manipulation.
  • Typed Arrays: Typed arrays have kind of binary data handling support in the language. These are simply views for working with raw binary data stored in ArrayBuffer objects where you can manipulate integers (Int8Array, Int16Array, etc.) or floating-point numbers (Float32Array, Float64Array) as examples. Typed arrays are useful in performance-sensitive applications (such as WebGL or multimedia).
  • Array Buffers: An ArrayBuffer is a generic, fixed-length raw binary data buffer. It offers a mechanism to allocate and manage unstructured memory, which can later be manipulated and accessed through typed arrays. This enables developers to operate on binary streams with greater effectiveness, facilitating efforts such as file manipulation, encoding/decoding, and hardware interaction.
  • DOM and Layout Trees

The Document Object Model (DOM) serves as a hierarchical representation of your HTML document, enabling JavaScript to alter content, styles, and the overall structure. The Layout Tree is built from both the DOM and the CSSOM (CSS Object Model), specifying the visual presentation of elements as well as their dimensions and positioning.

Factories and Classes

Factories and Classes serve as design patterns utilized for the creation of objects in JavaScript. Factories are essentially functions that generate new objects, enabling both flexibility and dynamic interactions. On the other hand, Classes, which were introduced in ES6, present a syntactical approach to outline object templates that encompass properties and methods, while also facilitating inheritance and encapsulation.

this, call, apply, and bind

  • this: The this keyword refers to the object that is currently executing the function. Its value depends on the execution context in a method, it refers to the object the method is called on in a regular function, it defaults to the global object (or undefined in strict mode). The behavior of this can be dynamic and is influenced by how the function is called.
  • call: call methods are used to call a function with defined this value. You can also pass some arguments in a comma-separated list to the function. When you want to borrow methods or change the context of this dynamically then it is easy in the call method.
  • apply: This function works the same way as the call function. But it accepts arguments as an Array or array-like object instead of comma-separated list. This is especially useful when your arguments themselves are already in an Array.
  • bind: The bind function has its own this value and can also preset some arguments. This does not invoke the function immediately unlike call and apply, it uses the function as a constructor. This is helpful when you want to bind the context to a function forever, mostly used with the event handlers or callbacks.
  • Closures

A closure occurs when a function retains access to its lexical environment even when it is executed beyond that environment. Closures facilitate data encapsulation, enable the use of private variables, and maintain a persistent state. They are commonly utilized in scenarios such as callbacks and factory functions.

Higher-Order Functions

A higher-order function is defined as a function that either accepts another function as an input or produces a function as its output. These functions enhance modularity and abstraction, and are commonly utilized in operations like map, filter, and reduce.

Recursion

The method of executing an action repeatedly involves a process where a function invokes itself. Although this approach can be effectively utilized for traversing trees, it is essential to incorporate a base case in order to prevent the occurrence of an infinite loop.

Input Required

This code uses input(). Please provide values below: