Output-Based JavaScript Tricky Questions:
1️⃣ setTimeout with 0 delay
console.log("A");
setTimeout(() => {
console.log("B");
}, 0);
console.log("C");
✅ Output
A
C
B
🧠 Explanation
setTimeout goes to macrotask queue, executed after call stack is empty.
2️⃣ Promise vs setTimeout
console.log("start");
Promise.resolve().then(() => console.log("promise"));
setTimeout(() => console.log("timeout"), 0);
console.log("end");
✅ Output
start
end
promise
timeout
🧠 Explanation
Microtasks (Promise) run before macrotasks (setTimeout).
3️⃣ Multiple Promises
Promise.resolve().then(() => console.log(1));
Promise.resolve().then(() => console.log(2));
console.log(3);
✅ Output
3
1
2
🧠 Explanation
Synchronous code first, then microtasks in order.
4️⃣ Nested setTimeout
setTimeout(() => {
console.log("A");
setTimeout(() => console.log("B"), 0);
}, 0);
console.log("C");
✅ Output
C
A
B
🧠 Explanation
Nested setTimeout creates new macrotask.
5️⃣ Promise inside setTimeout
setTimeout(() => {
Promise.resolve().then(() => console.log("P"));
}, 0);
setTimeout(() => console.log("T"), 0);
✅ Output
P
T
🧠 Explanation
Microtask inside first macrotask runs before next macrotask.
6️⃣ async/await basics
async function test() {
console.log(1);
await Promise.resolve();
console.log(2);
}
test();
console.log(3);
✅ Output
1
3
2
🧠 Explanation
await pauses function, rest goes to microtask queue.
7️⃣ async function return
async function foo() {
return 10;
}
foo().then(console.log);
console.log(20);
✅ Output
20
10
🧠 Explanation
Async always returns a Promise.
8️⃣ await with setTimeout
async function run() {
console.log("A");
await new Promise(res => setTimeout(res, 0));
console.log("B");
}
run();
console.log("C");
✅ Output
A
C
B
🧠 Explanation
setTimeout inside await → macrotask.
9️⃣ Promise chaining
Promise.resolve(1)
.then(x => x + 1)
.then(x => console.log(x));
✅ Output
2
🧠 Explanation
Each .then returns a new Promise.
🔟 Promise rejection
Promise.reject("Error")
.catch(err => console.log(err));
console.log("Done");
✅ Output
Done
Error
🧠 Explanation
.catch() runs as microtask.
1️⃣1️⃣ then vs catch order
Promise.resolve()
.then(() => {
throw "Oops";
})
.catch(console.log)
.then(() => console.log("After"));
✅ Output
Oops
After
🧠 Explanation
Error handled → chain continues.
1️⃣2️⃣ Object mutation
const obj = { a: 1 };
const ref = obj;
ref.a = 2;
console.log(obj.a);
✅ Output
2
🧠 Explanation
Objects are passed by reference.
1️⃣3️⃣ let vs var
for (var i = 0; i < 1; i++) {
setTimeout(() => console.log(i), 0);
}
✅ Output
1
🧠 Explanation
var is function-scoped.
1️⃣4️⃣ let in loop
for (let i = 0; i < 1; i++) {
setTimeout(() => console.log(i), 0);
}
✅ Output
0
🧠 Explanation
let creates a new block scope per iteration.
1️⃣5️⃣ Hoisting
console.log(a);
var a = 10;
✅ Output
undefined
🧠 Explanation
var is hoisted with undefined.
1️⃣6️⃣ Temporal Dead Zone
console.log(b);
let b = 5;
✅ Output
ReferenceError
🧠 Explanation
let is hoisted but in TDZ.
1️⃣7️⃣ this in normal function
const obj = {
x: 10,
show() {
console.log(this.x);
}
};
obj.show();
✅ Output
10
1️⃣8️⃣ this lost
const obj = {
x: 10,
show() {
setTimeout(function () {
console.log(this.x);
}, 0);
}
};
obj.show();
✅ Output
undefined
🧠 Explanation
Normal function → this = window.
1️⃣9️⃣ arrow fixes this
const obj = {
x: 10,
show() {
setTimeout(() => console.log(this.x), 0);
}
};
obj.show();
✅ Output
10
2️⃣0️⃣ Promise inside Promise
Promise.resolve()
.then(() => {
Promise.resolve().then(() => console.log("Inner"));
})
.then(() => console.log("Outer"));
✅ Output
Outer
Inner
🧠 Explanation
Inner Promise scheduled after current microtask.
2️⃣1️⃣ finally
Promise.resolve("X")
.finally(() => console.log("Finally"))
.then(console.log);
✅ Output
Finally
X
2️⃣2️⃣ async + return
async function a() {
console.log(1);
return 2;
}
a().then(console.log);
console.log(3);
✅ Output
1
3
2
2️⃣3️⃣ Multiple awaits
async function test() {
await Promise.resolve();
console.log("A");
await Promise.resolve();
console.log("B");
}
test();
✅ Output
A
B
🧠 Explanation
Each await queues a microtask.
2️⃣4️⃣ Promise.all
Promise.all([
Promise.resolve(1),
Promise.resolve(2)
]).then(console.log);
✅ Output
[1, 2]
2️⃣5️⃣ Promise.race
Promise.race([
new Promise(res => setTimeout(res, 10, "A")),
Promise.resolve("B")
]).then(console.log);
✅ Output
B
2️⃣6️⃣ setTimeout order
setTimeout(() => console.log(1), 0);
setTimeout(() => console.log(2), 0);
✅ Output
1
2
2️⃣7️⃣ sync inside async
async function foo() {
console.log("A");
}
foo();
console.log("B");
✅ Output
A
B
2️⃣8️⃣ Promise constructor
new Promise(resolve => {
console.log("X");
resolve();
}).then(() => console.log("Y"));
✅ Output
X
Y
2️⃣9️⃣ Nested async
async function one() {
console.log(1);
}
async function two() {
await one();
console.log(2);
}
two();
✅ Output
1
2
3️⃣0️⃣ Object reference change
let a = { x: 1 };
let b = a;
a = { x: 2 };
console.log(b.x);
✅ Output
1
🧠 Explanation
Reassignment breaks reference.
3️⃣1️⃣ Promise inside Promise chain
Promise.resolve()
.then(() => {
console.log("A");
return Promise.resolve("B");
})
.then(console.log);
✅ Output
A
B
🧠 Explanation
The returned Promise resolves with "B", passed to next .then().
3️⃣2️⃣ Promise without return
Promise.resolve()
.then(() => {
console.log("A");
Promise.resolve("B");
})
.then(console.log);
✅ Output
A
undefined
🧠 Explanation
Without return, next .then() receives undefined.
3️⃣3️⃣ setTimeout + Promise mix
setTimeout(() => console.log("T1"), 0);
Promise.resolve().then(() => console.log("P1"));
setTimeout(() => console.log("T2"), 0);
✅ Output
P1
T1
T2
🧠 Explanation
Microtasks (Promise) execute before macrotasks (setTimeout).
3️⃣4️⃣ await non-Promise
async function test() {
console.log(1);
await 2;
console.log(3);
}
test();
console.log(4);
✅ Output
1
4
3
🧠 Explanation
await wraps non-Promise values in Promise.resolve().
3️⃣5️⃣ async return value
async function foo() {
return Promise.resolve(5);
}
foo().then(console.log);
✅ Output
5
🧠 Explanation
Returned Promise is automatically unwrapped.
3️⃣6️⃣ await with rejection
async function test() {
try {
await Promise.reject("Error");
} catch (e) {
console.log(e);
}
}
test();
✅ Output
Error
🧠 Explanation
Rejected Promise throws inside async → caught by try/catch.
3️⃣7️⃣ Promise.then order
Promise.resolve()
.then(() => console.log("A"))
.then(() => console.log("B"));
Promise.resolve()
.then(() => console.log("C"));
✅ Output
A
C
B
🧠 Explanation
Microtasks execute in order of registration.
3️⃣8️⃣ Multiple awaits
async function test() {
console.log("Start");
await Promise.resolve();
console.log("Mid");
await Promise.resolve();
console.log("End");
}
test();
✅ Output
Start
Mid
End
🧠 Explanation
Each await queues a new microtask.
3️⃣9️⃣ Promise in loop
for (var i = 0; i < 3; i++) {
Promise.resolve().then(() => console.log(i));
}
✅ Output
3
3
3
🧠 Explanation
var shares same reference; loop finishes first.
4️⃣0️⃣ let in Promise loop
for (let i = 0; i < 3; i++) {
Promise.resolve().then(() => console.log(i));
}
✅ Output
0
1
2
🧠 Explanation
let creates a new block scope per iteration.
4️⃣1️⃣ Object reference
const obj = { a: 1 };
function update(o) {
o.a = 2;
}
update(obj);
console.log(obj.a);
✅ Output
2
🧠 Explanation
Objects are passed by reference.
4️⃣2️⃣ Reassign inside function
let obj = { a: 1 };
function update(o) {
o = { a: 2 };
}
update(obj);
console.log(obj.a);
✅ Output
1
🧠 Explanation
Reassignment doesn’t affect original reference.
4️⃣3️⃣ this inside arrow
const obj = {
x: 10,
foo: () => console.log(this.x)
};
obj.foo();
✅ Output
undefined
🧠 Explanation
Arrow functions don’t have their own this.
4️⃣4️⃣ this inside normal function
const obj = {
x: 10,
foo() {
console.log(this.x);
}
};
obj.foo();
✅ Output
10
4️⃣5️⃣ bind effect
function show() {
console.log(this.x);
}
const obj = { x: 5 };
const bound = show.bind(obj);
bound();
✅ Output
5
🧠 Explanation
bind permanently sets this.
4️⃣6️⃣ Promise.resolve vs new Promise
console.log("A");
Promise.resolve().then(() => console.log("B"));
new Promise(res => {
console.log("C");
res();
}).then(() => console.log("D"));
✅ Output
A
C
B
D
🧠 Explanation
Promise executor runs synchronously.
4️⃣7️⃣ finally doesn’t change value
Promise.resolve("X")
.finally(() => "Y")
.then(console.log);
✅ Output
X
🧠 Explanation
finally doesn’t modify resolved value.
4️⃣8️⃣ setTimeout inside Promise
Promise.resolve().then(() => {
setTimeout(() => console.log("T"), 0);
console.log("P");
});
✅ Output
P
T
🧠 Explanation
Promise runs first, then macrotask.
4️⃣9️⃣ Hoisting function
sayHi();
function sayHi() {
console.log("Hi");
}
✅ Output
Hi
🧠 Explanation
Function declarations are hoisted.
5️⃣0️⃣ Function expression hoisting
sayHi();
var sayHi = function () {
console.log("Hi");
};
✅ Output
TypeError
🧠 Explanation
var hoisted as undefined, not function.
5️⃣1️⃣ Promise.all rejection
Promise.all([
Promise.resolve(1),
Promise.reject("Err"),
Promise.resolve(3)
]).catch(console.log);
✅ Output
Err
🧠 Explanation
Promise.all fails fast on first rejection.
5️⃣2️⃣ Promise.any
Promise.any([
Promise.reject("A"),
Promise.resolve("B"),
Promise.resolve("C")
]).then(console.log);
✅ Output
B
🧠 Explanation
Returns first fulfilled Promise.
5️⃣3️⃣ Promise.allSettled
Promise.allSettled([
Promise.resolve(1),
Promise.reject("X")
]).then(console.log);
✅ Output
[
{ status: "fulfilled", value: 1 },
{ status: "rejected", reason: "X" }
]
🧠 Explanation
Waits for all Promises, no short-circuit.
5️⃣4️⃣ async inside setTimeout
setTimeout(async () => {
console.log(await Promise.resolve("A"));
}, 0);
console.log("B");
✅ Output
B
A
5️⃣5️⃣ await console.log
async function test() {
await console.log(1);
console.log(2);
}
test();
✅ Output
1
2
🧠 Explanation
console.log runs synchronously.
5️⃣6️⃣ Closure trap
function create() {
let x = 10;
return function () {
console.log(x);
};
}
const fn = create();
fn();
✅ Output
10
5️⃣7️⃣ typeof null
console.log(typeof null);
✅ Output
object
🧠 Explanation
Legacy JavaScript bug.
5️⃣8️⃣ NaN comparison
console.log(NaN === NaN);
✅ Output
false
5️⃣9️⃣ Boolean coercion
console.log(!!"");
console.log(!!" ");
✅ Output
false
true
6️⃣0️⃣ Object keys
const obj = { 1: "a", 2: "b" };
console.log(Object.keys(obj));
✅ Output
["1", "2"]
🧠 Explanation
Object keys are strings.
6️⃣1️⃣ setTimeout inside loop (var)
for (var i = 1; i <= 3; i++) {
setTimeout(() => console.log(i), i * 100);
}
✅ Output
4
4
4
🧠 Explanation
var is function-scoped. Loop finishes (i = 4) before timers execute.
6️⃣2️⃣ setTimeout inside loop (let)
for (let i = 1; i <= 3; i++) {
setTimeout(() => console.log(i), i * 100);
}
✅ Output
1
2
3
🧠 Explanation
let creates a new block scope for each iteration.
6️⃣3️⃣ Promise inside forEach
[1, 2, 3].forEach(async (x) => {
await Promise.resolve();
console.log(x);
});
✅ Output
1
2
3
🧠 Explanation
Each async callback queues a microtask; execution order is preserved.
6️⃣4️⃣ async forEach misconception
async function test() {
[1, 2, 3].forEach(async x => {
await Promise.resolve();
console.log(x);
});
console.log("Done");
}
test();
✅ Output
Done
1
2
3
🧠 Explanation
forEach does not await async callbacks.
6️⃣5️⃣ async for...of
async function test() {
for (let x of [1, 2, 3]) {
await Promise.resolve();
console.log(x);
}
console.log("Done");
}
test();
✅ Output
1
2
3
Done
🧠 Explanation
for...of respects await.
6️⃣6️⃣ Promise inside async
async function test() {
return Promise.resolve("A");
}
test().then(console.log);
✅ Output
A
🧠 Explanation
Returned Promise is automatically unwrapped.
6️⃣7️⃣ async error handling
async function test() {
throw "Error";
}
test().catch(console.log);
✅ Output
Error
🧠 Explanation
Throwing inside async = rejected Promise.
6️⃣8️⃣ setTimeout + await
async function test() {
console.log("A");
await new Promise(r => setTimeout(r, 0));
console.log("B");
}
test();
console.log("C");
✅ Output
A
C
B
🧠 Explanation
setTimeout is macrotask → executed after sync code.
6️⃣9️⃣ Promise.resolve timing
console.log("X");
Promise.resolve().then(() => console.log("Y"));
console.log("Z");
✅ Output
X
Z
Y
🧠 Explanation
Promises are microtasks → run after sync code.
7️⃣0️⃣ Nested microtasks
Promise.resolve().then(() => {
console.log(1);
Promise.resolve().then(() => console.log(2));
});
✅ Output
1
2
🧠 Explanation
Inner microtask is queued after outer microtask finishes.
7️⃣1️⃣ setTimeout nesting
setTimeout(() => {
console.log("A");
setTimeout(() => console.log("B"), 0);
}, 0);
✅ Output
A
B
🧠 Explanation
Nested setTimeout creates a new macrotask.
7️⃣2️⃣ Promise.all execution
Promise.all([
Promise.resolve("A"),
Promise.resolve("B")
]).then(res => console.log(res.join("")));
✅ Output
AB
🧠 Explanation
Promise.all waits for all to resolve.
7️⃣3️⃣ Promise.any rejection
Promise.any([
Promise.reject("X"),
Promise.reject("Y")
]).catch(err => console.log(err.errors));
✅ Output
["X", "Y"]
🧠 Explanation
Promise.any rejects only if all promises reject.
7️⃣4️⃣ Promise.race rejection
Promise.race([
new Promise((_, r) => setTimeout(r, 0, "Err")),
new Promise(res => setTimeout(res, 10, "OK"))
]).catch(console.log);
✅ Output
Err
🧠 Explanation
First settled promise wins (resolve or reject).
7️⃣5️⃣ Object mutation vs reassignment
let a = { x: 1 };
let b = a;
b.x = 2;
console.log(a.x);
✅ Output
2
🧠 Explanation
Both variables reference the same object.
7️⃣6️⃣ this in arrow inside method
const obj = {
x: 5,
foo() {
const bar = () => console.log(this.x);
bar();
}
};
obj.foo();
✅ Output
5
🧠 Explanation
Arrow function inherits this from enclosing scope.
7️⃣7️⃣ this lost in callback
const obj = {
x: 5,
foo() {
setTimeout(function () {
console.log(this.x);
}, 0);
}
};
obj.foo();
✅ Output
undefined
🧠 Explanation
Normal function → this becomes window.
7️⃣8️⃣ bind fix
const obj = {
x: 5,
foo() {
setTimeout(function () {
console.log(this.x);
}.bind(this), 0);
}
};
obj.foo();
✅ Output
5
🧠 Explanation
bind fixes this.
7️⃣9️⃣ Hoisting function vs var
foo();
var foo = function () {
console.log("Hi");
};
✅ Output
TypeError
🧠 Explanation
foo is hoisted as undefined, not a function.
8️⃣0️⃣ Function declaration hoisting
foo();
function foo() {
console.log("Hi");
}
✅ Output
Hi
8️⃣1️⃣ Closure with timeout
function outer() {
let x = 10;
setTimeout(() => console.log(x), 0);
}
outer();
✅ Output
10
🧠 Explanation
Closure retains access to x.
8️⃣2️⃣ Changing closed value
function outer() {
let x = 10;
return () => console.log(x);
}
const fn = outer();
x = 20;
fn();
✅ Output
10
🧠 Explanation
Closure captures local variable, not global.
8️⃣3️⃣ typeof function
console.log(typeof function () {});
✅ Output
function
8️⃣4️⃣ typeof array
console.log(typeof []);
✅ Output
object
🧠 Explanation
Arrays are objects internally.
8️⃣5️⃣ Equality coercion
console.log([] == false);
✅ Output
true
🧠 Explanation
[] → "" → 0, false → 0.
8️⃣6️⃣ Strict equality
console.log([] === false);
✅ Output
false
8️⃣7️⃣ String + number
console.log("5" + 3);
✅ Output
53
8️⃣8️⃣ String - number
console.log("5" - 3);
✅ Output
2
8️⃣9️⃣ parseInt trap
console.log(parseInt("10px"));
console.log(parseInt("px10"));
✅ Output
10
NaN
9️⃣0️⃣ Object comparison
console.log({} == {});
✅ Output
false
🧠 Explanation
Objects are compared by reference.
9️⃣1️⃣ Promise vs async order
async function test() {
console.log("A");
await Promise.resolve();
console.log("B");
}
Promise.resolve().then(() => console.log("C"));
test();
✅ Output
A
C
B
🧠 Explanation
Aruns immediatelyawaitpausestest- Promise
.then(C) runs beforeB(both are microtasks, order matters)
9️⃣2️⃣ setTimeout + Promise
setTimeout(() => console.log("T"), 0);
Promise.resolve().then(() => console.log("P"));
console.log("S");
✅ Output
S
P
T
🧠 Explanation
- Sync first
- Microtasks (Promise)
- Macrotasks (setTimeout)
9️⃣3️⃣ Promise inside async
async function foo() {
Promise.resolve().then(() => console.log("A"));
console.log("B");
}
foo();
✅ Output
B
A
🧠 Explanation
Promise callback is microtask → runs after sync code.
9️⃣4️⃣ await Promise.then
async function test() {
await Promise.resolve().then(() => console.log("A"));
console.log("B");
}
test();
✅ Output
A
B
🧠 Explanation
.then() runs before await resumes.
9️⃣5️⃣ Promise chain order
Promise.resolve()
.then(() => console.log(1))
.then(() => console.log(2));
Promise.resolve().then(() => console.log(3));
✅ Output
1
3
2
🧠 Explanation
Microtasks execute in registration order.
9️⃣6️⃣ async function without await
async function test() {
console.log("Hello");
}
test();
console.log("World");
✅ Output
Hello
World
🧠 Explanation
async doesn’t make code async unless await is used.
9️⃣7️⃣ await non-promise
async function test() {
console.log(1);
await 10;
console.log(2);
}
test();
console.log(3);
✅ Output
1
3
2
🧠 Explanation
await 10 → Promise.resolve(10) → microtask.
9️⃣8️⃣ Promise constructor sync
new Promise(() => {
console.log("X");
});
console.log("Y");
✅ Output
X
Y
🧠 Explanation
Promise executor runs synchronously.
9️⃣9️⃣ Promise resolve timing
new Promise(res => {
console.log("A");
res();
}).then(() => console.log("B"));
console.log("C");
✅ Output
A
C
B
🧠 Explanation
.then() is a microtask.
1️⃣0️⃣0️⃣ Hoisting var
console.log(a);
var a = 5;
✅ Output
undefined
🧠 Explanation
var is hoisted with undefined.
1️⃣0️⃣1️⃣ TDZ with let
console.log(b);
let b = 5;
✅ Output
ReferenceError
🧠 Explanation
let exists in Temporal Dead Zone.
1️⃣0️⃣2️⃣ Function scope
function test() {
if (true) {
var x = 10;
}
console.log(x);
}
test();
✅ Output
10
🧠 Explanation
var is function-scoped.
1️⃣0️⃣3️⃣ Block scope
function test() {
if (true) {
let x = 10;
}
console.log(x);
}
test();
✅ Output
ReferenceError
🧠 Explanation
let is block-scoped.
1️⃣0️⃣4️⃣ this in arrow
const obj = {
x: 10,
foo: () => console.log(this.x)
};
obj.foo();
✅ Output
undefined
🧠 Explanation
Arrow functions don’t have their own this.
1️⃣0️⃣5️⃣ this in method
const obj = {
x: 10,
foo() {
console.log(this.x);
}
};
obj.foo();
✅ Output
10
1️⃣0️⃣6️⃣ setTimeout this
const obj = {
x: 10,
foo() {
setTimeout(function () {
console.log(this.x);
}, 0);
}
};
obj.foo();
✅ Output
undefined
🧠 Explanation
Normal function → this = global.
1️⃣0️⃣7️⃣ Arrow fixes this
const obj = {
x: 10,
foo() {
setTimeout(() => console.log(this.x), 0);
}
};
obj.foo();
✅ Output
10
1️⃣0️⃣8️⃣ Closure with var
function outer() {
var x = 5;
return function () {
console.log(x);
};
}
outer()();
✅ Output
5
1️⃣0️⃣9️⃣ Closure mutation
function outer() {
let x = 1;
return () => {
x++;
console.log(x);
};
}
const fn = outer();
fn();
fn();
✅ Output
2
3
🧠 Explanation
Closure preserves variable state.
1️⃣1️⃣0️⃣ Object reference
let a = { n: 1 };
let b = a;
a.n = 2;
console.log(b.n);
✅ Output
2
1️⃣1️⃣1️⃣ Reassignment
let a = { n: 1 };
let b = a;
a = { n: 2 };
console.log(b.n);
✅ Output
1
1️⃣1️⃣2️⃣ == coercion
console.log(null == undefined);
✅ Output
true
🧠 Explanation
Special loose equality rule.
1️⃣1️⃣3️⃣ === strict
console.log(null === undefined);
✅ Output
false
1️⃣1️⃣4️⃣ Array comparison
console.log([] == []);
✅ Output
false
🧠 Explanation
Different references.
1️⃣1️⃣5️⃣ Boolean coercion
console.log(Boolean([]));
✅ Output
true
1️⃣1️⃣6️⃣ !! operator
console.log(!!0);
console.log(!!1);
✅ Output
false
true
1️⃣1️⃣7️⃣ typeof NaN
console.log(typeof NaN);
✅ Output
number
1️⃣1️⃣8️⃣ parseInt weirdness
console.log(parseInt("08"));
✅ Output
8
🧠 Explanation
Modern JS uses base-10 by default.
1️⃣1️⃣9️⃣ setTimeout order
setTimeout(() => console.log(1), 0);
setTimeout(() => console.log(2), 0);
setTimeout(() => console.log(3), 0);
✅ Output
1
2
3
🧠 Explanation
Macrotasks execute in FIFO order.
1️⃣2️⃣0️⃣ Final event loop mix
console.log("A");
setTimeout(() => console.log("B"), 0);
Promise.resolve().then(() => console.log("C"));
console.log("D");
✅ Output
A
D
C
B
🧠 Explanation
- Sync: A, D
- Microtask: C
- Macrotask: B