Interview Questions

Filter by difficulty:

A programming language is like a special language computers understand. It helps us give them instructions to do stuff, like making apps, doing tasks automatically, or running devices. It's made up of rules, symbols, and a certain way of writing things called syntax. You might have heard of languages like Java, Python, C++, or JavaScript—they're all different types of programming languages used for different things.

Front-end is what users see and use on a software or website. It's made with languages like HTML, CSS, and JavaScript to build the interface and let users interact with it.

Back-end is like the engine behind a website or app. It handles storing, processing, and managing data. This part includes the server, database, and logic that work together to support what users see and use on the  front-end.

HTML (Hypertext Markup Language) is the building block for web pages and apps. It's made of tags that define how content appears and is laid out on the internet. These tags structure and shape what you see on a web page.

CSS, which stands for Cascading Style Sheets, is like the designer for HTML. It's all about how things look—fonts, colors, spacing, and the overall style of web pages. It works hand in hand with HTML to make things visually appealing on websites.

JavaScript is a versatile programming language used primarily for making websites interactive. It's the language behind the behavior of web pages, enabling features like animations, interactive forms, and dynamic content.

With frameworks like Node.js, you can use JavaScript on the server too, making it possible to build entire applications from front to back with just one language.

JavaScript Java
Primarily for front-end web development Used for server-side applications and Android apps
Dynamically typed Statically typed
Interpreted language for web browsers Compiled into bytecode for JVM
Single-threaded with asynchronous programming Supports multi-threading
Runs on any platform with compatible browser/runtime Platform-independent via JVM
Used in front-end development, Node.js, web apps Enterprise systems, Android, big data
Rich ecosystem with frameworks like React, Angular Large ecosystem with Spring, Hibernate

In JavaScript, paying attention to uppercase and lowercase letters is crucial because it's case-sensitive. That means even a tiny change, like using a capital letter instead of a lowercase one, can make a big difference. For example, "myVariable" and "myvariable" are seen as two distinct things in JavaScript.

javascript

let myVariable;
let myvariable;

HTML provides the structure and content of a webpage.

CSS styles and designs that content, making it visually appealing.

JavaScript adds interactivity, enabling dynamic changes and user interactions on the webpage. Together, they form the backbone of modern web development, with HTML for content, CSS for styling, and JavaScript for functionality.

Together, they form the backbone of modern web development, with HTML for content, CSS for styling, and JavaScript for functionality. Read more

JavaScript was created by Brendan Eich in 1995 while he was working at Netscape Communications Corporation. Initially named "LiveScript," it was later renamed JavaScript as a marketing move to associate it with the popular Java programming language.

It was developed in a very short time, about 10 days, and was first introduced in Netscape Navigator 2.0. Initially, it was primarily used for small client-side tasks. However, its potential for creating dynamic web pages was quickly recognized, leading to its widespread adoption.

In 1997, JavaScript was standardized under the name ECMAScript by Ecma International to ensure its consistency across different platforms. Since then, it has evolved significantly, with regular updates introducing new features and functionalities, making it a key language for both front-end and back-end web development. Read more

ECMAScript is like the rulebook—the set of standards for scripting languages established by Ecma International. On the other hand, JavaScript is a language that follows these ECMAScript rules. Simply put, JavaScript is one way to bring those ECMAScript standards to life.

The official name of JavaScript is ECMAScript, and there have been several versions released over the years. The major versions are:

  • ECMAScript 1 (1997)
  • ECMAScript 2 (1998)
  • ECMAScript 3 (1999)
  • ECMAScript 4 (never released)
  • ECMAScript 5 (2009)
  • ECMAScript 6 (2015), also known as ES2015
  • ECMAScript 7 (2016), also known as ES2016
  • ECMAScript 8 (2017), also known as ES2017
  • ECMAScript 9 (2018), also known as ES2018
  • ECMAScript 10 (2019), also known as ES2019
  • ECMAScript 11 (2020), also known as ES2020
  • ECMAScript 12 (2021), also known as ES2021

ES5 (ECMAScript 5) arrived in 2009 and earned broad support from major browsers. Then came ES6 (ECMAScript 2015) in 2015, bringing in fresh features like arrow functions, classes, and template literals. While not all browsers embraced every ES6 feature, it quickly became the go-to standard for JavaScript development.

Client-side JavaScript works its magic right in a user's web browser. It's all about creating those cool interactive effects and changing what's on the page dynamically.

On the other hand, server-side JavaScript does its job on the server. It takes care of the behind-the-scenes tasks, like managing requests, talking to databases, and getting data ready to send back to the user's browser. Two different places, but both using JavaScript to make things happen!

1. High-Level Language: JavaScript is a high-level language, meaning it's designed to be more human-readable, abstracted from machine code, and easier to understand and write.

2. Garbage Collected: JavaScript has automatic memory management. When objects are no longer needed, the garbage collector kicks in to clean up memory, making it easier for developers by handling memory deallocation.

3. Interpreted Language (JIT): JavaScript is typically interpreted by browsers' engines. Just-in-Time (JIT) compilation optimizes code execution at runtime, translating it into machine code on the fly for faster performance.

4. Multi-Paradigm: JavaScript supports multiple programming paradigms like object-oriented, imperative, and functional programming, allowing developers to choose different approaches as needed.

5. Prototype-Based Functions: JavaScript uses prototypes for object inheritance instead of traditional classes. Objects can inherit properties and behaviors directly from other objects, offering flexibility in object creation.

6. First-Class Functions: Functions in JavaScript are treated as first-class citizens, meaning they can be assigned to variables, passed as arguments to other functions, and returned from functions, enabling higher-order functions and functional programming techniques.

7. Dynamically Typed: JavaScript doesn't require explicit type declarations. Variable types are determined at runtime, allowing flexibility but also potentially introducing errors due to unexpected type conversions.

8. Single Threaded: JavaScript operates on a single thread, meaning it can only execute one operation at a time in a single call stack. This can lead to blocking operations if not managed well.

9. Non-Blocking Event Loop: Despite being single-threaded, JavaScript uses an event-driven, non-blocking I/O model. It handles asynchronous operations through event callbacks and timers, allowing for efficient handling of multiple tasks without blocking the main thread.

10. Platform Independent: JavaScript is supported across various platforms and devices due to its compatibility with web browsers, making it a versatile language for web development that isn't tied to a specific operating system. These features collectively contribute to JavaScript's versatility and functionality across a wide range of applications and development scenarios.

These features collectively contribute to JavaScript's versatility and functionality across a wide range of applications and development scenarios.

JavaScript is indeed a dynamically typed language. In dynamically typed languages like JavaScript, variable types are determined at runtime, allowing for more flexibility but sometimes leading to unexpected behavior if not carefully managed.

In a single-threaded environment, the program processes one operation at a time, ensuring that each task is finished before moving to the next. This simplicity makes single-threaded programs easier to manage and understand. However, they might not utilize the full potential of modern hardware with multiple cores and processors, potentially limiting their performance in certain scenarios.

A non-blocking event loop is a clever way for software to manage many requests and events at once without slowing down the main operations. It keeps an eye out for new events, handles each one using its callback, and does it all in a loop. This way, the application stays responsive to other things going on while smoothly managing these events asynchronously. It's a technique widely used in web servers, network programming, and graphical user interfaces (GUIs) to keep things running smoothly without getting bogged down by one task.

The rules for defining a variable depend on the programming language being used, but in general, some common rules include:

  • 1. The name of the variable should start with a letter or underscore character.
  • 2. The name of the variable should consist of letters, digits, or underscore characters only.
  • 3. Variable names are case-sensitive.
  • 4. Variable names should not be the same as reserved words or keywords used by the programming language.
  • 5. Variable names should be descriptive and meaningful to aid code readability. It's important to follow the correct syntax and rules when defining variables as it can affect the functionality of the program.

Variables in JavaScript are containers for storing data, declared using `var`, `let`, or `const` followed by a unique name. They store various data types like numbers, strings, arrays, and objects, allowing developers to manipulate these values using operators and functions. Variables enable dynamic storage, retrieval, and manipulation of data, making them essential for managing program state and performing computations in JavaScript.

In programming, **'data'** is any information used by a program, such as numbers, strings, arrays, or objects. **'Value'** is a specific instance of data, representing the content of a variable or expression at a given time. Data provides the framework, while values are the actual representations used and manipulated in the program.

In frameworks like Angular and React, using "use strict" explicitly is often unnecessary because these frameworks automatically enforce strict mode by default. Modern JavaScript frameworks (including Angular and React) primarily use ES6 modules (import/export). Strict mode is automatically enabled in all ES6 modules, so there's no need to include "use strict" manually at the top of the module files.

In computer programming, a data type is an attribute of a variable or value that determines the type of data it can hold, such as integers, floating-point numbers, characters, and booleans. Data types help ensure that operations are performed correctly on variables and values, and they allow the compiler or interpreter to allocate the appropriate amount of memory for a particular data object.

There are seven primitive data types in JavaScript:

  • 1. Boolean
  • 2. Null
  • 3. Undefined
  • 4. Number
  • 5. BigInt (added in ES2020)
  • 7. Symbol

And two non-primitive data types:

  • 1. object
  • 2. function

In JavaScript, a symbol is a primitive data type that is used to create unique values. It is often used as an identifier for object properties to avoid naming conflicts. Symbols are created using the Symbol() function and can be used as keys in object literals or added as properties to objects.

javascript

const mySym = Symbol(8);

BigInt is a built-in data type in JavaScript that allows the representation of integers larger than 2^53 - 1, which is the maximum safe integer value in JavaScript. BigInt values are represented by appending the letter "n" to the end of an integer literal or by calling the BigInt() constructor function.

javascript

const bigNumber = BigInt(35445565654656);
const anotherBigNumber = 3454354543543543n;
Primitive Data Types Non-Primitive Data Types
Primitive types store single values directly Non-primitive types store references to objects
Primitive types: number, string, boolean, null, undefined, symbol (ES6) Non-primitive types: classes, arrays, interfaces
Immutable and have fixed memory size Mutable and memory size can vary
Stored in the stack memory Stored in the heap memory
Compared by value Compared by reference

The `typeof NaN` in JavaScript is `'number'`. This is because `NaN` (which stands for "Not a Number") is a special value in JavaScript that represents an invalid number result. While it has the type of `number`, it is not actually a real number and cannot be used in mathematical operations.

javascript

console.log(typeof NaN); //number

The `typeof` operator in JavaScript returns `"object"` when applied to the value `null`. However, `null` is not actually an object, but rather a primitive value representing the intentional absence of any object value.

javascript

console.log(typeof null); //object

In JavaScript, Infinity is a global property that represents the mathematical concept of infinity, which is an infinitely large number. It is used to represent values that are too large or too small to be represented by the Number data type. For example, dividing a non-zero number by zero results in Infinity. Positive Infinity is represented by the keyword "Infinity", while Negative Infinity is represented by the keyword "-Infinity".

javascript

console.log(10/0); //Infinity

High-level languages are more abstracted and user-friendly, designed to be closer to human language and easier to understand. They offer built-in features and are independent of the machine's architecture.

Low-level languages are preferred for embedded systems, operating systems, device drivers, and performance-critical applications due to their direct hardware control, resource optimization, and high performance.

High-level languages are more abstracted, closer to human language, and offer better readability. They're easier to learn and use, handling complex tasks with simpler syntax. Low-level languages are closer to machine code, offering direct hardware control, but they're less readable and more complex due to their proximity to hardware operations.

Front-end Back-end
Deals with what users interact with Manages server, database, and application logic
Technologies: HTML, CSS, JavaScript Technologies: Node.js, Python (Django), Ruby (Rails)
Creates user interfaces and experiences Handles server-side operations and data storage
Runs in the user's web browser Runs on the server
Focuses on design, interactivity, and responsiveness Read more Focuses on data, security, and server management Read more

Developer tools are essential in web development for debugging, performance optimization, and efficiency. Some widely used tools include:

  • 1. Chrome DevTools:
    • Inspect and modify HTML/CSS.
    • Debug JavaScript.
    • Analyze network and performance.
  • 2. Visual Studio Code:
    • Intelligent code suggestions.
    • Built-in debugging.
    • Versatile extensions.
  • 3. Webpack:
    • Bundles assets for optimization.

Standardization in JavaScript is crucial for ensuring consistency, interoperability, and compatibility across different platforms and browsers. It helps developers write code that behaves predictably regardless of the environment in which it runs.

The ECMA International (European Computer Manufacturers Association) plays a significant role in standardizing JavaScript through the ECMAScript specification. ECMAScript defines the scripting language's syntax, semantics, and core features. It ensures that different implementations of JavaScript (like in browsers or server-side environments) conform to the same set of rules, facilitating portability and reducing fragmentation.

Ensuring JavaScript compatibility across browsers and devices poses several challenges due to differences in rendering engines, feature support, and performance optimizations. Some challenges include:

  • Challenges:
  • Solutions:

By employing these strategies, developers can enhance JavaScript compatibility across various browsers and devices, providing a consistent experience for users.

Handling JavaScript compatibility across different browsers and versions involves several techniques and tools:

Polyfills and transpilers are essential tools in managing JavaScript compatibility concerns. They address the following aspects:

  • Polyfills:
  • Transpilers (e.g., Babel):

Feature detection and browser detection are two distinct strategies for managing JavaScript compatibility:

  • Feature Detection:
  • Browser Detection:

Automatic memory management, or garbage collection , is a process in programming languages like JavaScript that handles memory allocation and deallocation automatically. It works by periodically identifying and freeing up memory that's no longer in use. This prevents memory leaks and removes the need for manual memory management. The process involves two main mechanisms:

  • Mark-and-Sweep Algorithm: It scans through the memory, marks objects that are still in use, and then clears out the unmarked ones.
  • Reference Counting: This method keeps track of references to objects; when an object has no references pointing to it, it's considered unused and can be collected.

Developers don't typically manage this process directly in JavaScript. Still, they can assist the garbage collector by nullifying unnecessary references and being cautious with closures and event listeners that might unintentionally retain references. Understanding these concepts helps in writing more efficient code and avoiding memory leaks.

Interpreted languages like JavaScript are translated line-by-line during execution, while compiled languages are translated entirely before execution, optimizing performance. Just-In-Time (JIT) compilation in JavaScript dynamically compiles frequently used code into optimized machine code during runtime, boosting performance by adapting to runtime behavior and caching previously compiled code. This hybrid approach combines the flexibility of interpreted languages with the performance benefits of compiled languages.

A multi-paradigm programming language supports multiple programming paradigms , which are different approaches or styles of programming. These paradigms dictate how a programmer structures and organizes code to solve problems. Some common paradigms include procedural, object-oriented, functional, and imperative programming.

In JavaScript, prototype-based inheritance links objects through prototypes, allowing properties to be inherited by looking up the prototype chain. It's flexible and dynamic, enabling easy runtime modifications. In contrast, languages like Java or C++ use class-based inheritance, where objects are created based on predefined classes, offering a more structured, compile-time-defined approach to inheritance.

First-class functions refer to a programming language's ability to treat functions as first-class citizens, which means functions are treated just like any other data type, such as numbers or strings. In JavaScript, functions are indeed considered first-class citizens.

JavaScript allows functions to be stored in variables, passed as arguments, and returned from other functions. This flexibility enables higher-order functions, function composition, callbacks for handling events, and supports functional programming concepts like map and reduce. This approach in JavaScript makes code more modular, expressive, and versatile.

JavaScript uses dynamic typing , determining variable types at runtime and allowing variables to hold different types of values. Statically typed languages require explicit type declarations, checked at compile-time. JavaScript's flexibility without explicit type declarations can make code quicker to write but might lead to runtime type-related errors, unlike statically typed languages that catch errors early but might require more annotations and verbose code.

JavaScript's single-threaded nature means it operates on a single call stack, executing one command at a time. This can pose challenges for concurrency and performance in web applications. Long-running tasks can block other operations, but JavaScript manages this using asynchronous programming, like event loops and callbacks. This ensures responsiveness in the user interface and allows non-blocking execution of tasks, improving performance despite being single-threaded.

The event loop in JavaScript manages asynchronous tasks by checking the call stack and event queue. When the stack is empty, it picks tasks from the queue and executes them, enabling non-blocking operations. It ensures that asynchronous tasks, once completed, trigger their callbacks without waiting, allowing efficient handling of I/O operations without blocking the main thread. This mechanism is vital for managing non-blocking I/O in JavaScript.

JavaScript's platform independence allows it to run across various environments: browsers, servers, mobile, and desktop applications. This versatility means developers can use the same language for different platforms, reducing the need to learn multiple languages and offering a consistent development experience. This characteristic greatly contributes to JavaScript's widespread use in diverse domains.

console.log() is for general information output. console.error() is specifically for logging errors, displaying them in red for immediate attention. console.warn() is for warnings, displayed in yellow to highlight potential issues. All three methods output information to the console but serve different purposes based on the severity of the message.

console.log() is handy for:

It's a vital tool for understanding code behavior and identifying issues during JavaScript debugging.

document.write() writes content directly into the HTML document during or after loading. It's handy for quick demos but has limitations: it can interrupt parsing, affect performance, cause asynchronous issues, and isn't suitable for complex development due to potential unexpected behavior in modern web applications. It's generally avoided in favor of more controlled DOM manipulation methods or modern frameworks.

document.write() is suitable for quick demos or when immediate content modification during page load is necessary, especially for testing or script loading. However, it's generally avoided due to its limitations and potential issues in complex applications. Other methods like innerHTML or appendChild() offer more control and reliability for DOM manipulation in modern development.

The innerHTML property in JavaScript is used to access or modify the HTML content within an element in the Document Object Model (DOM). It allows developers to dynamically change the content of an HTML element by setting or retrieving the markup contained within it. When using it Read more :

innerHTML updates HTML content within an element directly, useful for quick changes. createElement() and appendChild() create and manipulate elements, offering more control and efficiency, preferable for complex or multiple element creations and structured DOM manipulations. Use innerHTML for simple changes and the latter for more controlled, performant manipulations.

In JavaScript, values are evaluated as either truthy or falsy in a boolean context. When a non-boolean value is used in a boolean expression (like in an if statement), it's implicitly converted to a boolean value (true or false). Values that evaluate to true in a boolean context are termed truthy, while those evaluating to false are termed falsy.

Type coercion in JavaScript refers to the automatic or explicit conversion of values from one data type to another. It occurs when values of different types are combined or compared in operations, forcing them to be converted to a common type for the operation to be executed.

Manual type conversion in JavaScript involves explicitly converting data from one type to another using built-in functions or methods provided by the language.

Identifiers in JavaScript are names used to identify variables, functions, objects, and other entities within a program. They serve as labels that represent specific elements in the code.

When creating identifiers in JavaScript, certain rules and conventions should be followed to maintain readability and ensure compatibility with the language's syntax. Read More

Reserved keywords in JavaScript are words that have predefined meanings or functionalities within the language. These keywords are reserved for specific purposes and cannot be used as identifiers (such as variable names, function names, or labels) in JavaScript code.

In JavaScript, constants are identifiers used to represent fixed values that remain unchanged throughout the execution of a program. They are similar to variables in that they can store data, but unlike variables, the value assigned to a constant cannot be reassigned or changed once it's initialized.

The let keyword in JavaScript is used to declare variables that are block-scoped. It was introduced in ES6 (ECMAScript 2015) and offers some differences compared to var, particularly in terms of scoping and hoisting.

let in JavaScript is for declaring variables with block-level scope. Unlike var, it doesn't hoist variables to the top of their scope. let restricts variable access to the block where it's defined, making code more predictable and preventing hoisting-related bugs compared to var.

The var keyword in JavaScript is used to declare variables. It was the primary way to declare variables in JavaScript before the introduction of let and const in ES6 (ECMAScript 2015). Understanding its behavior regarding scope and hoisting is crucial when using var.

var in JavaScript declares variables with function-level scope. It's hoisted to the top of its scope during compilation, initializing as undefined. This means the variable is accessible throughout the whole function or globally if outside any function. However, it can lead to unexpected behavior due to hoisting and lack of block-level scope. It's best to use let or const for clearer scoping and to avoid potential issues.

The const keyword in JavaScript is used to declare constants, which are variables whose values cannot be reassigned or redeclared once they have been initialized. Constants must be assigned a value at the time of declaration, and this value remains constant throughout the code execution.

It's important to note that while const prevents reassignment, for objects or arrays, their internal elements can still be changed, but you can't assign a completely new object or array to a const variable.

Alert boxes, while handy for displaying immediate messages, come with several limitations that can impact user interaction and customization:

In JavaScript, the confirm() method is used to display a dialog box with a message and two buttons: "OK" and "Cancel." It's a built-in function that prompts the user to confirm or cancel an action, providing a Boolean response based on the user's choice Read more .

window.alert() displays a message in a dialog box, pausing the script until the user clicks OK. It's used for critical notifications but sparingly because it disrupts user interaction and script execution. Overuse can desensitize users and impact the user experience.

window.alert() is simple and immediate but disrupts flow and lacks customization. Modals or custom UI elements offer more control and better user experience but take longer to implement and might complicate the application if overused.

While window.alert() offers simplicity and standardization, modals or custom UI elements provide more flexibility, customization, and better user interaction. The choice between them depends on the specific context, considering the importance of the message, the desired user experience, and the overall design strategy of the application. Balancing simplicity with a rich and user-friendly experience is key in choosing the appropriate method for displaying messages.

In JavaScript, the prompt() method displays a dialog box with a message prompting the user to input data. It allows users to enter text or data into an input field within the dialog box and returns the entered value as a string Read more .

Operators in programming are symbols or keywords that perform operations on one or more operands to produce a result. They are fundamental components of programming languages and are used to manipulate data, perform calculations, compare values, and control the flow of execution within a program.

In programming, an operand is a term used to describe the data or values on which an operator operates to perform a specific operation. In simple terms, an operand is a variable, constant, or literal value that is manipulated by an operator within an expression or statement.

In expressions involving operators, operands are the entities that the operator acts upon to produce a result.

javascript

let a = 5; // Operand (variable)
let b = 3; // Operand (variable)

let result = a + b; // Operator (+) acts on 'a' and 'b' to produce a result

console.log(result); // Output will be 8 (sum of 'a' and 'b')

Arithmetic operators in JavaScript perform mathematical operations on numeric values.

Comparison operators in JavaScript are used to compare two values or expressions and produce a Boolean result (true or false) based on the comparison's outcome. They play a crucial role in evaluating conditions within conditional statements like if, while, or for loops.

Assignment operators in JavaScript are used to assign values to variables. They differ from the simple assignment operator (=) by combining assignment with arithmetic or other operations, making the code more concise.

= (Assignment Operator): The = operator is used for assignment in many programming languages. It assigns the value on the right-hand side to the variable on the left-hand side. For example, x = 5; assigns the value 5 to the variable x.

== (Equality Operator): The == operator is used for equality comparison. It checks if the values on both sides are equal after performing type coercion. For instance, 5 == '5' will return true because it coerces the string to a number and then checks equality.

=== (Strict Equality Operator): The === operator is also used for equality comparison. However, unlike ==, it checks for strict equality without performing type coercion. It checks if both the values and their types are identical. For example, 5 === '5' will return false because the types are different (number vs. string).

Logical operators in JavaScript are used to perform logical operations on Boolean values and expressions.

The ternary operator, also known as the conditional operator (? :), provides a concise way to write conditional expressions in JavaScript. It's a shorthand alternative to the if-else statement and allows you to make decisions based on conditions in a single line of code.

The typeof operator in JavaScript is used to determine the data type of a variable or an expression, returning a string that represents the type of the operand.

Operator precedence in JavaScript defines the order in which different operators are evaluated when multiple operators are present in an expression. It determines the grouping of operands and operators based on their precedence levels.

In programming, a control structure refers to the blocks or constructs that enable you to control the flow of execution within a program. These structures determine the order in which individual statements or instructions are executed based on specified conditions.

A loop in programming is a control structure that allows the repeated execution of a block of code as long as a specified condition is true. It's used to automate repetitive tasks or iterate over collections of data, enabling efficient execution of code without the need for writing the same instructions multiple times.

The for loop in JavaScript is a control flow statement that allows you to execute a block of code repeatedly for a specified number of iterations. It's commonly used to iterate over elements in an array, perform a task a certain number of times, or traverse through a range of values Read more .

The for...of loop in JavaScript is an iteration statement introduced in ECMAScript 6 (ES6) that simplifies the process of iterating over iterable objects, such as arrays, strings, maps, sets, and other iterable data structures. It provides a more concise and readable syntax compared to traditional for loops when working with collections Read more .

The for...in loop in JavaScript is used to iterate over the enumerable properties of an object. It traverses through all enumerable keys (property names) of an object, allowing you to access the values associated with those keys. It's commonly used for object iteration Read more .

The while loop in JavaScript repeatedly executes a block of code as long as a specified condition remains true. It's used when the number of iterations is uncertain and is determined by a condition that needs to be evaluated before each iteration Read more .

Use a for loop when you know the exact number of iterations or when you are iterating over a collection (like arrays or lists). It's ideal for cases where the loop control is defined by a counter:

for (let i = 0; i < 10; i++) {
  // Executes 10 times
}

Use a while loop when the number of iterations is not known in advance and depends on a condition. It's best when the loop should continue until a particular condition is met:

while (condition) {
  // Executes as long as condition is true
}

The do...while loop in JavaScript is similar to the while loop but with one crucial difference: it ensures that the code block inside the loop is executed at least once, even if the condition is initially false. After the first execution, it evaluates the condition and continues executing the loop as long as the condition remains true Read more .

Nested loops in JavaScript refer to using one loop inside another loop. This creates a loop within a loop, allowing for the execution of repetitive tasks that require multiple iterations at different levels. They are particularly useful for handling multidimensional data structures, generating combinations, or working with matrices.

The switch statement in JavaScript provides a way to perform different actions based on multiple possible conditions. It serves as an alternative to using multiple if...else statements when you have a single expression that needs to be compared to several different values Read more .

break: break is a keyword that interrupts the current loop or switch block execution. When encountered, break immediately exits the loop or switch block, moving to the next statement after the loop or switch. It's commonly used to terminate a loop prematurely based on certain conditions, avoiding unnecessary iterations Read more .

continue: continue is a keyword used in loops to skip the current iteration and proceed to the next iteration. When continue is encountered, the loop execution immediately jumps to the next iteration, bypassing any remaining code within the loop for the current iteration. It's useful for skipping certain iterations based on specific conditions without completely exiting the loop.

The default case within a switch statement serves as a catch-all case, executing when none of the preceding case values match the expression provided to the switch. It's similar to the else statement in an if...else chain, executing when no specific case matches the given expression Read more.

In JavaScript, the switch statement is case sensitive, meaning it differentiates between uppercase and lowercase characters when matching cases. This sensitivity influences how the switch block evaluates and matches cases against the provided expression Read more.

When intentionally using "falling through" cases in a switch statement, where multiple cases share the same block of code without break statements between them, several precautions and considerations are crucial to ensure proper code execution and avoid unexpected behavior:

  • Capabilities:
  • Limitations:

Forward compatibility refers to the ability of a system or software to gracefully handle data or functions from newer versions without breaking compatibility with older versions.

Backward compatibility refers to the ability of a system or software to maintain compatibility with older versions, ensuring that previous functionalities and data remain usable when upgrading to newer versions.

The ECMA-262 specification is the official standard for JavaScript, defining the syntax, semantics, and behaviors of the language.

ISO/IEC 22275 is a standard that specifies the requirements for software engineering tools for the verification and validation of web content accessibility.

The separation of concerns principle is a design principle that advocates for dividing a computer program into distinct sections, each addressing a separate concern, such as presentation, data storage, and business logic.

"use strict" is a directive in JavaScript that enables strict mode, enforcing stricter parsing and error handling rules. It helps catch common coding mistakes and promotes safer, more optimized code.

Just-In-Time (JIT) compilation is a technique used in programming language implementations where code is compiled at runtime, just before it is executed. This contrasts with ahead-of-time (AOT) compilation, where code is compiled before runtime.

  • Benefits of JIT compilation include:

A string in JavaScript is a sequence of characters used to represent text. Strings are immutable, meaning once created, they cannot be changed. They can be created using single quotes (' '), double quotes (" "), or backticks (` ` for template literals).

There are two main ways to create strings in JavaScript:

  • String Literal (most common):
    let str = "Hello"; 
  • Using new String() Constructor (creates an object, rarely used):
  • let strObj = new
    String("Hello");

You can convert a number to a string in JavaScript in two main ways:

  • Using toString() method:
  • let num = 123;
    let str = num.toString();
  • Using String() function:
  • let strObj = new
    String("Hello");

You can convert a string to a number in JavaScript using:

  • Number() function:
  • let str = "123"; 
    let num = Number(str); 
  • parseInt() for integers:
  • let str = "123"; 
    let num = parseInt(str);
  • parseFloat() for floating-point numbers:
  • let str = "123.45"; 
    let num = parseFloat(str);

The difference between == and === in JavaScript when comparing strings is that == (loose equality) checks for value equality after type conversion (coercion).

"123" == 123 // true (string is converted to a number)

=== (strict equality) checks for both value and type equality without type conversion.

"123" === 123 //false

You can check if a string contains a specific substring in JavaScript using:

  • includes() method (returns true or false):
  • let str = "Hello, world!"; 
    str.includes("world");// true
  • indexOf() method (returns the index, or -1 if not found):
  • let str ="Hello, world!"; 
    str.indexOf("world") !== -1; // true

You can extract a part of a string in JavaScript using three main methods:

  • slice:
  • //slice(start, end)
    let str = "Hello, world!"; 
    let part = str.slice(0, 5); // "Hello" 
  • substring:
  • //substring(start, end)
    let str = "Hello, world!"; 
    let part = str.substring(0, 5); // "Hello" 
  • substr:
    //substr(start, length) (deprecated but still used)
    let str = "Hello, world!"; 
    let part = str.substr(0, 5); // "Hello"

The differences between slice(), substring(), and substr() in JavaScript are:

slice(start, end):

  • Extracts from start to end (not inclusive).
  • Accepts negative indices.
"Hello".slice(1, 4); // "ell"
"Hello".slice(-4, -1); // "ell"

substring(start, end): -

  • Extracts from start to end (not inclusive).
  • Does not accept negative indices.
"Hello".substring(1, 4); // "ell"

substr(start, length) (deprecated):

  • Extracts a substring starting at start with a specified length.
  • Accepts negative start values.
"Hello".substr(1, 3); // "ell"
"Hello".substr(-4, 3); // "ell"

Template literals are a type of string in JavaScript enclosed by backticks (` `) and allow:

String Interpolation: Embed variables or expressions using ${}.

let name = "John"; 
let greeting = `Hello, ${name}!`; // "Hello, John!"

Multi-line strings: Write strings over multiple lines without needing escape characters.

let multiLine = `This is a multi-line string.`;

Differences from regular strings:

  • Template literals: Use backticks (` `), support interpolation, and handle multi-line easily.
  • Regular strings: Use single (' ') or double (" ") quotes and require manual concatenation for variables or expressions.

replace(): - Replaces only the first occurrence of a substring or pattern.

 let str = "apple apple"; 
str.replace("apple", "orange"); // "orange apple"

replaceAll(): - Replaces all occurrences of a substring or pattern.

let str = "apple apple"; 
str.replaceAll("apple", "orange"); //"orange orange"

Note: replaceAll() is newer (introduced in ES2021), while replace() has been around longer.

test() method (used with a regular expression): - Returns true if the string matches the pattern.

let regex = /hello/; 
regex.test("hello world"); // true

match() method (returns matching substrings or null): - Can be used to check if there's a match (returns an array or null).

let str = "hello world"; 
str.match(/hello/); // ["hello"]

You can find the first occurrence of a substring in a string in JavaScript using the indexOf() method. It returns the index of the first occurrence of the substring, or -1 if the substring is not found.

let str = "Hello, world!";
let index = str.indexOf("world"); // returns 7

Using a loop with indexOf():

let str = "Hello world, welcome to the world!"; 
let searchTerm = "world"; 
let indices = [];
let index = str.indexOf(searchTerm);

while (index !== -1) {
    indices.push(index);
    index = str.indexOf(searchTerm, index + 1); // Continue searching from the next position
}

console.log(indices); // [6, 23]

Using regular expressions with match():

let str = "Hello world, welcome to the world!"; 
let matches = str.match(/world/g);  // ["world", "world"]
//The g flag in the regex ensures it finds all matches.

1. Unicode: Unicode is a character encoding standard that aims to represent every character from every writing system. Each character is assigned a unique code point (e.g., 'A' = U+0041). JavaScript strings are based on the Unicode standard, meaning they can represent characters from virtually any language.

2. UTF-16: UTF-16 (16-bit Unicode Transformation Format) is the encoding JavaScript uses internally to represent strings. Each character is represented by 16 bits (2 bytes). For characters beyond the Basic Multilingual Plane (BMP), UTF-16 uses two 16-bit code units (known as a surrogate pair). Examples:

  • A character like 'A' is represented as a single 16-bit code unit.
  • Emojis or certain special characters (e.g., 😊) require two 16-bit units in UTF-16.
let str = '😊';
console.log(str.length);  // 2 (because it uses a surrogate pair in UTF-16)

1. charCodeAt : Use the charCodeAt() method to get the character code (Unicode) of a character at a specific position in a string.

let str = 'A'; 
let code = str.charCodeAt(0);  // 65 (Unicode code for 'A')

2. String.fromCharCode(): Use the String.fromCharCode() method to convert a character code back to a string.

let code = 65;
let char = String.fromCharCode(code);  // 'A'

These methods work for characters within the Basic Multilingual Plane (BMP), where each character is represented by a single 16-bit code unit. For characters outside BMP (e.g., emojis), you'd use codePointAt() and String.fromCodePoint().

1. for loop:

let str = "Hello";
for (let i = 0; i < str.length; i++) {
  console.log(str[i]);
}

2. for...of` loop (preferred for strings):

let str = "Hello";
for (let char of str) {
  console.log(char);
}

3. split() method with forEach():

let str = "Hello";
str.split('').forEach(char => console.log(char));

4. charAt() method in a loop:

let str = "Hello";
for (let i = 0; i < str.length; i++) {
    console.log(str.charAt(i));
}

The difference between charAt() and charCodeAt() in JavaScript is:

1. charAt(index): Returns the character at the specified index in the string. - Output is a string.

let str = "Hello"; 
str.charAt(1); // "e"

2. charCodeAt(index): Returns the Unicode character code (numeric value) of the character at the specified index. - Output is a number.

let str = "Hello"; 
str.charCodeAt(1); // 101 (Unicode code for "e")

In short, charAt() gives you the character, while charCodeAt() gives you its Unicode value.

When you try to access a character at an index that doesn't exist in a string in JavaScript:

1. Using charAt: It returns an empty string ("").

let str = "Hello";
console.log(str.charAt(10)); // ""

2. Using bracket notation ([]): It returns undefined.

let str = "Hello"; 
console.log(str[10]); // undefined

Both cases handle out-of-range indices gracefully without throwing an error.

Yes, JavaScript strings are immutable. This means once a string is created, it cannot be changed or modified. Any operation that seems to modify a string, such as concatenation or replacing a part of it, actually creates and returns a new string without altering the original one.

let str = "Hello"; 
str[0] = "h"; // This has no effect, strings are immutable 
console.log(str); // "Hello"

To change a string, you need to create a new one:

let newStr = str.replace("H", "h"); // "hello"

You can handle multi-line strings in JavaScript in two main ways:

1. Using Template Literals (best option): Template literals, enclosed in backticks (` `), allow you to create multi-line strings easily.

let multiLine = `This is
a multi-line
string.`; 

2. Using Escape Character (\n): You can also use \n for new lines within regular strings.

let multiLine = "This is\na multi-line\nstring.";

When working with strings in JavaScript, some key performance considerations include:

1. String Immutability: Since strings are immutable, any modification creates a new string, which can lead to memory overhead, especially in loops or large data processing.

2. String Concatenation: Repeated string concatenation (using `+`) in loops can be inefficient due to the creation of many intermediate strings. Instead, consider using:

let str = ["Hello", "World"].join(" ");

3. Template Literals: While template literals improve readability, their performance is similar to regular string concatenation, but be mindful of excessive usage in performance-critical areas.

4. Avoiding Unnecessary String Operations: Frequent use of methods like replace(), slice(), or substring() on large strings can be costly due to the creation of new strings each time.

5. Memory Usage: If dealing with large datasets or strings (e.g., file contents), try to minimize unnecessary string operations to reduce memory consumption and processing time.

By considering these factors, you can improve the performance of your JavaScript code when handling strings.

In JavaScript, you can use regular expressions with strings through methods like match(), replace(), search(), and split().

1. match(): Finds matches based on a regular expression.

let str = "Hello world!";
let result = str.match(/world/);  // ["world"]

2. replace(): Replaces parts of a string that match a regular expression.

let str = "Hello world!";
let result = str.replace(/world/, "JavaScript");  // "Hello JavaScript!"

3. search(): Returns the index of the first match or -1 if not found.

let str = "Hello world!";
let index = str.search(/world/);  // 6

4. split(): Splits a string based on a regular expression.

let str = "apple, banana, cherry";
let result = str.split(/,\s*/);  // ["apple", "banana", "cherry"]

Regular Expression Flags:

  • g: Global search (find all matches).
  • i: Case-insensitive search.
  • m: Multi-line search.
let str = "Hello hello";
let result = str.match(/hello/gi);  // ["Hello", "hello"]

Regular expressions provide powerful pattern matching and string manipulation capabilities in JavaScript.

The difference between match() and exec() when dealing with regular expressions in JavaScript is:

1. match():

  • Used on strings.
  • Returns an array of matches or null if no match is found.
  • With the global (g) flag, it returns an array of all matches.

//Example without g flag:
let str = "Hello world";
let result = str.match(/world/);  // ["world"]

//Example with `g` flag:
let str = "Hello world world";
let result = str.match(/world/g);  // ["world", "world"]

2. exec():

  • Used on regular expression objects.
  • Returns an array with detailed match information, or null if no match is found.
  • Only returns one match at a time, even with the global flag. It must be called repeatedly in a loop to get all matches.
let regex = /world/;
let result = regex.exec("Hello world");  // ["world"]

//With g flag and loop:
let regex = /world/g;
let str = "Hello world world";
let match;

while ((match = regex.exec(str)) !== null) {
    console.log(match);  // Logs each "world" match
}

Key Differences:

  • match() is simpler and often used for straightforward matching on strings.
  • exec() is more powerful and detailed, providing additional match information like capture groups, but requires manual iteration for multiple matches when using the g flag.

To check if a string is empty in JavaScript, you can simply compare it to an empty string (""). Using a simple comparison:

let str = "";
if (str === "") {
    console.log("String is empty");
}

Alternatively, using the .length property:

let str = "";
if (str.length === 0) {
    console.log("String is empty");
}

A tagged template literal in JavaScript is a way to parse a template literal with a function (called a "tag"). The tag function processes the template literal's parts before it produces the final string or value. It allows for more advanced manipulation of the template literal's contents, such as formatting or custom processing.

//Syntax:
tagFunction`Template literal string ${expression}`;
//Example:
function myTag(strings, ...values) {
    console.log(strings);  // Array of string parts
    console.log(values);   // Array of expression values
    return strings[0] + values[0];  // Just for demonstration
}

let name = "John";
let result = myTag`Hello, ${name}!`;
console.log(result);  // "Hello, John!"
 

myTag is the tag function that receives:

  • strings: an array of string segments (static parts of the template).
  • values: the values of the interpolated expressions.

You can process these values and return a new string or value. Use Cases:

  • Custom string formatting (e.g., currency, localization).
  • Security (e.g., escaping HTML or SQL injection prevention).
  • More complex processing of template literals beyond simple interpolation.

A function declaration defines a named function using the function keyword as a statement. It is hoisted, meaning you can call it before its definition in the code.

A function expression assigns a function to a variable. It is not hoisted, so it must be defined before it is called.

// Function Declaration - hoisted
console.log(square(3)); // 9
function square(n) { return n * n; }

// Function Expression - NOT hoisted
// console.log(cube(3)); // TypeError
const cube = function(n) { return n * n * n; };
console.log(cube(3)); // 27

An arrow function is a concise function syntax introduced in ES6 using =>. Key differences from regular functions:

  • No own this — inherits this from the enclosing scope.
  • No arguments object.
  • Cannot be used as a constructor (no new).
  • Supports implicit return when body has no curly braces.
const add = (a, b) => a + b;
console.log(add(2, 3)); // 5

const obj = {
  value: 10,
  regular: function() { return this.value; }, // 10
  arrow: () => this // refers to outer 'this', not obj
};

The arguments object is an array-like object available inside regular functions that contains all the values passed to the function, regardless of how many parameters are defined. It is not available in arrow functions.

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)); // 10

In modern JavaScript, it is recommended to use rest parameters (...args) instead, which returns a real array.

Default parameters allow you to set a fallback value for a function parameter when no argument or undefined is passed. They were introduced in ES6.

function greet(name = "Guest") {
  return "Hello, " + name + "!";
}

console.log(greet("Alice")); // Hello, Alice!
console.log(greet());        // Hello, Guest!

Default values are evaluated at call time, not at function definition time. They can also reference other parameters defined before them.

In JavaScript, primitives (numbers, strings, booleans) are passed by value. A copy is made inside the function; the original variable is unaffected.

Objects and arrays are passed by reference. The function receives a reference to the same object, so mutations inside the function affect the original.

// Primitive - pass by value
function addTen(n) { n += 10; }
let x = 5;
addTen(x);
console.log(x); // 5 (unchanged)

// Object - pass by reference
function rename(person) { person.name = "Bob"; }
const user = { name: "Alice" };
rename(user);
console.log(user.name); // Bob (changed)

In JavaScript, functions are first-class citizens. This means functions can be assigned to variables, passed as arguments to other functions, and returned as values from other functions, just like any other value (number, string, object).

const greet = function(name) { return "Hello, " + name; };
console.log(greet("Alice")); // Hello, Alice

function run(fn) { return fn("Bob"); }
console.log(run(greet)); // Hello, Bob

A higher-order function is a function that either takes one or more functions as arguments, or returns a function as its result. Built-in examples include map, filter, and reduce.

const numbers = [1, 2, 3, 4];
const doubled = numbers.map(n => n * 2);
console.log(doubled); // [2, 4, 6, 8]

function multiplier(factor) {
  return n => n * factor;
}
const triple = multiplier(3);
console.log(triple(5)); // 15

A callback function is a function passed as an argument to another function, which then calls it at the right time. Callbacks are the foundation of asynchronous JavaScript.

function fetchData(callback) {
  setTimeout(() => {
    callback("Data loaded");
  }, 1000);
}

fetchData(result => console.log(result)); // Data loaded (after 1s)

A closure is a function that remembers the variables from its outer (enclosing) scope even after the outer function has finished executing. Closures are used to create private variables and to maintain state.

function makeCounter() {
  let count = 0;
  return function() {
    count++;
    return count;
  };
}

const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

Hoisting is JavaScript's default behavior of moving declarations to the top of their scope before code runs. Function declarations are fully hoisted. Variables declared with var are hoisted but initialized as undefined. Variables declared with let and const are hoisted but not initialized (they are in the Temporal Dead Zone until the declaration line).

console.log(sayHello()); // "Hello!" - function is fully hoisted

function sayHello() { return "Hello!"; }

console.log(x); // undefined - var hoisted, value is not
var x = 10;

// console.log(y); // ReferenceError - let is in TDZ
let y = 20;

The Temporal Dead Zone (TDZ) is the time between entering a scope and the point where a let or const variable is declared. Accessing the variable during this period throws a ReferenceError. This is unlike var, which returns undefined before its declaration.

// TDZ starts here for 'name'
console.log(name); // ReferenceError: Cannot access 'name' before initialization
let name = "Alice"; // TDZ ends here

An IIFE is a function that is defined and immediately called. It runs as soon as it is created. IIFEs are useful for creating a private scope, avoiding global variable pollution, and running initialization code once.

(function() {
  const message = "I run immediately!";
  console.log(message);
})();

// Arrow function IIFE
(() => {
  console.log("Arrow IIFE");
})();

Currying is a technique where a function with multiple arguments is transformed into a sequence of functions, each taking one argument. It allows partial application of a function.

// Normal function
function add(a, b) { return a + b; }

// Curried version
function curriedAdd(a) {
  return function(b) {
    return a + b;
  };
}

const addFive = curriedAdd(5);
console.log(addFive(3));  // 8
console.log(addFive(10)); // 15

Recursion is when a function calls itself to solve a smaller version of the same problem. Every recursive function needs a base case to stop the recursion and avoid an infinite loop. It is useful for tasks like tree traversal, factorial, and Fibonacci sequences.

function factorial(n) {
  if (n <= 1) return 1;        // base case
  return n * factorial(n - 1); // recursive call
}

console.log(factorial(5)); // 120
// 5 * 4 * 3 * 2 * 1 = 120

All three methods let you set the value of this for a function:

  • call() — invokes the function immediately, arguments passed one by one.
  • apply() — invokes the function immediately, arguments passed as an array.
  • bind() — returns a new function with this bound, does not call it immediately.
function greet(city, country) {
  return this.name + " from " + city + ", " + country;
}
const person = { name: "Alice" };

console.log(greet.call(person, "Paris", "France"));
console.log(greet.apply(person, ["Paris", "France"]));

const boundGreet = greet.bind(person, "Paris", "France");
console.log(boundGreet()); // called later

Debugging is the process of finding and fixing errors (bugs) in your code. A bug can be a typo, incorrect logic, or unexpected behavior. Developers use tools like the browser Console, breakpoints, and console.log() to inspect and trace the flow of code until the issue is found and corrected.

function add(a, b) {
  return a - b; // bug: should be +
}
console.log(add(3, 4)); // -1 (wrong, expected 7)

// After fix:
function add(a, b) {
  return a + b;
}
console.log(add(3, 4)); // 7

Chrome DevTools is a set of developer tools built into the Chrome browser. Open it with F12 or right-click and select Inspect. The key panels for JavaScript debugging are:

  • Console — view errors, warnings, and log messages; run JavaScript interactively.
  • Sources — view source files, add breakpoints, and step through code line by line.
  • Network — inspect HTTP requests and responses.

A breakpoint pauses code execution at a specific line so you can inspect variables and program state. You can add one by clicking a line number in the DevTools Sources panel, or by writing debugger; directly in your code.

function calculateTotal(price, tax) {
  debugger; // pauses here when DevTools is open
  return price + tax;
}
calculateTotal(100, 18);
  • console.log() — prints general information (white/default styling).
  • console.warn() — prints a warning message with a yellow background. Use for non-critical issues.
  • console.error() — prints an error message with a red background and a stack trace. Use for critical failures.
console.log("User loaded");       // general info
console.warn("Cache is almost full"); // warning
console.error("Failed to fetch data"); // error with stack trace
  • SyntaxError — invalid code that cannot be parsed (e.g., missing bracket).
  • ReferenceError — accessing an undeclared variable.
  • TypeError — wrong type operation (e.g., calling a non-function).
  • RangeError — value outside allowed range (e.g., negative array length).
  • URIError — malformed URI in functions like decodeURIComponent().
  • InternalError — engine-level error such as too much recursion.

A ReferenceError occurs when you try to access a variable that does not exist. A TypeError occurs when a variable exists but you try to use it in a way that its type does not support.

// ReferenceError
console.log(foo); // ReferenceError: foo is not defined

// TypeError
let num = 42;
num(); // TypeError: num is not a function

let obj = null;
console.log(obj.name); // TypeError: Cannot read properties of null

JavaScript stores numbers as 64-bit floating point values (IEEE 754). In this format, some decimal fractions cannot be represented exactly in binary, leading to tiny rounding errors.

console.log(0.1 + 0.2); // 0.30000000000000004

// Fix: use toFixed() to round
console.log((0.1 + 0.2).toFixed(1)); // "0.3"

NaN (Not a Number) is the result of an invalid numeric operation. Use Number.isNaN() to check for it — it is more reliable than the global isNaN(), which coerces its argument first.

console.log(0 / 0);          // NaN
console.log(Number("abc"));  // NaN

console.log(Number.isNaN(NaN));     // true
console.log(Number.isNaN("abc"));   // false (no coercion)

console.log(isNaN("abc"));  // true (coerces first — less reliable)

parseInt() parses a string and returns a whole integer, dropping any decimal part. parseFloat() parses a string and returns a floating point number, preserving the decimal part.

console.log(parseInt("3.99px"));   // 3   (integer only)
console.log(parseFloat("3.99px")); // 3.99 (keeps decimals)

console.log(parseInt("abc"));      // NaN
console.log(parseFloat("abc"));    // NaN

BigInt is a numeric type that can represent integers larger than Number.MAX_SAFE_INTEGER (253 - 1). You use it by appending n to a number. It is useful in cryptography, large ID values, and scientific computing.

const big = 9007199254740991n + 1n;
console.log(big); // 9007199254740992n

// Cannot mix with regular numbers
console.log(10n + 5); // TypeError

Infinity is a special numeric value representing a number greater than any other number. It is produced by dividing a positive number by zero or by exceeding the maximum representable number. -Infinity is its negative counterpart.

console.log(1 / 0);   // Infinity
console.log(-1 / 0);  // -Infinity
console.log(Infinity + 1); // Infinity

console.log(Number.isFinite(Infinity)); // false
console.log(Number.isFinite(100));      // true

Use the Intl.NumberFormat API to format numbers according to a locale's conventions, including currencies and percentages.

const num = 1234567.89;

// US format
console.log(new Intl.NumberFormat("en-US").format(num));
// 1,234,567.89

// Currency
console.log(new Intl.NumberFormat("en-US", {
  style: "currency", currency: "USD"
}).format(num));
// $1,234,567.89

JavaScript can be written in HTML files using <script> tags, in external .js files, in the browser console, on the server-side with Node.js, in mobile apps using React Native or Ionic, in desktop apps using Electron, on IoT devices, and in cloud functions like AWS Lambda.

A value is a specific piece of data such as a number or string. A variable is a named storage location in a program that holds a value, which can be changed during execution. In other words, a variable represents a value that may vary throughout the program.

A comment in JavaScript is text ignored by the browser, used to add notes for developers. Use // before text for a single-line comment. Use /* ... */ to wrap text for a multi-line comment.

In non-strict mode, JavaScript allows implicit global variable creation without var/let/const, octal integer literals, assignment to read-only properties without errors, extra function arguments, and use of reserved words as variable names. This can lead to unexpected bugs and is generally not recommended.

A statement is a single instruction executed by the computer, such as a variable assignment, a conditional expression, a loop, or a function call. Statements are written in specific syntax and combined to create programs that perform tasks.

A single-line statement expresses one complete action in a single line, such as a variable assignment or a function call. In JavaScript, statements typically end with a semicolon, though it is often optional due to automatic semicolon insertion.

In JavaScript, a multi-line statement can be split across lines by enclosing the expression in parentheses or brackets, or by using a backslash at the end of each line. For example, long function arguments or chained method calls can naturally span multiple lines.

A code block is a section of code grouped together as a single unit, surrounded by curly braces {}. It contains one or more statements executed sequentially and is used in functions, loops, conditionals, and other control structures.

var is the oldest way to declare variables and has function scope. let and const were introduced in ES6 and have block scope. const is used for variables that will not be reassigned, while let is for variables that may change. Prefer const by default and let when reassignment is needed.

let and const have block-level scope while var has function-level scope. const cannot be reassigned after initialization while let and var can. var declarations are hoisted to the top of their scope, while let and const are not hoisted in the same way and will throw an error if accessed before declaration.

Use const by default for variables that should not change. Use let when you need to reassign a variable. Avoid var in modern JavaScript, as let and const are more predictable with block scoping and avoid the quirks of function-level hoisting.

The ++ operator increments a variable by 1 and the -- operator decrements it by 1. Used as a prefix (++x), the variable is modified before the expression is evaluated. Used as a postfix (x++), the current value is used first and then the variable is modified.

The remainder operator (%) returns the remainder of a division between two numbers. For example, 9 % 4 returns 1 because 4 goes into 9 twice with a remainder of 1. It is useful for checking divisibility and cycling through index values.

Output in JavaScript can be written using console.log() for the browser console, document.write() to write directly into an HTML document, innerHTML to set element content, window.alert() for a popup message box, and prompt() for a dialog box that can receive input.

A string literal is a fixed sequence of characters enclosed in quotes ('hello' or "hello") and is the preferred approach. A string object is created using the String() constructor (new String('hello')) and is a wrapper object around the primitive. String literals are more efficient and easier to work with, and direct comparison with === may behave differently for string objects.

The length property of a string returns the number of characters in that string. For example, 'Hello World'.length returns 11, including the space. The length property is read-only and cannot be used to change the string.

Use the split() method to convert a string to an array. It splits the string based on a specified separator and returns a new array. For example, 'Hello World'.split(' ') returns ['Hello', 'World']. Splitting by an empty string converts each character to an array element.

A string literal is enclosed in single or double quotes and represents a static string. A template literal (also called a template string) is enclosed in backticks and supports string interpolation using ${} syntax, making it easy to embed expressions and create multi-line strings.

padStart() adds padding characters to the beginning of a string until it reaches a target length, while padEnd() adds padding to the end. Both accept a target length and an optional padding character (default is a space). For example, '5'.padStart(3, '0') returns '005'.

indexOf() returns the index of the first occurrence of a value, or -1 if not found. includes() returns a boolean indicating whether the value is present. Use includes() for simple existence checks and indexOf() when you also need the position of the value.

indexOf() returns the index of the first occurrence of a value in a string or array, searching from the beginning. lastIndexOf() returns the index of the last occurrence, searching from the end. Both return -1 if the value is not found.

search() searches a string for a regex pattern and returns the index of the first match, or -1 if not found. match() returns an array of all matches or null if none are found. Use search() when you only need to know position, and match() when you need the matched substrings.

Implicit type conversion, also known as type coercion, is the automatic conversion of one data type to another by JavaScript during an operation. For example, adding a number to a string converts the number to a string and concatenates them. This can cause unexpected results if not understood.

Explicit type conversion, also known as type casting, is manually converting a value from one data type to another using built-in functions like parseInt(), parseFloat(), Number(), String(), or Boolean(). It gives developers full control over how types are converted.

There are three popup box types in JavaScript: alert() displays a message with an OK button, confirm() displays a message with OK and Cancel buttons and returns a boolean, and prompt() displays a message with a text input field and OK/Cancel buttons, returning the user's input.

The falsy values in JavaScript are: false, 0, empty string ('', "", ``), null, undefined, and NaN. Any other value is considered truthy, including 0n (BigInt zero), empty arrays ([]), and empty objects ({}).

A while loop checks the condition before executing the code block, so it may never run if the condition is initially false. A do-while loop always executes the code block at least once before checking the condition for the first time.

Cases in a switch statement are conditional blocks executed when the switch expression matches their value. Each case starts with the case keyword followed by a value and a colon, contains code to run for that match, and typically ends with break to prevent fall-through to the next case.

Scoping defines the rules that determine how variables and functions are accessed during runtime. Variables declared outside any function have global scope and are accessible everywhere. Variables declared inside a function have local scope, accessible only within that function.

JavaScript has global scope (variables accessible anywhere in the code), function/local scope (variables accessible only within the function where declared), and block scope (variables declared with let or const inside a block like if or for, accessible only within that block).

A function is a reusable block of code that performs a specific task. It can accept optional parameters and return an optional value. Functions in JavaScript are first-class objects, meaning they can be assigned to variables, passed as arguments, and returned from other functions.

Functional programming is a paradigm that emphasizes pure functions (same input always gives same output), immutability (data is not changed after creation), and higher-order functions (functions that take or return other functions). It leads to more predictable and testable code.

Generator functions are special functions defined with the function* keyword that can pause and resume during execution using the yield keyword. They return an iterator object and produce values one at a time on demand, making them useful for lazy iteration and asynchronous control flow.

Functions can be created using a function declaration (function foo() {}), a function expression (const foo = function() {}), an arrow function (const foo = () => {}), or the Function constructor (new Function(...)). Function declarations and expressions are most common.

A function expression defines a function as part of an expression, typically by assigning it to a variable. Unlike function declarations, function expressions are not hoisted and can only be called after their definition. They can be anonymous or named.

An anonymous function is a function without a name, used inline or as a callback. It is commonly passed as an argument to other functions like setTimeout, addEventListener, or array methods like map and filter. It is defined and used where it is needed, rather than declared separately.

A function declaration is defined with the function keyword, is hoisted to the top of its scope, and can be called before its declaration. A function expression assigns a function to a variable, is not hoisted, and cannot be called before it is defined.

The main difference is how the this keyword is handled. In a function expression, this is dynamically bound to the calling context. In an arrow function, this is lexically bound and inherits the this value from the surrounding scope where the arrow function is defined.

A parameter is a variable defined in a function's declaration as a placeholder for values to be passed in. An argument is the actual value supplied when the function is called. For example, in function add(a, b), a and b are parameters. In add(2, 3), 2 and 3 are arguments.

Callback hell is a situation in asynchronous programming where multiple nested callbacks create deeply indented, hard-to-read code. It arises when operations depend on each other's results, leading to a pyramid of nested functions that are difficult to debug and maintain.

setTimeout() executes a function once after a specified delay in milliseconds. It returns a timer ID that can be passed to clearTimeout(id) to cancel the scheduled execution before it fires. For example: const id = setTimeout(fn, 1000); clearTimeout(id);

setInterval() repeatedly executes a function at a fixed time interval in milliseconds. It returns an interval ID that can be passed to clearInterval(id) to stop the repetition. Use clearInterval inside a setTimeout or an event handler to stop after a certain time or event.

DRY stands for 'Don't Repeat Yourself.' It is a coding principle that encourages developers to avoid duplicating code by creating reusable and modular components. This reduces redundancy, improves readability, makes code easier to maintain, and reduces the risk of bugs from inconsistent duplicates.

Design patterns are proven, reusable solutions to commonly occurring problems in software design. Famous JavaScript design patterns include Singleton, Factory, Observer, Module, Constructor, Prototype, Adapter, Decorator, Command, and Iterator patterns.

console.log() displays data in a simple linear format, useful for printing single values or small groups. console.table() displays data in a formatted table, making it much easier to read arrays of objects with multiple properties. Use console.table when inspecting structured data.

In JavaScript, numbers are a primitive data type representing both integers and floating-point values. All numbers are stored as 64-bit floating-point (IEEE 754 double precision). Special values include NaN (not a number), Infinity, and -Infinity for invalid or extreme results.

The number type safely represents integers up to 2^53 - 1 (Number.MAX_SAFE_INTEGER). BigInt has no practical size limit and is created by appending n to an integer literal (123n) or using BigInt(). BigInt arithmetic always produces exact results without rounding, unlike number.

JavaScript represents numbers using the Number data type which handles integers, floating-point, and special values. It also supports hexadecimal (0xff), octal (0o77), and binary (0b1010) literals. All are stored internally as 64-bit floating-point values following the IEEE 754 standard.

toFixed(n) formats a number to n decimal places as a string. toString(base) converts a number to a string in the given base. valueOf() returns the primitive numeric value. parseInt() parses a string to an integer. parseFloat() parses a string to a float. isNaN() checks if a value is NaN.

The Date object represents a specific moment in time and provides methods to work with dates and times. It can be created with new Date() (current time), new Date(milliseconds), new Date(dateString), or new Date(year, month, day, hour, minute, second).

Use the toLocaleString() method with a locale string and options object. For example, number.toLocaleString('fr-FR') formats a number in French style. You can also use Intl.NumberFormat and Intl.DateTimeFormat APIs for more precise control over formatting across different locales.

DOM stands for Document Object Model. It is a programming interface for HTML documents that represents the page as a hierarchical tree of nodes. JavaScript uses the DOM to access and manipulate the document's structure, style, and content dynamically.

The DOM is needed so JavaScript can interact with and modify HTML elements, styles, and content on a web page. Without the DOM, JavaScript could not respond to user events, add or remove elements, or update the page dynamically, making interactive web applications impossible.

getElementById returns a single element by id. getElementsByTagName returns all elements with a given tag name. getElementsByClassName returns all elements with a specific class. querySelector returns the first element matching a CSS selector. querySelectorAll returns all matching elements as a NodeList.

A Node is any object in the DOM tree, including elements, text nodes, and comments. HTMLCollection is a live array-like collection of HTML elements returned by DOM methods like getElementsByTagName. An Element is a specific type of Node representing an HTML element with attributes and methods.

innerHTML retrieves or sets the HTML markup inside an element, including HTML tags. textContent retrieves or sets only the plain text content, ignoring HTML tags. Prefer textContent for plain text to avoid XSS security risks that can come from inserting unsanitized HTML.

Event bubbling is the process where an event triggered on an inner element propagates outward through each parent element up to the document root. Each ancestor's event handlers are triggered in sequence as the event 'bubbles up' the DOM tree. This is the default behavior in JavaScript.

Event capturing is the phase where an event starts at the outermost element (document root) and propagates inward toward the target element. It occurs before the bubbling phase. To listen in the capturing phase, pass true as the third argument to addEventListener.

Event bubbling is a bottom-up approach where events start at the target element and propagate outward to the root. Event capturing is a top-down approach where events start at the root and move inward to the target. By default, JavaScript uses the bubbling phase for event handlers.

innerHTML sets or gets the HTML markup content inside an element, replacing all child nodes. An attribute (like id, class, or href) is a characteristic of an HTML element accessed with getAttribute() or setAttribute(). innerHTML modifies content, while attributes modify element properties.

Use the element.style property to set CSS styles directly from JavaScript. For example, element.style.backgroundColor = 'red' and element.style.fontSize = '20px'. Use camelCase for CSS property names (e.g. backgroundColor instead of background-color).

An event in JavaScript is a signal sent by the browser indicating that something has happened, such as a user clicking a button, pressing a key, or a page finishing loading. Event handlers are functions assigned to respond to these events and execute code accordingly.

event.preventDefault() prevents the browser from executing its default behavior for an event. For example, it can stop a link from navigating to another page, prevent a form from submitting, or stop a checkbox from being checked. It does not stop event propagation.

Mouse events include click, dblclick, mousedown, mouseup, mousemove, mouseover, and mouseout. Keyboard events include keydown, keypress, and keyup. There are also focus events (focus, blur), and form events (submit, reset, change). Each fires based on user interaction with the corresponding input.

An event listener is a function attached to a DOM element that waits for a specific event and executes code when it occurs. Add one using element.addEventListener(eventType, handler). Unlike inline event handlers, you can attach multiple listeners to the same element for the same event.

Use element.removeEventListener(eventType, handler) to remove a previously added listener. The exact same function reference used when adding must be passed - anonymous functions cannot be removed this way. For example: element.removeEventListener('click', handleClick).

Use document.createElement(tagName) to create a new element, set its properties (id, className, textContent), then attach it to the DOM with parentElement.appendChild(newElement) or parentElement.insertBefore(newElement, referenceElement).

BOM (Browser Object Model) objects represent the browser environment. Window is the top-level global object. History manages browsing history. Navigator provides browser and OS information. Screen gives display information. Location represents the current URL. LocalStorage provides persistent client-side key-value storage.

A JavaScript engine is a program that reads and executes JavaScript code. Famous engines include V8 (Google Chrome, Node.js), SpiderMonkey (Firefox), JavaScriptCore (Safari), and Chakra (Internet Explorer, early Edge). These engines interpret, compile, and optimize JavaScript at runtime.

The call stack is a data structure that tracks active function calls. When a function is called, its execution context is pushed onto the stack. When it returns, it is popped off. JavaScript is single-threaded, so only one function runs at a time, following the call stack order.

An execution context is the environment in which JavaScript code runs. It includes the variable environment (variables and function declarations), the scope chain, and the value of this. A new execution context is created for each function call and for the global scope.

When a function is called, a new execution context is created and pushed onto the call stack. The currently running context is always at the top of the stack. When a function returns, its execution context is popped off and control returns to the previous context below it on the stack.

Heap memory is the region of memory where dynamically allocated objects are stored at runtime. Objects, arrays, and functions are created in the heap. The JavaScript engine's garbage collector manages heap memory by automatically reclaiming memory from objects that are no longer reachable.

A compiler is a program that translates the entire source code of a program from a high-level language into machine code or bytecode all at once before execution. The resulting output is an executable that can be run independently, generally producing faster execution than interpretation.

An interpreter is a program that reads and executes source code line by line at runtime without compiling it first. It translates and runs each statement immediately, making debugging easier since errors are caught as they occur. JavaScript was traditionally interpreted.

A compiler translates the entire source code into an executable before running, resulting in faster execution. An interpreter executes code line by line at runtime, which makes it easier to test and debug. Modern JavaScript engines use JIT (Just-In-Time) compilation, combining both approaches.

An execution context contains the variable environment (all declared variables and functions), the scope chain (references to outer scopes), and the this keyword. There are two types: the global execution context (created when the script starts) and function execution contexts (created for each function call).

The variable environment is the part of an execution context that stores all variable declarations, function declarations, and function arguments for the current scope. It is set up during the creation phase, which is when hoisting occurs for var declarations and function definitions.

The scope chain is the hierarchical series of scopes that JavaScript searches when resolving a variable reference. It starts from the current local scope and moves outward through each enclosing scope until it finds the variable or reaches the global scope. Closures preserve the scope chain.

The this keyword refers to the object that owns the currently executing code. In a method, this is the object the method belongs to. In a global function, this is the global object (window). In arrow functions, this is inherited from the enclosing lexical scope. It can be set explicitly with call(), apply(), or bind().

The creation phase is the first step when an execution context is set up: variables are hoisted, functions are stored, and the scope chain is established. The code phase (execution phase) follows, where JavaScript executes statements line by line in order, assigning values to variables.

In strict mode, the this keyword inside a regular function that is not called as a method is undefined, rather than the global object. This prevents accidental access to global properties and helps catch errors where this is used without a proper object context.

Primitives (numbers, strings, booleans, null, undefined, Symbol, BigInt) are immutable and stored by value - copying a primitive creates an independent copy. Objects (arrays, functions, objects) are mutable and stored by reference - copying an object variable copies the reference, not the data.

Normal copy means assigning a variable to another variable. For primitives, this creates an independent copy of the value. For objects and arrays, it copies the reference, so both variables point to the same data in memory. Changing the object through either variable affects both.

A shallow copy creates a new object with the same top-level properties, but nested objects still share the same references. Use the spread operator ({...original} or [...original]) or Object.assign({}, original) for a shallow copy. Changes to nested properties affect both the original and the copy.

A deep copy creates a completely independent clone of an object, including all nested objects. Use JSON.parse(JSON.stringify(obj)) for simple objects (no functions or special types), the spread operator for one-level nesting, or a library like Lodash's cloneDeep() for complex nested structures.

Objects in JavaScript are non-primitive types stored in heap memory. Variables that hold objects actually store a reference (pointer) to the object's location in the heap, not the object itself. Primitives, on the other hand, are stored directly by value.

Destructuring is a syntax for extracting values from arrays or properties from objects into distinct variables. For arrays: const [a, b] = [1, 2]. For objects: const { name, age } = person. It makes code more concise and readable when working with complex data structures.

Destructuring cannot directly reverse an entire array, but you can swap two variables in a single line: [a, b] = [b, a]. This is a common use of array destructuring for value swapping. To reverse a full array, use Array.reverse() (mutating) or [...arr].reverse() (non-mutating).

A function can return multiple values by returning an array or an object. Use array destructuring: const [a, b] = getValues(). Use object destructuring: const { a, b } = getValues(). Returning an object is often clearer as the variable names are explicit.

Array destructuring uses square brackets and extracts values by position: const [a, b] = arr. Object destructuring uses curly braces and extracts values by property name: const { x, y } = obj. Both support renaming, default values, and rest patterns.

Use nested square brackets to match the nesting structure: const [a, b, [c, d]] = [1, 2, [3, 4]]. This assigns 1 to a, 2 to b, 3 to c, and 4 to d. The nested pattern must mirror the shape of the array being destructured.

Set default values using the = operator in the destructuring pattern: const [a = 1, b = 2] = arr for arrays and const { foo = 'default', bar = 0 } = obj for objects. The default is used only when the value is undefined.

Object destructuring is a technique to extract specific properties from an object and assign them to variables in a concise way. Using curly braces on the left side of an assignment, you can unpack named properties directly: const { name, age } = person.

Match variable names to property names: const { name, age } = person. Rename with a colon: const { name: fullName } = person. Set defaults: const { age = 25 } = person. Combine these: const { name: n = 'unknown', age: a = 0 } = person.

Use the rest operator (...) in destructuring to collect remaining items: const [first, ...rest] = arr collects all but the first element into rest. For objects: const { a, ...others } = obj. The rest variable must always be the last element in the pattern.

Use the colon syntax in object destructuring to create an alias: const { originalName: aliasName } = object. The property originalName is extracted from the object and assigned to the variable aliasName. This avoids naming conflicts or enables more descriptive variable names.

Use the = operator for each property: const { a = 10, b = 'hello' } = obj. If the property is missing or undefined in the object, the default value is used instead. You can combine renaming and defaults: const { name: n = 'unknown' } = obj.

Nested object destructuring extracts properties from nested objects using a matching nested curly brace syntax: const { name, address: { city } } = person. This accesses city from person.address in one statement, avoiding verbose property chain access.

Use destructuring syntax directly in the function parameter list: function greet({ name, age }) {}. When the function is called with an object, the specified properties are automatically extracted. You can also set defaults: function greet({ name = 'Guest', age = 0 } = {}) {}.

The spread operator (...) expands an iterable such as an array, string, or object into individual elements. It is used to copy arrays/objects, merge multiple arrays, spread array elements as function arguments, and convert iterables to arrays. It provides a clean, concise syntax for these operations.

Use the spread operator inside brackets or braces to create a shallow copy: const copy = [...originalArray] or const copy = {...originalObject}. This creates a new container with the same top-level values, but nested objects still share the same reference as the original.

Use the spread operator to expand each array inside a new array literal: const combined = [...arr1, ...arr2, ...arr3]. Each array's elements are expanded in order and merged into the single new array. You can also mix spread arrays with individual values.

Use the spread operator inside square brackets: const arr = [...str]. This expands the string into individual characters. For example, [...'hello'] returns ['h', 'e', 'l', 'l', 'o']. This is equivalent to str.split('').

Use the spread operator to expand an array as individual function arguments: myFunction(...args). For example, if args = [1, 2, 3], then myFunction(...args) is equivalent to myFunction(1, 2, 3). This is a cleaner alternative to Function.prototype.apply.

The rest parameter (...) allows a function to accept an indefinite number of arguments by collecting them into an array. It must be the last parameter in the function signature. For example, function sum(...nums) {} collects all passed arguments into the nums array.

Both use the ... syntax but in opposite contexts. The spread operator is used to expand an iterable into individual elements (in function calls or array/object literals). The rest operator is used to collect multiple individual elements into an array (in function parameters or destructuring).

Define the function with the rest parameter as the last argument: function myFunc(...args) {}. All extra arguments passed to the function are collected into the args array. You can then use any array methods on args to process the variable inputs.

Short circuiting is the behavior where logical operators stop evaluating as soon as the result is determined. With &&, if the first operand is falsy, the second is skipped. With ||, if the first operand is truthy, the second is skipped. This enables concise conditional expressions.

The || (OR) operator returns the first truthy value, treating falsy values like 0, empty string, and false as triggers for the fallback. The ?? (nullish coalescing) operator only falls back when the left side is null or undefined, so it correctly handles 0, false, and empty string as valid values.

The nullish coalescing operator (??) returns the right-hand operand when the left-hand operand is null or undefined, otherwise it returns the left-hand operand. It provides default values specifically for null/undefined, unlike || which also triggers on any falsy value.

Optional chaining (?.) allows safe access to properties of potentially null or undefined objects. Instead of throwing a TypeError, it short-circuits and returns undefined. Benefits include cleaner code with fewer null checks, reduced risk of runtime errors when accessing deeply nested properties.

An array is a data structure that stores an ordered collection of elements in a single variable. Elements can be of any type and are accessed by their zero-based numeric index. Arrays are defined using square brackets: const arr = [1, 'hello', true].

Arrays have a length property returning the number of elements, support zero-based index access, are mutable (elements can be added, removed, or changed), can hold mixed data types, and are technically a specialized type of object with numeric keys and special built-in methods.

An array literal uses square bracket notation (const arr = [1, 2, 3]) and is the preferred, concise approach. An array object uses the Array constructor (new Array(1, 2, 3)). Both produce the same result, but array literals are simpler, more readable, and avoid ambiguity.

An array index is the zero-based numeric position of an element. It is used to access, update, insert, or delete specific elements: arr[0] accesses the first element. Indexes enable efficient random access to any element and are fundamental for iterating and manipulating arrays.

sort() works on all element types but converts them to strings by default, which can produce unexpected results for numbers (e.g. [10, 9, 2] sorts as [10, 2, 9]). Always provide a comparison function for non-string data, such as (a, b) => a - b for ascending numeric sort.

Pass a comparison function whenever the default lexicographic sorting is not appropriate. For numbers, dates, or objects, provide a custom comparator. For example, arr.sort((a, b) => a - b) for ascending numeric sort and arr.sort((a, b) => b.name.localeCompare(a.name)) for descending string sort on objects.

push() adds elements to the end of an array and unshift() adds to the beginning. Both return the new array length. pop() removes and returns the last element, while shift() removes and returns the first element. push/pop operate at the end; unshift/shift operate at the beginning.

slice(start, end) returns a new array with elements from start to end (exclusive) without modifying the original array. splice(index, deleteCount, ...items) modifies the original array by removing, replacing, or inserting elements in place, and returns the removed elements.

forEach() is an array method that calls a function for each element but does not support break or continue. The for...of loop works with any iterable (arrays, strings, Maps, Sets) and supports break and continue for controlling iteration flow.

map() creates a new array by transforming each element using a callback. filter() creates a new array with only the elements that pass a test. reduce() accumulates all elements into a single output value. None modify the original array. All three are common tools in functional programming.

some() returns true if at least one element passes the given test, short-circuiting once a truthy result is found. every() returns true only if all elements pass the test, short-circuiting once a falsy result is found. some() is like an array-wide OR check; every() is like an AND check.

flat(depth) creates a new array with nested arrays concatenated up to the specified depth, default is 1. flatMap() first maps each element using a callback, then flattens the result by one level. flatMap(fn) is equivalent to arr.map(fn).flat(1) but more efficient.

An object is a data structure that stores key-value pairs, where keys are strings (or Symbols) and values can be any type. Objects can also have methods (functions as values). They are created using object literals ({}) or constructor functions and are the foundation of OOP in JavaScript.

An object literal ({}) directly creates an object with a concise syntax and is preferred for simple cases. Using new with a constructor function creates objects programmatically and supports inheritance patterns with prototype chains. ES6 classes provide cleaner syntax for the constructor approach.

Dot notation (obj.property) is cleaner and used for known, fixed property names. Bracket notation (obj['property'] or obj[variable]) allows dynamic property access using variables or expressions, and is required for property names with special characters, spaces, or names stored in variables.

Object.keys(obj) returns an array of the object's own enumerable property names. Object.values(obj) returns an array of the property values. Object.entries(obj) returns an array of [key, value] pairs. These methods are useful for iterating over or transforming object data.

A Set is a built-in data structure that stores unique values of any type in insertion order. Unlike arrays, Sets automatically ignore duplicate values. Key methods include add(), delete(), has(), clear(), and the size property. Sets are ideal for deduplication and membership checks.

WeakSet is a collection that stores only objects and holds weak references to them, meaning stored objects can be garbage collected if no other references exist. WeakSets are not iterable, have no size property, and are useful for tracking object presence without preventing garbage collection.

A Set is iterable, so you can loop over it directly: for (const value of mySet) { console.log(value); }. You can also iterate over mySet.values() or use mySet.forEach(value => console.log(value)). All methods iterate in insertion order.

Convert a Set to an array using the spread operator: const arr = [...mySet], or using Array.from(): const arr = Array.from(mySet). Both produce a new array containing all unique Set values in insertion order.

A Map is a built-in data structure that stores key-value pairs where keys can be of any type, not just strings. Maps maintain insertion order, have a size property, and provide set(), get(), has(), and delete() methods. They are more flexible than plain objects for key-value storage.

WeakMap is a collection of key-value pairs where keys must be objects and are held weakly. When a key object has no other references, it can be garbage collected and the WeakMap entry is removed automatically. WeakMaps are not iterable and are useful for private data or caching.

Chaining in Map means calling multiple map.set() calls in a single expression since set() returns the Map itself. For example: new Map().set('a', 1).set('b', 2).set('c', 3) creates a Map with three entries in one statement. This pattern makes initialization more concise.

In a Map, arrays are compared by reference, not by value. Two separate arrays with the same content are treated as different keys because they are different objects. So map.set([1,2], 'x') and map.set([1,2], 'y') create two separate entries. Only the same array object can retrieve its entry.

Convert a Map to an array of [key, value] pairs using the spread operator: const arr = [...myMap], or Array.from(myMap). Use [...myMap.keys()] for just the keys, or [...myMap.values()] for just the values.

If the array contains [key, value] pairs, pass it directly to the Map constructor: const map = new Map([[key1, val1], [key2, val2]]). If the array has a different structure, use reduce() to transform it into [key, value] pairs first.

Use Object.entries() with the Map constructor: const map = new Map(Object.entries(obj)). Object.entries() returns an array of [key, value] pairs from the object, which is the exact format the Map constructor accepts.

Use map.forEach((value, key) => {}) to iterate with a callback. Use for (const [key, value] of map) {} with a for...of loop and destructuring. Both iterate over all key-value pairs in insertion order.

OOP (Object-Oriented Programming) in JavaScript is a paradigm that organizes code around objects that contain both data (properties) and behavior (methods). It promotes code reuse through inheritance, hides implementation details through encapsulation, and models real-world entities as objects.

The 6 OOP principles are: Encapsulation (bundling data and methods, hiding internals), Abstraction (exposing only essential features), Inheritance (child classes reuse parent behavior), Polymorphism (objects of different types used interchangeably), Composition (building from smaller objects), and Interface (defining interaction contracts).

A Class is a blueprint for objects. An Object is an instance with specific state. Encapsulation hides internal implementation details behind a public interface (e.g. a bank account exposes deposit/withdraw but hides balance logic). Abstraction focuses on what something does (e.g. a play button). Inheritance lets child classes reuse parent behavior. Polymorphism lets different object types be used through a common interface.

Inheritance in JavaScript works through the prototype chain. When you access a property, JavaScript looks up the chain until it finds it or reaches null. Use Object.create(parent) to inherit from a prototype, constructor functions with prototype assignment, or ES6 class with extends and super().

Prototypal inheritance is a mechanism where objects inherit properties and methods directly from other objects through the prototype chain. Each object has an internal [[Prototype]] link. If a property is not found on the object, JavaScript searches up the prototype chain until it finds it or reaches null.

Prototypal inheritance can be achieved using Object.create(parent) to set a prototype, using constructor functions with Child.prototype = Object.create(Parent.prototype), or using ES6 class with extends keyword. The class syntax is the most readable and is syntactic sugar over prototype-based inheritance.

A constructor function is a function used with the new keyword to create and initialize objects. It is named with an uppercase letter by convention. When called with new, a new object is created, this is bound to it, properties are assigned, and the object is returned automatically.

ES6 classes provide a cleaner, more familiar syntax for creating objects and implementing inheritance in JavaScript. They use the class keyword to define blueprints, constructor() for initialization, and the extends keyword with super() for inheritance. Internally, they still use prototypal inheritance.

Object.create(proto) creates a new object with its [[Prototype]] set to the specified proto object. The new object inherits all properties and methods from its prototype. It is a foundational way to implement prototypal inheritance without using constructor functions or classes.

The prototypal chain is the series of linked [[Prototype]] references that JavaScript traverses when looking up a property or method. It starts at the object itself, then moves to its prototype, then to the prototype's prototype, and so on until Object.prototype (whose [[Prototype]] is null).

Getters (get keyword) and setters (set keyword) in ES6 classes are special methods that control access to object properties. A getter retrieves a value and a setter updates it. They allow validation, computed values, and encapsulation. Access them like regular properties: obj.name.

If a property and its getter/setter share the same name, accessing the property calls the getter, which tries to access the same property, which calls the getter again, creating infinite recursion. This results in a 'Maximum call stack size exceeded' error. Use a backing property with a different name, often prefixed with an underscore.

A static method is defined with the static keyword inside a class and belongs to the class itself rather than to any instance. It is called directly on the class (MyClass.myMethod()) without needing to create an instance. Static methods are useful for utility functions related to the class.

With constructor functions: call Parent.call(this) and set Child.prototype = Object.create(Parent.prototype). With ES6 classes: use class Child extends Parent and call super() in the constructor. With Object.create: create child = Object.create(parent) and add properties to the child object.

Use closures inside constructor functions to create private variables and expose only getter/setter methods. In ES6 classes, use the # prefix for private fields (e.g. #name) to restrict access to within the class body. Convention-based 'protection' uses an underscore prefix to signal internal-only usage.

Use the module pattern with an IIFE to create a closure where private variables and functions are inaccessible from outside. In ES6 classes, use the # prefix syntax for truly private fields and methods that cannot be accessed outside the class body.

Method chaining allows calling multiple methods in a single expression on the same object. Implement it by returning this at the end of each method in an ES6 class. For example: obj.add(5).subtract(3) works when both add() and subtract() return this.

Synchronous code runs line by line in a single thread, blocking execution until each operation completes. Asynchronous code allows other operations to run while waiting for slow tasks like network requests or timers. Asynchronous patterns include callbacks, Promises, and async/await.

AJAX (Asynchronous JavaScript and XML) is a technique for making asynchronous HTTP requests from a browser to a server without reloading the entire page. It enables dynamic content updates. Modern implementations use JSON rather than XML, and the Fetch API or XMLHttpRequest to make requests.

An API (Application Programming Interface) defines how software components interact. SOAP uses XML with strict contracts. REST uses HTTP methods (GET, POST, PUT, DELETE) for CRUD on resources. A Request is a client message to the server. A Response is the server's reply. Request Body contains payload data. Query Params pass extra info in the URL. JSON and XML are common data formats.

Server-client architecture separates a web app into a server (data storage and logic) and a client (user interface). JavaScript on the client makes HTTP requests to the server, which processes them and returns data. This enables dynamic, data-driven web applications without full page reloads.

A Promise represents the eventual success or failure of an asynchronous operation. The fetch() function makes HTTP requests and returns a Promise that resolves to a Response object. Together, they enable clean asynchronous network requests using .then()/.catch() or async/await.

Use .then(result => {}) on a Promise to handle fulfillment and .catch(error => {}) for rejections. Alternatively, use async/await with a try/catch block for more readable code. Both approaches allow you to work with the resolved value once the asynchronous operation completes.

Use the .catch() method after .then() to handle rejected Promises: promise.then(...).catch(error => {}). With async/await, wrap the await in a try/catch block. Always handle rejections to avoid unhandled promise rejection warnings and to gracefully recover from errors.

Create a Promise using new Promise((resolve, reject) => {}). Call resolve(value) when the asynchronous operation succeeds and reject(error) when it fails. Chain .then() to handle the resolved value and .catch() to handle errors.

async/await is syntax that makes asynchronous code look synchronous. Mark a function with async to make it return a Promise, then use await before a Promise to pause execution until it resolves. Use try/catch to handle errors. It is built on top of Promises and makes async code easier to read.

An async function always returns a Promise. The explicit return value becomes the resolved value of that Promise. Access it using await (inside another async function) or .then(). For example: const result = await myAsyncFn() or myAsyncFn().then(result => {}).

Use Promise.all([p1, p2, p3]) to run multiple Promises concurrently. It returns a new Promise that resolves when all input Promises resolve, providing an array of results. If any Promise rejects, Promise.all() rejects immediately with that error.

Wrap potentially failing code in a try block. If an error is thrown, execution jumps to the catch block where you handle the error. The optional finally block always runs regardless of success or failure, making it ideal for cleanup tasks like closing connections.

Promise.race() resolves or rejects as soon as the first Promise settles. Promise.allSettled() waits for all Promises to settle and returns an array of outcome objects (with status, value or reason) regardless of success or failure. Promise.any() resolves with the first fulfilled Promise, or rejects with AggregateError if all fail.

A module is an independent, reusable piece of code that encapsulates related functionality in its own file scope. ES6 modules use the import and export keywords to share functionality between files, enabling better code organization, avoiding global scope pollution, and explicit dependency management.

Export items using the export keyword: export const name = ... or export default myFunction. Import them with import: import { name } from './module.js' for named exports, or import myFunction from './module.js' for default exports. Use import * as module from './module.js' for all exports.

Polyfilling is adding JavaScript code that emulates newer features in older browsers that don't support them natively. A polyfill detects if a feature is missing and provides a fallback implementation, ensuring cross-browser compatibility without requiring users to update their browsers.

Transpiling converts modern JavaScript code (e.g. ES6+) into an equivalent older version (e.g. ES5) that is compatible with older browsers. Tools like Babel handle this automatically. Transpiling converts syntax like arrow functions and classes, while polyfilling adds missing APIs.

Polyfilling adds new API functionality to older environments by implementing missing features in JavaScript code (e.g. adding Array.from to older browsers). Transpiling converts modern syntax to equivalent older syntax (e.g. arrow functions to regular functions). Polyfilling is about features; transpiling is about syntax.

The DOM (Document Object Model) is a programming interface that represents an HTML page as a tree of objects. When a browser loads a page, it builds this tree from the HTML. JavaScript can then select, read, and modify any node in the tree to update what the user sees without reloading the page.

innerHTML reads or writes the HTML content inside an element, including any tags — so tags are parsed and rendered. textContent reads or writes plain text only; any HTML tags are treated as literal text and not rendered. Use textContent when inserting user-provided data to avoid XSS security risks.

querySelector returns the first element that matches a CSS selector, or null if nothing matches. querySelectorAll returns a NodeList of all matching elements (which may be empty). Both accept any valid CSS selector, making them more flexible than getElementById or getElementsByClassName.

Use document.createElement() to create a new element in memory, set its content and attributes, then use appendChild() (or insertBefore(), prepend(), append()) to attach it to an existing element in the DOM. The element only becomes visible on the page after it is attached to the document tree.

The modern way is to call element.remove() directly on the element you want to remove. The older approach is parent.removeChild(child), where you call removeChild on the parent element and pass the child to remove. Both produce the same result; element.remove() is simpler and does not require a reference to the parent.

The BOM (Browser Object Model) is a set of objects provided by the browser that let JavaScript interact with the browser environment beyond the page content. The root object is window, which also gives access to history, navigator, screen, location, and Web Storage APIs. Unlike the DOM, the BOM has no official standard but is consistently supported across all modern browsers.

Both store key-value pairs in the browser with the same API (setItem, getItem, removeItem, clear). The difference is lifetime: localStorage data persists indefinitely until explicitly cleared, surviving tab and browser restarts. sessionStorage data is cleared automatically when the browser tab is closed. Both are scoped to the current origin (protocol + domain + port).

Cookies are sent to the server automatically with every HTTP request and support an expiry date; they are limited to about 4 KB. localStorage is client-side only (never sent to the server), has a larger capacity of around 5 MB, and has no built-in expiry. Use cookies for server-side authentication and session data; use localStorage for client-only preferences and caching.

window.location is an object that contains the current page URL broken into parts: href (full URL), hostname, pathname, search (query string), and hash. You can read these to inspect the URL or set location.href to navigate the browser to a new page. location.reload() reloads the current page.

window.navigator is a BOM object that contains information about the user's browser and device. Common properties include userAgent (browser and OS identification string), language (user's preferred language), onLine (whether the browser has network access), and cookieEnabled. It is often used for browser detection and feature checks.

Event bubbling means that when an event fires on an element, it propagates upward through the DOM tree to all its ancestor elements. For example, clicking a button inside a div will also trigger any click listeners on that div and on the document. You can stop this with event.stopPropagation() inside the handler.

Event capturing is the opposite of bubbling. The event travels from the document root down to the target element before the target handles it. You opt into capturing by passing true as the third argument to addEventListener. The full event lifecycle is: capturing (top-down), target, then bubbling (bottom-up).

Event delegation is a pattern where a single event listener is attached to a parent element to handle events for all its children, relying on event bubbling. It is useful because it reduces the number of listeners (better performance for large lists), and it automatically handles dynamically added child elements without needing to attach new listeners each time.

onclick is an element property that can only hold one handler at a time — assigning a new function overwrites the previous one. addEventListener can attach multiple independent handlers for the same event without overwriting any of them. addEventListener also supports capturing phase listeners and can be removed with removeEventListener, making it the preferred and more flexible approach.

Call event.stopPropagation() inside an event handler to prevent the event from bubbling up (or capturing down) to ancestor elements. To also prevent any other listeners on the same element from running, use event.stopImmediatePropagation(). To prevent the browser's default action (like following a link), use event.preventDefault(). These methods can be combined as needed.