0% found this document useful (0 votes)
9 views6 pages

JavaScript Interview Prep: Key Concepts

javascript interview questions

Uploaded by

chimandeka1323
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views6 pages

JavaScript Interview Prep: Key Concepts

javascript interview questions

Uploaded by

chimandeka1323
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

JavaScript Deep Dive Notes for Interview Preparation

This document covers advanced JavaScript concepts such as hoisting, function types,
asynchronous programming, closures, and scoping with real-world examples and
interview-ready summaries.

1. JavaScript Execution Context and Memory

Every JavaScript program runs inside an **Execution Context**, which is created in two
phases:
1. **Memory Creation Phase (Hoisting Phase):**
- All variables and function declarations are stored in memory before execution begins.
- Variables declared with `var` are initialized with `undefined`.
- `let` and `const` are hoisted but remain uninitialized (TDZ - Temporal Dead Zone).
- Function declarations are hoisted with their full body.
2. **Execution Phase:**
- Code runs line by line. Variables are assigned their actual values, and functions are
executed.

Memory Diagram Example:

Code:
[Link](a);
var a = 10;
function greet() { [Link]("Hello"); }

Memory Creation Phase:


a -> undefined
greet -> function(){...}

Execution Phase:
[Link](a); // undefined
a = 10;

2. for(var) vs for(let) with setTimeout

Example 1:
for (var i = 0; i < 10; i++) {
setTimeout(() => [Link](i), 0);
}
Output: Prints 10 ten times (10 10 10 10 10 10 10 10 10 10)

Explanation:
- `var` is function-scoped, not block-scoped.
- By the time setTimeout callback runs, the loop has finished, and `i = 10`.

Example 2:
for (let i = 0; i < 10; i++) {
setTimeout(() => [Link](i), 0);
}
Output: Prints 0 1 2 3 4 5 6 7 8 9

Explanation:
- `let` is block-scoped.
- For each iteration, a new copy of `i` is created in memory.
- The callback captures that block’s `i`.

📘 Interview Summary:

- `var` → Single shared memory reference (function-scoped).


- `let` → Creates new binding each iteration (block-scoped).

3. IIFE in Loop with var

Example:
for (var i = 0; i < 10; i++) {
((j) => setTimeout(() => [Link](j), 0))(i);
}
Output: 0 1 2 3 4 5 6 7 8 9

Explanation:
- The IIFE `( (j) => ... )(i)` immediately captures the value of `i`.
- Each iteration passes its current `i` value as `j` (new scope).
- The closure ensures correct values are logged.

4. Promises, async, await, .then, .catch, .finally

A **Promise** represents a value that may be available now, later, or never.


Example:
const data = new Promise((resolve, reject) => {
setTimeout(() => resolve("Data loaded"), 1000);
});

data
.then(res => [Link](res))
.catch(err => [Link](err))
.finally(() => [Link]("Done"));

Async/Await Example:
async function fetchData() {
try {
const res = await data;
[Link](res);
} catch (err) {
[Link](err);
} finally {
[Link]("Done");
}
}
fetchData();

// here [Link]() again awaited(if not awaited then it would return again a promise

const getData = async () => {

try {

const data = await fetch("[Link]

const jsonData = await [Link]();

[Link]("data : ", jsonData);

} catch (error) {

[Link]("error :", error);

};

getData();
📘 Interview Summary:

- `Promise` simplifies asynchronous code (better than callbacks).


- `.then()` handles resolved values.
- `.catch()` handles rejections.
- `.finally()` runs in all cases.
- `async/await` makes async code look synchronous.

5. Function Declaration vs Expression

Function Declaration:
function greet() {
[Link]("Hello");
}

✅ Fully hoisted — can be called before defined.

Function Expression:
const greet = function() {
[Link]("Hello");
};

❌ Not hoisted with definition — calling before initialization causes ReferenceError (if
const/let).

Function expression with var gives typeError as var hoisted but undefined

6. Why ReferenceError (var) when calling before assignment

Code:
getData();
var getData = function() {
[Link]("inside getData");
};

Explanation:
- `var getData` is hoisted as `undefined`.
- During execution, calling `getData()` is equivalent to calling `undefined()`.
- Hence → **TypeError: getData is not a function.**

📘 Interview Summary:

- `var` is hoisted with `undefined` value → TypeError when used as function.


- `let/const` → TDZ applies → ReferenceError.
- Function declarations are hoisted with full definition → safe to call early.

7. Arrow Functions, Hoisting, and TDZ

Arrow functions are **always function expressions**, never declarations.

Example:
[Link](greet); // ReferenceError (TDZ)
const greet = () => [Link]("Hi");

With var:
[Link](greet); // undefined
// greet(); ❌ TypeError: greet is not a function
var greet = () => [Link]("Hi");

Summary:
- Arrow functions are not hoisted with their body.
- Declared with var → TypeError.
- Declared with let/const → ReferenceError (TDZ).
- Lexically bind `this` (do not have their own this or arguments).

8. Summary Table: Function Types and Hoisting Behavior


Function Type Hoisted? Can Call Before Error Type
Declaration?

Function Yes (with body) ✅ Yes None


Declaration

Function Expression Variable hoisted ❌ No TypeError


(var) (undefined)
Function Expression Hoisted (TDZ) ❌ No ReferenceError
(let/const)

Arrow Function Variable hoisted ❌ No TypeError


(var) (undefined)

Arrow Function Hoisted (TDZ) ❌ No ReferenceError


(let/const)

9. Common Interview Questions


1. Explain how hoisting works for var, let, and const.

2. What is the Temporal Dead Zone (TDZ)?

3. Difference between function declaration and function expression.

4. Why do we get TypeError when calling var-declared function expressions before


initialization?

5. Explain the difference between for(var) and for(let) in asynchronous loops.

6. How does IIFE solve closure issues in loops?

7. Explain how Promise, async, await, and .then/.catch/.finally work internally.

8. Why do arrow functions not have their own `this`?

9. Can you illustrate the memory creation phase in JavaScript with an example?

Common questions

Powered by AI

JavaScript Promises and async/await provide a more structured and readable means of handling asynchronous operations than traditional callbacks by flattening the asynchronous code's nested structure ('callback hell'). Promises allow results to be handled through a chain of '.then()', '.catch()', and '.finally()' calls, delineating resolved values, errors, and cleanup processes. Async/await syntax further simplifies asynchronous code by making it appear synchronous, allowing developers to handle sequential asynchronous operations more naturally .

The Temporal Dead Zone (TDZ) in JavaScript refers to the time span between the start of the current scope and the point at which a 'let' or 'const' variable is declared. During the TDZ, accessing an uninitialized 'let' or 'const' variable throws a ReferenceError. Although the variable is hoisted to the top of its scope, it remains uninitialized and inaccessible until the code execution hits its declaration, restricting any usage or reference until this initialization point .

'for(var)' uses function scoping, leading to a single shared memory reference across loop iterations in asynchronous operations like setTimeout. This results in the output reflecting the loop completion value, typically 10 repeats of the last value. In contrast, 'for(let)' is block-scoped, creating a new copy of the loop variable 'i' for each iteration. This allows each asynchronous setTimeout to capture and log each block-scoped copy of 'i', producing a sequential output from 0 to 9 .

Arrow functions do not create their own 'this' binding; instead, they lexically inherit 'this' from the surrounding non-arrow function or global scope. This means the 'this' value within an arrow function is determined by the context in which the arrow function was defined, not where it is invoked. This behavior affects execution context by preventing 'this' from being dynamically altered, making arrow functions ideal for callbacks that should preserve the original 'this' context .

Consider the code snippet: console.log(a); var a = 10; function greet() { console.log('Hello'); }. During the Memory Creation Phase, 'a' is hoisted as 'undefined' and 'greet' as a complete function. By the Execution Phase, the first line attempts to log 'a', which is 'undefined' at this point due to hoisting. Following execution, the variable 'a' is then assigned value '10'. Function 'greet' can be safely called at any code point due to its fully hoisted state with body .

Using 'var' in loop variable declarations results in a single shared memory reference with function-scoping during asynchronous operations. Therefore, by the time callbacks execute, 'var' captures the loop's completed state, typically leading to unexpected identical values in outputs like with setTimeout calls. Conversely, 'let' introduces block-scoping, creating a new, independent instance for each iteration, allowing callbacks to log different values corresponding to each loop's iteration derivative, offering more predictable results .

Variables declared with 'var' are hoisted as 'undefined', causing a TypeError if invoked as a function before assignment. 'let' and 'const' declarations are subject to the Temporal Dead Zone (TDZ). Accessing them before initialization leads to a ReferenceError because they aren't initialized prior to usage, effectively creating a state where the variable is inaccessible despite existing in memory .

An IIFE resolves closure issues in loops using 'var' by immediately capturing the current loop variable's state in its own scope each iteration. This ensures each iteration of asynchronous operations like setTimeout has access to the closures capturing the distinct value of 'i' at that time, rather than sharing one mutable reference as would occur without an IIFE. Consequently, each callback logs a unique value corresponding to the loop's current increment .

JavaScript Execution Context operates in two key phases: the Memory Creation Phase and the Execution Phase. In the Memory Creation Phase, variables and function declarations are hoisted. Variables declared with 'var' are initialized as 'undefined', whereas those with 'let' and 'const' enter the Temporal Dead Zone (TDZ) and remain uninitialized until the line of code is executed. Function declarations are hoisted with their complete body. In the Execution Phase, the code is executed line-by-line, with variables being initialized to their actual values and functions invoked as programmed .

Function declarations in JavaScript are fully hoisted with their body, allowing them to be invoked before the line where they are defined. In contrast, function expressions are only partially hoisted as variables: if using 'var', the function is hoisted as 'undefined', leading to a TypeError if invoked before assignment; if using 'let' or 'const', a ReferenceError occurs due to the Temporal Dead Zone (TDZ).

You might also like