JavaScript has two main categories of data types:
String
: Textual data.Number
: Numeric values (including Infinity
and NaN
).Boolean
: true
or false
.null
: Represents the intentional absence of any object value.undefined
: A variable that has been declared but not yet assigned a value.Symbol
(ES6): A unique and immutable primitive.BigInt
(ES2020): Represents integers with arbitrary precision.Object
: A collection of key-value pairs. Arrays, functions, and other complex structures are objects.==
(Loose Equality): Compares two values for equality after performing type coercion. This can lead to unexpected results.===
(Strict Equality): Compares two values for equality without type coercion. It checks if both the value and the type are the same.Expression | == | === | Reason for Loose Equality |
---|---|---|---|
5 == "5" | true | false | String "5" is coerced to Number 5 . |
0 == false | true | false | false is coerced to Number 0 . |
null == undefined | true | false | This is a specific rule in the spec. |
Best Practice: Always use ===
to prevent bugs from unintended type conversions.
Feature | undefined | null |
---|---|---|
Type | Its type is undefined . | Its type is object (a historical bug). |
Meaning | Represents the absence of a value due to the system (e.g., unassigned variable, missing object property). | Represents the intentional absence of a value, explicitly set by the programmer. |
Example | let x; console.log(x); // undefined | let x = null; console.log(x); // null |
In a boolean context (like an if
statement), every value in JavaScript behaves as either true
or false
.
false
. There are only eight:
false
0
(zero)-0
(minus zero)0n
(BigInt zero)""
(empty string)null
undefined
NaN
(Not a Number){}
, []
, "0"
, "false"
, and functions.NaN
stands for "Not a Number". It's a special numeric value that represents an invalid or unrepresentable number, often the result of a failed mathematical operation.
A unique property of NaN
is that it is not equal to anything, including itself (NaN === NaN
is false
).
Therefore, you cannot check for it with equality operators. Use Number.isNaN()
instead.
console.log(NaN === NaN); // false console.log(Number.isNaN(NaN)); // true console.log(Number.isNaN(1 / 'a')); // true
Feature | var | let | const |
---|---|---|---|
Scope | Function-scoped | Block-scoped ({} ) | Block-scoped ({} ) |
Hoisting | Hoisted and initialized to undefined | Hoisted but not initialized (TDZ) | Hoisted but not initialized (TDZ) |
Reassignment | Can be reassigned | Can be reassigned | Cannot be reassigned |
Redeclaration | Can be redeclared in same scope | Cannot be redeclared in same scope | Cannot be redeclared in same scope |
The Temporal Dead Zone is a behavior in ES6 that occurs when accessing a let
or const
variable before its declaration. The period from the start of the block until the declaration is processed is the TDZ for that variable. Accessing the variable in the TDZ results in a ReferenceError
.
The typeof
operator returns a string indicating the type of the unevaluated operand.
Gotchas:
typeof null
returns "object"
. This is a long-standing bug.typeof []
returns "object"
. Arrays are objects.typeof function(){}
returns "function"
. Functions are first-class objects, but have their own type.JavaScript provides wrapper objects (String
, Number
, Boolean
) that allow you to call methods on primitive values. When you call a method like .toUpperCase()
on a string primitive, JavaScript temporarily wraps it in a String
object to access the method, and then discards the wrapper. This is called "autoboxing".
"use strict";
is a directive that enables "strict mode". Strict mode changes certain previously accepted "bad syntax" into real errors, provides more visibility into potential issues, and disables features that are confusing or poorly thought out. For example, in strict mode, assigning a value to an undeclared variable throws an error, and this
is undefined
in global functions.
Type coercion is the automatic or implicit conversion of values from one data type to another. This happens in operations like the loose equality ==
check or when using the +
operator with a string and a number.
The global object is an object that always exists in the global scope. In a web browser, it's the window
object. In Node.js, it's global
. In modern environments, globalThis
can be used to access the global object regardless of the context.
let x = 5;
, if (x > 0) { ... }
.5
, x + 10
, myFunction()
.
Every expression can be written as a statement, but not every statement can be an expression.Logical operators &&
(AND) and ||
(OR) are short-circuiting.
expr1 && expr2
: If expr1
is falsy, it returns expr1
without evaluating expr2
.expr1 || expr2
: If expr1
is truthy, it returns expr1
without evaluating expr2
.
This is often used for conditional logic or setting default values.The instanceof
operator checks if an object's prototype chain contains the prototype
property of a constructor. It's used to determine if an object is an instance of a particular class or constructor function.
Hoisting is JavaScript's default behavior of moving declarations to the top of the current scope (function scope for var
, block scope for let
/const
).
var
variables are hoisted and initialized with undefined
.let
and const
are hoisted but not initialized (creating the TDZ).function foo() {}
) are fully hoisted, meaning you can call them before they appear in the code.const foo = function() {}
) are not hoisted.Lexical scoping (or static scoping) means that the accessibility of variables is determined by the position of the variables and blocks of code at the time of writing. An inner function has access to the scope of its parent functions, regardless of where the function is executed. This is what makes closures possible.
A closure is a function that remembers the environment in which it was created. It's the combination of a function and the lexical environment within which that function was declared. This means an inner function has access to its outer function's variables and parameters, even after the outer function has returned.
function createCounter() { let count = 0; return function() { count++; console.log(count); }; } const counter = createCounter(); counter(); // 1 counter(); // 2
The value of this
is determined by how a function is called (its "call site").
this
refers to the global object (window
in browsers).this
is the global object in non-strict mode, undefined
in strict mode.obj.myMethod()
): this
is the object the method was called on (obj
).new MyClass()
): this
is the newly created instance.this
is lexically bound; it inherits this
from the parent scope.These methods are used to set the this
value of a function explicitly.
call(thisArg, arg1, arg2, ...)
: Invokes the function immediately with a given this
value and arguments provided individually.apply(thisArg, [argsArray])
: Invokes the function immediately with a given this
value and an array of arguments.bind(thisArg)
: Returns a new function with this
permanently bound to thisArg
. It does not invoke the function immediately.A higher-order function is a function that either takes another function as an argument, or returns a function, or both. Array methods like map
, filter
, and reduce
are common examples.
An IIFE is a function that is executed right after it is created. It's a common pattern for creating a local scope to avoid polluting the global namespace.
(function() { var privateVar = "I am private"; // ... })();
function foo() {}
. It's a statement, and it's hoisted completely.const foo = function() {}
. It's an expression that produces a value (the function). The variable (foo
) is hoisted according to its keyword (var
, let
, const
), but the function body is not.A pure function is a function that:
Function composition is the process of combining two or more functions to produce a new function. The output of one function becomes the input of the next.
const compose = (f, g) => (x) => f(g(x)); const toUpperCase = (str) => str.toUpperCase(); const exclaim = (str) => `${str}!`; const shout = compose(exclaim, toUpperCase); console.log(shout("hello")); // "HELLO!"
Default parameters (ES6) allow you to initialize named parameters with default values if no value or undefined
is passed.
function greet(name = "Guest") { console.log(`Hello, ${name}`); } greet(); // "Hello, Guest"
...
): Collects multiple elements into a single array. It must be the last parameter in a function definition.
function sum(...numbers) { return numbers.reduce((acc, curr) => acc + curr, 0); }
...
): Expands an iterable (like an array or string) into individual elements. Used in function calls, array literals, or object literals.
const arr = [1, 2, 3]; console.log(Math.max(...arr)); // 3
A generator function (function*
) can be paused and resumed, allowing it to produce a sequence of values over time. It uses the yield
keyword to produce a value. It returns a generator object, which is an iterator.
Recursion is a technique where a function calls itself to solve a problem. A recursive function must have a base case to stop the recursion and a recursive step that moves it closer to the base case.
A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action. It's the cornerstone of asynchronous programming in JavaScript.
JavaScript uses prototypal inheritance. Every object has a hidden [[Prototype]]
property that is either null
or references another object (its "prototype"). When you try to access a property on an object, if it's not found on the object itself, the JavaScript engine searches the object's prototype, then that prototype's prototype, and so on, until the property is found or the end of the chain (null
) is reached. This is called the prototype chain.
Every regular function (not arrow functions) has a prototype
property. This property is an object that will become the prototype of any new object instances created by that function when used as a constructor with the new
keyword.
prototype
: A property on a constructor function that defines the prototype for its instances.__proto__
: A property on an object instance that points to its prototype. It's a getter/setter for the internal [[Prototype]]
property. Object.getPrototypeOf()
is the standard way to access it.const obj = { key: 'value' };
function Person(name) { this.name = name; } const p = new Person('Al');
class Person { ... } const p = new Person('Al');
Object.create()
: const obj = Object.create(somePrototype);
Creates a new object with the specified prototype object.The new
keyword does four things:
[[Prototype]]
to be the prototype
of the constructor function.this
to the newly created object and executes the constructor function's code.A constructor function is a regular function used to create and initialize objects with the new
keyword. By convention, their names start with a capital letter.
'prop' in obj
: Returns true
if the property exists anywhere in the object's prototype chain.obj.hasOwnProperty('prop')
: Returns true
only if the property exists directly on the object itself (not on its prototype).Object.freeze(obj)
: Prevents adding, deleting, or changing properties. The most restrictive.Object.seal(obj)
: Prevents adding or deleting properties, but allows changing existing ones.Object.preventExtensions(obj)
: Prevents adding new properties, but allows deleting or changing existing ones.Every property on an object has a property descriptor that defines its characteristics. The main keys are:
value
: The value of the property.writable
: true
if the property's value can be changed.enumerable
: true
if the property will be listed in a for...in
loop.configurable
: true
if the property can be deleted or its descriptor can be changed.
You can get a descriptor with Object.getOwnPropertyDescriptor()
.Object.assign()
and the spread operator ...
do shallow copies)._.cloneDeep
from Lodash). A common but limited hack is JSON.parse(JSON.stringify(obj))
, which doesn't work for functions, undefined
, or circular references.Getters and setters are special methods that provide read and write access to an object's property. They allow you to run code when a property is accessed or modified.
const user = { _name: "John", get name() { return this._name; }, set name(value) { if (value.length > 2) this._name = value; } };
Object.create(proto)
creates a new object and sets its [[Prototype]]
to the proto
object. This is a direct way to implement prototypal inheritance.
Map
is a collection of key-value pairs where any value (both objects and primitive values) may be used as a key.
Differences from Object
:
Map
keys can be any type, including objects. Object
keys must be strings or symbols.Map
remembers the original insertion order of the keys.Map
has a .size
property.Map
is optimized for frequent additions and removals.A Set
is a collection of unique values. You can store any type of value, but each value can only appear once.
A WeakMap
is a Map
where the keys must be objects, and the references to the keys are held "weakly". This means that if there are no other references to a key object, it can be garbage collected. This is useful for associating data with an object without preventing it from being collected.
Destructuring is a syntax that allows you to "unpack" values from arrays or properties from objects into distinct variables.
// Object destructuring const { name, age } = { name: 'John', age: 34 }; // Array destructuring const [first, second] = [10, 20];
Template literals are strings enclosed in backticks (`
) that allow for:
${expression}
.\n
.Arrow functions provide a more concise syntax for writing functions. Key Characteristics:
(a, b) => a + b;
this
: They do not have their own this
. They inherit this
from the surrounding lexical scope.arguments
object: Use rest parameters (...args
) instead.new
.ES Modules provide a standardized module system for JavaScript.
export
: Used to export functions, objects, or primitives from a module.import
: Used to import live, read-only bindings to exports from another module.
Modules help organize code, avoid polluting the global namespace, and manage dependencies.A Promise
is an object representing the eventual completion (or failure) of an asynchronous operation. It allows you to associate handlers with an asynchronous action's eventual success value or failure reason. A Promise
exists in one of three states: pending
, fulfilled
, or rejected
.
Promise.all(iterable)
: Fulfills when all of the promises in the iterable have fulfilled, or rejects as soon as one of them rejects.Promise.race(iterable)
: Fulfills or rejects as soon as one of the promises in the iterable fulfills or rejects.Promise.allSettled(iterable)
: Fulfills after all of the given promises have either fulfilled or rejected. The result is an array of objects describing the outcome of each promise. Useful when you need to know the result of every promise, regardless of its status.async/await
is syntactic sugar built on top of Promises that makes asynchronous code look and feel more synchronous.
async
keyword: Placed before a function, it makes the function return a Promise
.await
keyword: Used inside an async
function, it pauses the function execution and waits for a Promise
to resolve.ES6 classes are syntactic sugar over JavaScript's existing prototype-based inheritance. They provide a much simpler and clearer syntax for creating objects and dealing with inheritance.
The super
keyword is used to call methods on an object's parent.
super()
calls the parent class's constructor.super.myMethod()
calls the parent's version of that method.A Symbol
is a unique and immutable primitive data type introduced in ES6. They are often used as unique property keys for objects to avoid naming collisions.
[Symbol.iterator]
property which is a function that returns an iterator. Examples: Array
, String
, Map
, Set
.next()
method that returns an object with two properties: value
(the next value in the sequence) and done
(a boolean that's true
if the sequence is finished).Optional chaining is a safe way to access nested object properties. It stops the evaluation and returns undefined
if a reference in the chain is null
or undefined
. This prevents TypeError
exceptions.
const street = user?.address?.street;
The nullish coalescing operator returns its right-hand side operand when its left-hand side operand is null
or undefined
, and otherwise returns its left-hand side operand. It's a way to provide a default value for a variable that might be nullish.
for...in
: Iterates over the enumerable property keys of an object, including inherited properties.for...of
: Iterates over the values of an iterable object (Array
, String
, Map
, etc.). It does not work on plain objects because they are not iterable by default.Tagged templates are an advanced form of template literals. They allow you to parse template literals with a function. The first argument to the tag function is an array of the string literals, and the subsequent arguments are the evaluated expressions.
The event loop is the core mechanism in JavaScript that enables non-blocking asynchronous behavior. It's a constantly running process that monitors both the Call Stack and the Callback Queue. If the Call Stack is empty, it takes the first event from the queue and pushes it to the Call Stack, which effectively runs it.
Callback hell (or the pyramid of doom) is a situation in asynchronous code where multiple nested callbacks make the code hard to read, maintain, and debug. Promises and async/await
were created to solve this problem.
You use a standard try...catch
block, just like with synchronous code.
async function fetchData() { try { const response = await fetch('invalid-url'); const data = await response.json(); console.log(data); } catch (error) { console.error("Failed to fetch data:", error); } }
The event loop actually has two kinds of queues:
setTimeout
, setInterval
, I/O operations.Promise
callbacks (.then
, .catch
, .finally
) and queueMicrotask
.
Execution Order: The event loop executes tasks in a specific order. After each macrotask from the macrotask queue is completed, the event loop processes all available tasks in the microtask queue before moving on to the next macrotask. This means microtasks have a higher priority.setTimeout(fn, 0)
places the function fn
in the macrotask queue.Promise.resolve().then(fn)
places fn
in the microtask queue.
Therefore, the promise callback will always execute before the setTimeout
callback if both are scheduled at the same time.The fetch()
API provides a modern, Promise-based interface for making network requests. It's a Web API, meaning the browser provides it. When you call fetch
, the request is sent off in the background. The fetch
function immediately returns a Promise
that resolves to a Response
object once the server has responded with headers. You then need to call another method on the Response
object (like .json()
or .text()
) to read the body of the response, which also returns a promise.
CORS is a security mechanism implemented by browsers that controls how web pages in one domain can request resources from another domain. The server at the other domain must include specific CORS headers (like Access-Control-Allow-Origin
) in its response to permit the cross-origin request.
These are APIs used to abort asynchronous operations, most commonly fetch
requests. You create an AbortController
, pass its signal
property to the fetch
options, and then you can call controller.abort()
at any time to cancel the request.
JSONP (JSON with Padding) was a hack to get around the same-origin policy before CORS existed. It works by dynamically creating a <script>
tag that points to the remote server. The server would wrap the JSON data in a function call. It's no longer used because it's insecure (can lead to XSS) and CORS is the standard, more flexible solution.
Long polling is a technique where the client makes a request to the server, and the server holds the connection open until it has new data to send. Once the data is sent, the connection is closed, and the client immediately opens a new one. It's a way to simulate a server push.
WebSockets provide a full-duplex, persistent communication channel between a client and a server over a single TCP connection. This allows for real-time, low-latency communication in both directions, which is ideal for applications like chat apps, live notifications, and online gaming.
SSE is a technology where a server can push data to a client automatically once an initial client connection has been established. It's a one-way communication channel from server to client, and it's simpler than WebSockets. It's ideal for things like live stock tickers or news feeds.
Debouncing is a programming practice used to ensure that a function is not called too frequently. It groups a burst of sequential calls into a single one. A debounced function will only run after a certain amount of time has passed without it being called. Use case: a search bar that only fetches results after the user has stopped typing for 300ms.
Throttling is a practice that ensures a function is executed at most once every specified period. A throttled function will run, then wait for the specified interval before it can run again, regardless of how many times it was called during that interval. Use case: ensuring a scroll event handler doesn't fire more than once every 100ms.
This is a complex question testing deep knowledge. A simplified implementation would involve a class with:
state
(pending
, fulfilled
, rejected
).value
.onFulfilled
and onRejected
callbacks.then
method that pushes callbacks to the arrays.resolve
and reject
functions, which change the state and trigger the stored callbacks.The Document Object Model (DOM) is a tree-like representation of an HTML document. It's an API that allows programs to read and manipulate the content, structure, and style of a web page.
window
: The global object in the browser. It represents the browser window or tab. All global variables and functions are properties of window
.document
: A property of the window
object. It represents the HTML document loaded in that window.Event delegation is a technique where you add a single event listener to a parent element to handle events for all of its children. When a child element is clicked, the event "bubbles" up to the parent. The parent can then check the event.target
property to determine which child was actually clicked. This is more efficient than adding an event listener to every child element, especially for dynamic lists.
These are the two phases of DOM event propagation.
window
object down through the DOM tree to the target element.window
object.
By default, event listeners are handled in the bubbling phase. You can listen in the capturing phase by setting the third argument of addEventListener
to true
.innerHTML
: Gets or sets the HTML content inside an element. It can be a security risk (XSS) if you set it with untrusted content.innerText
: Gets or sets the "rendered" text content. It is style-aware and will not show text from hidden elements.textContent
: Gets or sets the raw text content of a node and its descendants, including text from hidden elements and <script>
tags. It has better performance than innerText
.Both are part of the Web Storage API for storing key-value pairs.
localStorage
: Persists data even after the browser is closed and reopened. The data has no expiration time.sessionStorage
: Stores data only for a single session. The data is cleared when the tab or window is closed.Cookies are small pieces of data stored on the client's computer by the web browser. They are sent back to the server with every subsequent request. They are used for session management, personalization, and tracking. They have size limits and are sent with every HTTP request, which can impact performance.
Feature | localStorage | Cookies |
---|---|---|
Capacity | 5-10 MB | ~4 KB |
Accessibility | Client-side only | Client and Server |
Expiration | Never expires | Manually set |
HTTP Requests | Not sent with requests | Sent with every request |
The Shadow DOM is a web standard that allows for encapsulated DOM and CSS in a web component. It creates a hidden, separate DOM tree attached to an element. This is crucial for creating reusable components (like a <video>
tag) without worrying about styles or scripts leaking in or out.
Data attributes (data-*
) are a way to store custom data private to the page or application on standard HTML elements. You can access them in JavaScript using the dataset
property.
DOMContentLoaded
: Fires when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading.load
: Fires when the whole page has loaded, including all dependent resources such as stylesheets and images.A Service Worker is a script that your browser runs in the background, separate from a web page. They enable features like offline capabilities, background sync, and push notifications. They act as a proxy server, intercepting network requests and handling them as you see fit.
This API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport. It's a highly efficient way to implement features like lazy-loading images or infinite scrolling.
This API provides a performant mechanism by which code can monitor an element for changes to its size, with notifications being delivered to the observer each time the size changes.
function debounce(func, delay) { let timeoutId; return function(...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => { func.apply(this, args); }, delay); }; }
function throttle(func, limit) { let inThrottle; return function(...args) { if (!inThrottle) { func.apply(this, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; }
This is a classic recursion problem. The base case is a string of length 1. The recursive step involves taking each character, finding all permutations of the remaining characters, and prepending the character to each of those permutations.
Memoization is an optimization technique used to speed up function calls by caching the results of expensive function calls and returning the cached result when the same inputs occur again.
function memoize(func) { const cache = {}; return function(...args) { const key = JSON.stringify(args); if (cache[key]) { return cache[key]; } const result = func(...args); cache[key] = result; return result; }; }
// Using ES2019's flat() method const nested = [1, [2, [3, [4]]]]; console.log(nested.flat(Infinity)); // [1, 2, 3, 4] // Recursive approach function flatten(arr) { let flatArr = []; arr.forEach(item => { if (Array.isArray(item)) { flatArr = flatArr.concat(flatten(item)); } else { flatArr.push(item); } }); return flatArr; }
for
loops, if
statements).map
and filter
, HTML).history.pushState()
method to change the URL in the browser without causing a page refresh.popstate
event, which fires when the user navigates using the browser's back/forward buttons.<input>
field for the user to type in.input
event listener to the input field.debounce
function to avoid making excessive API calls.innerHTML
with untrusted data. Use Content Security Policy (CSP) headers.🔗 Blog: https://codewiz.info
🔗 LinkedIn: https://www.linkedin.com/in/code-wiz-740370302/
🔗 Medium: https://medium.com/@code.wizzard01
🔗 Github: https://github.com/CodeWizzard01
Get instant AI-powered summaries of YouTube videos and websites. Save time while enhancing your learning experience.