Learning Partner

Code Output Challenges

Predict the output of a JavaScript snippet, choose an answer and review the result. Use these exercises alongside the interview tracks.

Hoisting

getName();
console.log(X);
function getName() {
  console.log('Hello');
}
console.log(b);
let b = 20;
console.log(b);
Review the expected output
Hello
Uncaught ReferenceError: X is not defined

The function getName() is hoisted, so calling it prints "Hello". However, X is not defined anywhere, leading to a ReferenceError. The variable b is declared using let, which is hoisted but remains in the Temporal Dead Zone (TDZ) until initialized. Accessing b before initialization results in another ReferenceError, but after initialization, console.log(b); prints 20.

Hoisting

function test() {
  if (false) {
    var x = 50;
  }
  console.log(x);
  console.log(y);
  var y = 100;
  console.log(y);
}
test();
Review the expected output
undefined
undefined
100

The variable x is declared inside the if block with var, so it is hoisted to the top of the function but remains undefined since the block doesn't execute. This leads to console.log(x); printing undefined. The variable y is also hoisted, but only its declaration, not its assignment. So console.log(y); before assignment prints undefined. After y = 100;, console.log(y); prints 100. Since x and y are declared with var, they are function-scoped and exist throughout the function execution.

Hoisting

var foo = function () {
  console.log('I am a function expression!');
};
function foo() {
  console.log('I am a function declaration!');
}
foo();
Review the expected output
I am a function expression!

<p>The function declaration <code>function foo()</code> is hoisted first, but it is later overwritten by the function expression assigned to <code>var foo</code>.</p> <p>When <code>foo()</code> is called, it executes the function expression, printing:</p> <pre>I am a function expression!</pre> <p>This happens because variable assignments override function declarations when they share the same name.</p>

Hoisting

if (true) {
  console.log(innerVar);
  var innerVar = 'I am hoisted!';
  console.log(innerVar);
}
console.log(innerVar);
Review the expected output
undefined
        I am hoisted!

<p>The variable <code>innerVar</code> is declared with <code>var</code>, which means it is hoisted to the top of its function or global scope.</p> <p>However, only the declaration is hoisted, not the initialization. This means when <code>console.log(innerVar)</code> is executed before the assignment, it prints <code>undefined</code>.</p> <p>After <code>innerVar = "I am hoisted!"</code>, the second <code>console.log(innerVar)</code> prints:</p> <pre>I am hoisted!</pre> <p>Since <code>var</code> is function-scoped, <code>innerVar</code> is accessible outside the block as well, so the final <code>console.log(innerVar)</code> also prints:</p> <pre>I am hoisted!</pre>

Hoisting

var x = 10;
console.log(x);
if (true) {
  (function () {
    var x = 20;
    console.log(x);
  })();
}
console.log(x);
Review the expected output
10
20
10

<p>The variable <code>x</code> is first declared globally with the value <code>10</code>, so <code>console.log(x)</code> prints:</p> <pre>10</pre> <p>Inside the <code>if</code> block, an **immediately invoked function expression (IIFE)** creates a new function scope. A new <code>x</code> is declared inside this function with the value <code>20</code>. This <code>x</code> is separate from the global <code>x</code>, so <code>console.log(x)</code> inside the function prints:</p> <pre>20</pre> <p>After the IIFE executes, we return to the global scope, where <code>x</code> is still <code>10</code>. So the final <code>console.log(x)</code> prints:</p> <pre>10</pre> <p>This demonstrates **function scope isolation**, where variables declared with <code>var</code> inside a function do not affect the outer scope.</p>

Hoisting

var x = 10;
function test() {
  if (x > 20) {
    var x = 50;
  }
  console.log(x);
}
test();
Review the expected output
undefined

<p>The global variable <code>x</code> is declared and initialized with <code>10</code>.</p> <p>Inside the <code>test()</code> function, a new variable <code>x</code> is declared using <code>var</code>. Due to **hoisting**, this function-scoped <code>x</code> is moved to the top of the function and initialized as <code>undefined</code>.</p> <p>Since the condition <code>x > 20</code> is false (because hoisted <code>x</code> is <code>undefined</code>), the assignment <code>x = 50</code> never executes.</p> <p>Thus, when <code>console.log(x)</code> runs inside the function, it prints:</p> <pre>undefined</pre> <p>This happens because the local <code>x</code> shadows the global <code>x</code>, and due to hoisting, it is treated as <code>var x;</code> at the start of the function.</p>

Hoisting

function test() {
  function foo() {}
  var bar;
  foo();
  bar();
  function foo() {
    console.log('foo');
  }
  bar = function () {
    console.log('bar');
  };
}
test();
Review the expected output
foo
        Uncaught TypeError: bar is not a function

<p>Function declarations are fully hoisted, while <code>var</code> variables are hoisted but remain <code>undefined</code> until assigned.</p> <p><code>foo()</code> runs successfully because function declarations are hoisted with their definitions, printing:</p> <pre>foo</pre> <p><code>bar()</code> causes an error because <code>bar</code> is hoisted as <code>undefined</code>, and the function is assigned later:</p> <pre>Uncaught TypeError: bar is not a function</pre>

Hoisting

function test() {
  if (false) {
    let x = 50;
  }
  console.log(x);
  console.log(y);
  let y = 100;
  console.log(y);
}
test();
Review the expected output
Uncaught ReferenceError: x is not defined

<p><code>let</code> variables are hoisted but stay in the <strong>Temporal Dead Zone (TDZ)</strong> until initialized.</p> <p><code>x</code> is inside a blocked <code>if (false)</code>, so it doesn't exist in scope. <code>console.log(x)</code> throws:</p> <pre>Uncaught ReferenceError: x is not defined</pre> <p><code>y</code> is hoisted but still in the TDZ when accessed, causing the same error. After initialization, <code>console.log(y)</code> prints:</p> <pre>100</pre>

Hoisting

console.log(greet);
var greet = 'Hello';
console.log(greet);
Review the expected output
undefined
Hello

<p>With <code>var</code>, variable declarations are hoisted and initialized to <code>undefined</code> during the creation phase. Therefore, the first <code>console.log(greet)</code> prints <code>undefined</code>. After the assignment, the second prints <code>Hello</code>.</p>

Hoisting

var employeeId = 'abc123';
function foo() {
  employeeId();
  return;
  function employeeId() {
    console.log(typeof employeeId);
  }
}
foo();
Review the expected output
function

<p>Function declarations are hoisted before variables, so inside <code>foo()</code>, <code>employeeId</code> refers to the function, not the global variable.</p> <p>Calling <code>employeeId()</code> works since it’s a function, but it prints:</p> <pre>function</pre>

Hoisting

function foo() {
  let a = (b = 0);
  a++;
  return a;
}
foo();
console.log(typeof a);
console.log(typeof b);
Review the expected output
undefined
        number

<p><code>let a = b = 0;</code> is interpreted as:</p> <pre>let a = 0; b = 0;</pre> <p>Since <code>b</code> is not declared with <code>let</code> or <code>var</code>, it becomes a **global variable**.</p> <p><code>a</code> is block-scoped inside <code>foo()</code>, so <code>console.log(typeof a)</code> prints:</p> <pre>undefined</pre> <p><code>b</code> exists globally, so <code>console.log(typeof b)</code> prints:</p> <pre>number</pre>

Hoisting

console.log(typeof foo);
var foo = function () {
  console.log('Hello!');
};
Review the expected output
"undefined"

<p>Variable <code>foo</code> is declared with <code>var</code>, so it is hoisted, but only the declaration, not the assignment.</p> <p>Before the function expression is assigned, <code>typeof foo</code> evaluates to:</p> <pre>"undefined"</pre> <p>If it were a function declaration instead of an expression, <code>typeof foo</code> would return <code>"function"</code>.</p>

Hoisting

console.log(a);
let a = 5;
Review the expected output
Uncaught ReferenceError: Cannot access 'a' before initialization

<p>Variables declared with <code>let</code> are hoisted but remain in the **Temporal Dead Zone (TDZ)** until they are initialized.</p> <p>Since <code>a</code> is accessed before its initialization, it throws:</p> <pre>Uncaught ReferenceError: Cannot access 'a' before initialization</pre>

Hoisting

var x = 1;
function test() {
  console.log(x);
  var x = 2;
}
test();
Review the expected output
undefined

<p>Due to **hoisting**, the local <code>var x</code> declaration inside <code>test()</code> is moved to the top.</p> <p>Thus, inside <code>test()</code>, <code>x</code> is hoisted as <code>var x;</code>, making it <code>undefined</code> at the time of <code>console.log(x)</code>.</p> <p>Even though there's a global <code>x = 1</code>, the local <code>x</code> shadows it, so the output is:</p> <pre>undefined</pre>

Hoisting

console.log(foo());
function foo() {
  return 'Hello';
}
var foo = function () {
  return 'Hi';
};
Review the expected output
"Hello"

<p>Function declarations are hoisted before variable assignments.</p> <p>So, <code>function foo() { return "Hello"; }</code> is fully hoisted and available at runtime.</p> <p>The <code>var foo</code> declaration is also hoisted, but the function expression is assigned later, so it doesn't override the function declaration at the time of execution.</p> <p>Thus, <code>console.log(foo())</code> prints:</p> <pre>"Hello"</pre>

Hoisting

(function () {
  console.log(x);
  var x = 10;
})();
Review the expected output
undefined

<p>The variable <code>x</code> is declared with <code>var</code> inside the IIFE (Immediately Invoked Function Expression).</p> <p>Due to **hoisting**, only the declaration is moved to the top, making <code>x</code> <code>undefined</code> before assignment.</p> <p>Thus, <code>console.log(x)</code> prints:</p> <pre>undefined</pre>

Hoisting

console.log(foo);
var foo = 10;
function foo() {}
console.log(foo);
Review the expected output
[Function: foo]
    10

<p>The function declaration <code>function foo() {}</code> is hoisted first, then the <code>var foo</code> declaration.</p> <p>Initially, <code>foo</code> is a function, so <code>console.log(foo)</code> prints:</p> <pre>[Function: foo]</pre> <p>Later, <code>foo</code> is reassigned to <code>10</code>, so the second <code>console.log(foo)</code> prints:</p> <pre>10</pre>

Hoisting

console.log(bar);
function bar() {
  console.log('I am bar!');
}
var bar = 5;
console.log(bar);
Review the expected output
[Function: bar]
    5

<p>The function declaration <code>bar()</code> is hoisted first.</p> <p>The <code>var bar</code> declaration is hoisted but not its assignment.</p> <p>So, initially, <code>console.log(bar)</code> prints the function:</p> <pre>[Function: bar]</pre> <p>After <code>bar = 5</code>, the second <code>console.log(bar)</code> prints:</p> <pre>5</pre>

Hoisting

foo();
var foo = function () {
  console.log('Hello!');
};
Review the expected output
Uncaught TypeError: foo is not a function

<p>Function expressions are not hoisted like function declarations.</p> <p><code>var foo</code> is hoisted as <code>undefined</code>, so calling <code>foo()</code> before assignment throws:</p> <pre>Uncaught TypeError: foo is not a function</pre>

Hoisting

console.log(a);
let a;
console.log(a);
Review the expected output
Uncaught ReferenceError: Cannot access 'a' before initialization

<p>The <code>let</code> variable <code>a</code> is hoisted but remains in the **Temporal Dead Zone (TDZ)** until it is initialized.</p> <p>Accessing it before initialization throws:</p> <pre>Uncaught ReferenceError: Cannot access 'a' before initialization</pre>

Hoisting

console.log(x);
var x;
console.log(x);
Review the expected output
undefined
    undefined

<p>The variable <code>x</code> is declared with <code>var</code>, so it is hoisted with an initial value of <code>undefined</code>.</p> <p>Thus, both <code>console.log(x)</code> statements print:</p> <pre>undefined</pre>

Hoisting

var a = 10;
console.log(a);
function fn() {
  console.log(a);
  var a = 20;
  a++;
  console.log(a);
  if (a) {
    var a = 30;
    a++;
    console.log(a);
  }
  console.log(a);
}
fn();
console.log(a);
Review the expected output
10
        undefined
        21
        31
        31
        10

<p>Global <code>a = 10</code>, so first <code>console.log(a)</code> prints:</p> <pre>10</pre> <p>Inside <code>fn()</code>, <code>var a</code> is hoisted as <code>undefined</code>, so:</p> <pre>undefined</pre> <p>After assignments:</p> <pre>21</pre> <pre>31</pre> <pre>31</pre> <p>Global <code>a</code> remains unchanged:</p> <pre>10</pre> <p><strong>Takeaway:</strong> <code>var</code> is function-scoped, causing shadowing.</p>

Promise

Promise.resolve(1)
  .then((val) => {
    console.log(val);
    return val + 1;
  })
  .then(console.log);
Review the expected output
1
        2

When a method using an arrow function accesses `this`, it lexically captures the instance scope, ensuring `this` correctly points to the class instance even when passed as a standalone callback.

Promise

console.log('Start');
Promise.resolve().then(() => console.log('Promise'));
console.log('End');
Review the expected output
Start
        End
        Promise

<ul> <li>Synchronous code runs first (the console.log("Start") and console.log("End")).</li> <li>Promise.resolve() creates a resolved Promise, but it is asynchronous. The .then() handler associated with it will not be executed immediately. Instead, it will be queued in the microtask queue.</li> <li> The Promise.then() callback runs after all synchronous code finishes, so "Promise" is logged after "Start" and "End".</li> </ul>

Promise

const p = new Promise((resolve, reject) => {
  let success = true;
  success ? resolve('Success') : reject('Failed');
});

p.then(console.log).catch(console.error);
Review the expected output
Success

Private class fields prefixed with `#` cannot be accessed outside the declaring class body. Attempting to read them throws a SyntaxError at compile/parse time.

Promise

Promise.resolve(10)
  .then((num) => num * 2)
  .then((num) => num + 5)
  .then(console.log);
Review the expected output
25

The subclass constructor must call `super()` before accessing `this`. Once initialized, methods inherited from the prototype chain resolve correctly.

Promise

function doubleAfter2Sec(x) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(x * 2), 2000);
  });
}
Promise.resolve(10).then(doubleAfter2Sec).then(console.log); // 20 after 2 seconds
Review the expected output
20

Static methods and properties belong to the class constructor function itself rather than instances. Accessing static members via an instance yields `undefined`.

Promise

console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
Review the expected output
1
        4
        3
        2

Promise.then is a microtask, executed before setTimeout (a macrotask).

Promise

const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.resolve(3);

Promise.all([p1, p2, p3]).then((results) => {
  console.log(results);
});
Review the expected output
[1, 2, 3]

Lexical closure captures the variable reference, not just the initial value. Functions returned from higher-order functions retain access to outer scoped variables.

Promise

function fetchWithTimeout(url, timeout = 3000) {
  const delay = new Promise((_, reject) =>
    setTimeout(() => reject('Timeout!'), timeout),
  );
  return Promise.race([fetch(url), delay]);
}
fetchWithTimeout('https://jsonplaceholder.typicode.com/users', 10)
  .then((res) => {
    console.log(res);
  })
  .catch((error) => {
    console.log(error);
  });
Review the expected output
Timeout!

Generator functions yield values on each `.next()` call. The returned iterator object has `value` and `done` properties reflecting execution state.

Prototype

function Person(name) {
  this.name = name;
}
Person.prototype.sayHello = function () {
  console.log('Hi, I am ' + this.name);
};
const p = new Person('Chetan');
p.sayHello();
Review the expected output
Hi, I am Chetan

The Temporal Dead Zone (TDZ) prevents accessing `let` and `const` variables before their declaration line is executed, throwing a ReferenceError.

Prototype

function Animal() {}
Animal.prototype.sound = 'Roar';

const tiger = new Animal();
console.log(tiger.sound);
Review the expected output
Roar

Function declarations are hoisted with their definitions, allowing them to be called before declaration. Variable declarations assigned function expressions remain undefined until executed.

Prototype

function Animal(name) {
  this.name = name;
}
Animal.prototype.eat = function () {
  console.log('undefined is eating');
};
function Dog(name) {
  Animal.call(this, name); // Call super constructor
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function () {
  console.log('undefined says woof');
};
const dog = new Dog('Bruno');
dog.eat();
dog.bark();
Review the expected output
Bruno is eating
        Bruno says woof

In non-strict mode, calling a regular function without an explicit context sets `this` to the global object (or undefined in strict mode).

Prototype

Array.prototype.last = function () {
  return this[this.length - 1];
};
const arr = [1, 2, 3];
console.log(arr.last());
Review the expected output
3

Destructuring with default values assigns the fallback only when the target property is strictly `undefined`, not when it is `null` or falsey.

Prototype

function Gadget() {}
Gadget.prototype.version = '1.0';

const g = new Gadget();
g.version = '2.0';

console.log(g.version);
console.log(g.__proto__.version);
Review the expected output
2.0
        1.0

Array.prototype.reduce accumulates values through an accumulator callback, returning the aggregated result across all iterations.

Class

class Test {
  constructor() {
    this.value = 42;
  }
  static getValue() {
    return this.value;
  }
}
Test.value = 100;
console.log(Test.getValue());
Review the expected output
100

Because this inside a static method refers to the class itself, and Test.value is 100.

Class

class Parent {
  constructor() {
    this.name = 'Parent';
  }
  sayHi() {
    console.log('Hi from ' + this.name);
  }
}

class Child extends Parent {
  constructor() {
    super(parenName);
    this.name = 'Child';
  }
  sayHi() {
    super.sayHi();
  }
}

const c = new Child();
c.sayHi();
Review the expected output
Hi from Child

The spread operator performs a shallow copy of properties. Nested objects retain reference equality with the source object.

Class

class Parent {
  constructor(name) {
    this.parentName = name;
  }
  sayHi() {
    console.log('Hi from ' + this.parentName);
  }
}

class Child extends Parent {
  constructor(parenName, childName) {
    super();
    this.name = childName;
  }
  sayHi() {
    super.sayHi();
  }
}

const c = new Child('aaa', 'bbb');
c.sayHi();
Review the expected output
Hi from aaa

Promise microtasks execute immediately after the current synchronous execution context empties, before any macrotasks (setTimeout) execute.

Class

class Foo {
  constructor() {
    this.count++;
  }
}
const a = new Foo();
const b = new Foo();
console.log(a.count);
console.log(b.count);
Review the expected output
NaN
NaN

async functions always return a Promise. A bare return value is implicitly wrapped with `Promise.resolve(value)`.

Class

class Logger {
  log = () => {
    console.log(this.message);
  };
  constructor(msg) {
    this.message = msg;
  }
}
const l = new Logger('Hello');
const logFn = l.log;
logFn();
Review the expected output
Hello

Object.freeze creates a shallow-immutable object, preventing property additions, deletions, or modifications.

Class

class Secret {
  #data = 'hidden';

  reveal() {
    return this.#data;
  }
}
const s = new Secret();
console.log(s.reveal());
console.log(s.#data);
Review the expected output
hidden
        throws SyntaxError

Curried functions take arguments one at a time via nested unary functions, returning intermediate closures until all arguments are satisfied.

Class

class Magic {
  static count = 0;
  constructor() {
    Magic.count++;
  }
}
const m1 = new Magic();
const m2 = new Magic();

console.log(m1.count);
console.log(Magic.count);
Review the expected output
undefined
        2

undefined as static property on the class itself, not on the instances.2, because we created two instances and each one increased the static count.

Class

const obj = new Test(); // ❓

class Test {
  constructor() {
    console.log('Created!');
  }
}
Review the expected output
Cannot access 'Test' before initialization"

Classes are not hoisted, unlike function declarations.

var-let-const

console.log(a); // undefined (hoisted)
var a = 10;
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 20;
Review the expected output
undefined
        Cannot access 'b' before initialization

The event loop drains the entire microtask queue before executing the next macrotask from the task queue.

var-let-const

if (true) {
  var x = 'I am var';
  let y = 'I am let';
  const z = 'I am const';
}
console.log(x);
console.log(y);
console.log(z);
Review the expected output
I am var
        y is not defined

as let and const are block scope so not accessibal after { }

var-let-const

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log('var loop:', i), 1000);
}
for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log('let loop:', j), 1000);
}
Review the expected output
var loop: 3
        var loop: 3
        var loop: 3
        let loop: 1
        let loop: 2
        let loop: 3

as var has function or gloabal scope so after there is only single memory assign to var one so it prints last value and in case of let for ecah {} it will maintain different value

var-let-const

for (var i = 0; i < 3; i++) {
  (function () {
    console.log(i);
  })();
}
Review the expected output
0
        1
        2

as var is fun or global scope for inside intertaion we have fun so for each iteration we have seperate bscope with diff value

var-let-const

for (var i = 0; i < 3; i++) {
  (function () {
    setTimeout(() => {
      console.log(i);
    }, 10000);
  })();
}
Review the expected output
3
        3
        3

as i is in outter scope and we are just accesing it so latest value only

var-let-const

function printFor() {
  for (var i = 0; i < 3; i++) {
    setTimeout(() => {
      printNo(i);
    }, 1000);
  }
}
function printNo(num) {
  console.log(num);
}
printFor();
Review the expected output
3
        3
        3

Template literals evaluate embedded expressions inside `${}` using their toString representations.

var-let-const

function printFor() {
  for (var i = 0; i < 3; i++) {
    function printNo(num) {
      setTimeout(() => {
        console.log(num);
      }, 1000);
    }
    printNo(i);
  }
}
printFor();
Review the expected output
0
        1
        2

here becaz of closure every param we pass will be lock with that instance of fun so diff value

Arrow_Function

const obj = {
  count: 0,
  increment: () => {
    this.count++;
  },
};
obj.increment();
Review the expected output
NaN

as we are calling obj.increment() from outside and there is not variabkle declared with count name so no access of this inarrow fun so undefined++ nan

Arrow_Function

const count = 2;
const obj = {
  count: 0,
  increment: () => {
    this.count++;
    console.log(this.count);
  },
};
obj.increment();
Review the expected output
NaN

now in global scope we have a variable count but that decclared with const so its not in global scope

Arrow_Function

var count = 2;
const obj = {
  count: 0,
  increment: () => {
    this.count++;
    console.log(this.count);
  },
};
obj.increment();
Review the expected output
3

npw in global scope we have count variable so 2++ => 3

Arrow_Function

var name = 'Angular';
var person = {
  name: 'React',
  age: 30,
  getDetail: function () {
    console.log('getDetail ' + this.name);
  },
  getName: () => {
    console.log('getName ' + this.name);
  },
};
person.getDetail();
person.getName();
Review the expected output
getDetail React
        getName Angular

now getDetail is normal fun so this refers to the person object. and arrow functions do not bind their own this it wil use its sorrunding scope and we are invoking getName poutside scope in scope we have Angular with same variable name

Arrow_Function

const fn = () => ({ name: 'JS' });
console.log(fn());
Review the expected output
{ name: "JS" }

Wrapping the object in () allows it to be returned directly. Without (), JavaScript thinks it's a block.

Arrow_Function

const fn = () => {
  name: 'JS';
};
console.log(fn());
Review the expected output
undefined

{} are usually interpreted as the function body in an arrow function <br/> JavaScript sees { name: "JS" } and thinks it's a block of code (not an object). So, it doesn't return anything: meaning the function fn() returns undefined

Arrow_Function

const outer = {
  count: 0,
  inc: function () {
    setTimeout(() => {
      this.count++;
      console.log(this.count);
    }, 100);
  },
};
outer.inc();
Review the expected output
1

Arrow function inherits this from inc method, which correctly refers to outer

Arrow_Function

let name = 'Outer';
const obj = {
  name: 'Inner',
  say: () => console.log(this.name),
};
obj.say();
Review the expected output
undefined

we are calling say fun from outside which is arrow one in in global scope we dont have name with var so undeinfed if global name was with var we would have got outer

Closure

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 1000);
}
Review the expected output
3
    3
    3

Analyze variable declarations, hoisting behavior, and asynchronous callback timing.

Closure

for (var i = 0; i < 3; i++) {
  ((j) => {
    setTimeout(() => console.log(j), 1000);
  })(i);
}
Review the expected output
0
  1
  2

Analyze variable declarations, hoisting behavior, and asynchronous callback timing.

Closure

function outer() {
  let secret = 'I know JS';
  return function inner() {
    return secret;
  };
}
const getSecret = outer();
console.log(getSecret());
Review the expected output
I know JS

Analyze variable declarations, hoisting behavior, and asynchronous callback timing.

Closure

let funcs = [];

for (var i = 0; i < 3; i++) {
  funcs.push(() => console.log(i));
}

funcs[0]();
funcs[1]();
Review the expected output
3
  3

Analyze variable declarations, hoisting behavior, and asynchronous callback timing.

Promise

console.log('Start');
Promise.resolve(() => {
  console.log('Promise');
});
setTimeout(() => {
  console.log('1 sec');
}, 1000);
setTimeout(() => {
  console.log('o sec');
}, 0);
setTimeout(() => {
  console.log('no time');
});
setTimeout(() => {
  console.log('o.5 sec');
}, 500);
console.log('End');
Review the expected output
Start
  End
  Promise
  o sec
  no time
  o.5 sec
  1 sec

Analyze variable declarations, hoisting behavior, and asynchronous callback timing.

Promise

console.log('Start');

setTimeout(() => {
  console.log('Timeout 1');
}, 0);

Promise.resolve().then(() => {
  console.log('Promise 1');
});

async function asyncFn() {
  console.log('Async Start');
  await null;
  console.log('Async End');
}

asyncFn();

setTimeout(() => {
  console.log('Timeout 2');
}, 0);

Promise.resolve().then(() => {
  console.log('Promise 2');
});

console.log('End');
Review the expected output
Start
Async Start
End
Promise 1
Async End
Promise 2
Timeout 1
Timeout 2

<p>The execution follows the JavaScript Event Loop order between synchronous code, MicroTask queue (Promises & await continuations), and MacroTask queue (setTimeout):</p> <p>1. <strong>Synchronous Execution:</strong> Prints <code>Start</code>, enqueues <code>Timeout 1</code> (MacroTask), enqueues <code>Promise 1</code> (MicroTask), enters <code>asyncFn()</code> synchronously printing <code>Async Start</code>, encounters <code>await null</code> which pauses <code>asyncFn</code> and enqueues its continuation (MicroTask), enqueues <code>Timeout 2</code> (MacroTask), enqueues <code>Promise 2</code> (MicroTask), and prints <code>End</code>.</p> <p>2. <strong>MicroTask Queue Drain:</strong> Runs <code>Promise 1</code>, then the resumed <code>asyncFn</code> continuation (<code>Async End</code>), then <code>Promise 2</code>.</p> <p>3. <strong>MacroTask Queue Drain:</strong> Runs <code>Timeout 1</code> followed by <code>Timeout 2</code>.</p>