Summary Quick Revision
use strict
In JavaScript, "use strict" is a directive introduced in ECMAScript 5 (ES5) that enables Strict Mode, a restricted variant of JavaScript.
Closures
A closure is a function that retains access to variables from its outer scope after that outer function has returned, enabling private state and encapsulation.
IIFE
An Immediately Invoked Function Expression runs as soon as it is defined and creates a private scope to avoid polluting the global namespace.
call, apply and bindcall invokes a function with a specified this and individual arguments; apply invokes with a specified this and an array of arguments; bind returns a new function with this (and optionally arguments) permanently bound.
this
The value of this depends on how a function is called: object method, standalone function, arrow function (lexical this), constructor, or event handler.
Hoisting
Function declarations and var declarations are hoisted to the top of their scope; let and const are not accessible before their declaration (temporal dead zone).
Temporal Dead Zone
The period between entering scope and the let/const declaration where accessing the variable throws a ReferenceError.
Event Propagation
Events travel through three phases: capturing, target, and bubbling. Handlers can run during capture or bubble and can stop propagation.
- Capturing Phase (Trickling): The event starts from the
windowand travels downward through ancestors until it reaches the target element. - Target Phase: The event reaches the actual element that was interacted with (e.g., a button).
- Bubbling Phase: The event “bubbles” back up from the target element through its ancestors to the
window
Function Types – Ways function can be defined
Function declarations, function expressions, arrow functions, generator functions, and async functions each have different hoisting, scoping, and this behavior.
Array Methods
Mutating methods: push, pop, splice; non‑mutating: map, filter, reduce, slice; modern helpers: flat, at, with.
DOM Methods
Selection, creation, attribute manipulation, event handling, and utilities such as getBoundingClientRect and scrollIntoView.
Promises vs Observables and RxJS
Promises produce a single future value and execute immediately; Observables produce streams, execute on subscription, and can be cancelled. RxJS operators like map, filter, switchMap, and mergeMap transform and control streams.
Tricky Coding Questions
console.log(a); var a = 10; # undefined
console.log(b); let b = 10; # ReferenceError
(function() {
var x = y = 5;
})();
console.log(typeof x); # undefine
console.log(typeof y); # number
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1000);
}
# Output: 333
setTimeout(() => console.log('timeout'), 0);
Promise.resolve().then(() => console.log('promise'));
# Execution Order: Promise, setTimeout
console.log(0 == '0'); # true
console.log(0 === '0'); # false
console.log(10 + 2 + "9") # 129
console.log(NAN === NAN) # false
# How to access variable x (which is outside function) in function test?
x = 10;
function test(){
let x = 20;
console.log(this.x); # 10, accessed global variable x using this.
console.log(x); # 20, local variable x
}
let x=1;
y = x++; # At this point: x=1, y=1
console.log(x,y); # 2, 1
# Note: ++ operator first assigns existing value, then increases by one, so assign 1 to y and becomes 2 in next console.log statement)
Hoisting and Scoping (The “Undefined” Trap):
What is the output of console.log(a); var a = 10;?
Answer: undefined. The declaration var a is hoisted to the top and initialized as undefined, but the assignment 10 stays in place.
Temporal Dead Zone:
What happens if you run console.log(b); let b = 10;?
Answer: ReferenceError. Unlike var, let and const variables are hoisted but not initialized, placing them in a “temporal dead zone” until the declaration is reached.
Shadowing in Functions:
What is the output of this IIFE?
(function() {
var x = y = 5;
})();
console.log(typeof x);
console.log(typeof y);
Answer: undefined and number. y becomes a global variable because it is not declared with var, while x is local to the function scope.
The Loop Closure Quirk:
What does this code print?
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1000);
}
Answer: 3 3 3. Because var is function-scoped, all callbacks share the same i, which is 3 by the time they run. Using let fixes this by creating a new binding for each iteration.
Microtasks vs. Macrotasks – Asynchronous Execution:
In what order will “timeout” and “promise” print?
setTimeout(() => console.log('timeout'), 0);
Promise.resolve().then(() => console.log('promise'));
Answer: “promise” then “timeout”. The Event Loop prioritizes the microtask queue (Promises) over the macrotask queue (setTimeout).
Type Coercion and Comparison
- Why does
0 == '0'returntrue, but0 === '0'returnfalse?
Answer: == performs implicit type coercion to make types match before comparing, while === checks both value and type.
2. What is the result of 10 + 2 + "9"?
Answer: "129". JavaScript adds the first two numbers (12) and then concatenates the result with the string "9".
3. What is the result of console.log(NaN === NaN)?
Answer: false. NaN (Not-a-Number) is the only value in JavaScript that is not equal to itself.
Detailed Notes and Examples
use strict
In JavaScript, "use strict" is a directive introduced in ECMAScript 5 (ES5) that enables Strict Mode, a restricted variant of JavaScript. It is designed to catch common coding mistakes, improve security, and allow JavaScript engines to perform better optimizations by eliminating some of the language’s “sloppy” behaviors.
How to Use It
- Global Scope: Place
"use strict";at the very top of a script file to apply it to all code in that file. - Function Scope: Place it inside the body of a specific function to apply strict mode only within that function’s scope.
- Automatic Activation: Strict mode is automatically enabled in JavaScript Modules (ES6 modules) and within JavaScript Classes.
Key Changes and Rules
Strict mode changes previously accepted “bad syntax” into real errors:
- No Undeclared Variables: You cannot use a variable without declaring it (e.g.,
x = 10will throw aReferenceErrorinstead of creating a global variable). - Unique Parameter Names: Functions cannot have duplicate parameter names (e.g.,
function sum(a, a, b)is not allowed). - Secure
this: In regular functions, ifthisis not set by the call, it defaults toundefinedrather than the global object (likewindow). - Restricted
eval: Variables declared inside aneval()call no longer “leak” into the surrounding scope. - Read-Only Protections: Writing to a read-only property or deleting an undeletable property (like
Object.prototype) throws an error instead of failing silently. - Forbidden Keywords: Certain words reserved for future versions (e.g.,
implements,interface,public,private) cannot be used as variable names.
Why Use It?
- Bug Prevention: It catches typos (like mistyped variable names) and structural mistakes early by throwing immediate errors.
- Performance: Engines can optimize strict mode code more effectively because it follows predictable rules.
- Security: It prevents access to potentially dangerous features and helps avoid accidental global variable pollution.
- Modern Standards: Using it ensures your code is compatible with modern JavaScript features like modules and classes, which rely on strict mode behavior by default.
Closures
Explanation
A closure is formed when an inner function retains access to variables from its outer function even after the outer function has finished executing. This enables private variables and persistent state.
Example
function counter() {
let count = 0; // private
return function () {
count++;
return count;
};
}
const increment = counter();
console.log(increment()); // 1
console.log(increment()); // 2
console.log(increment()); // 3
Pattern
function createUser(name) {
let score = 0;
return {
getName() { return name; },
getScore() { return score; },
increment() { score++; return score; }
};
}
IIFE
Explanation
An IIFE executes immediately and creates a private scope, preventing variables from leaking into the global scope.
Example
(function () {
const secret = 'hidden';
console.log('IIFE executed');
})();
Use cases
Initialization code, module-like encapsulation in older environments, avoiding global collisions.
call, apply and bind
call — invoke immediately with individual arguments.
apply — invoke immediately with arguments provided as an array.
bind — return a new function with this and optional arguments bound; does not invoke.
Examples
function greet(greeting, punctuation) {
console.log(`${greeting}, ${this.name}${punctuation}`);
}
const user = { name: "Lok" };
greet.call(user, "Hello", "!"); // Hello, Lok!
function sum(a, b, c) { return a + b + c; }
const numbers = [1, 2, 3];
console.log(sum.apply(null, numbers)); // 6
const module = { x: 42, getX() { return this.x; } };
const unboundGetX = module.getX;
const boundGetX = unboundGetX.bind(module);
console.log(boundGetX()); // 42
function multiply(a, b) { return a * b; }
const double = multiply.bind(null, 2);
console.log(double(5)); // 10
When to use
callfor immediate invocation with known args.applywhen args are in an array or array-like.bindfor callbacks or partial application wherethismust be preserved.
this Keyword
Contexts
- Object method:
thisis the object. - Standalone function:
thisisundefinedin strict mode, global in non-strict. - Arrow function:
thisis inherited from the lexical scope. - Constructor:
thisis the new instance. - Event handler:
thisis the element that received the event (unless arrow function used).
Examples
const obj = { name: 'Lok', sayName() { console.log(this.name); } };
obj.sayName(); // Lok
function showThis() {
'use strict';
console.log(this); // undefined
}
showThis();
const person = {
name: 'Lok',
regular: function() { console.log(this.name); }, // Lok
arrow: () => { console.log(this); } // lexical this
};
person.regular();
person.arrow();
function Person(name) { this.name = name; }
const p = new Person('Lok');
console.log(p.name); // Lok
Hoisting
Explanation
Hoisting moves declarations to the top of their scope at runtime. Function declarations and var declarations are hoisted; let and const are not accessible before their declaration.
Examples
// Function declaration hoisted
sayHi(); // works
function sayHi() { console.log('Hi'); }
// var hoisted but undefined until assignment
console.log(x); // undefined
var x = 5;
// let/const are not accessible before declaration
console.log(y); // ReferenceError if uncommented
let y = 10;
Key points
- Function declarations can be called before they appear in code.
varvariables exist before their assignment but have valueundefined.letandconstare in the temporal dead zone until declared.
Temporal Dead Zone
Explanation
The temporal dead zone (TDZ) is the time between entering a scope and the let/const declaration. Accessing the variable in the TDZ throws a ReferenceError.
Example
{
// console.log(a); // ReferenceError: Cannot access 'a' before initialization
let a = 2;
console.log(a); // 2
}
Practical note
Use let and const to avoid accidental use of uninitialized variables; be aware that they are not hoisted in the same usable way as var.
Function Types
Function Declaration
function sum(a, b) { return a + b; } // hoisted
Function Expression
const sum = function(a, b) { return a + b; }; // not hoisted
const factorial = function fac(n) { return n <= 1 ? 1 : n * fac(n - 1); };
Arrow Function
const multiply = (a, b) => a * b; // lexical this, no arguments object
Generator Function
function* numberGen() {
yield 1;
yield 2;
}
const gen = numberGen();
console.log(gen.next().value); // 1
Async Function
async function fetchData(url) {
const res = await fetch(url);
return res.json();
}
Array Methods
Mutating
const arr = [1, 2, 3];
arr.push(4);
arr.pop();
arr.splice(1, 1, 99);
Non‑mutating
const nums = [1, 2, 3, 4];
const doubled = nums.map(x => x * 2);
const evens = nums.filter(x => x % 2 === 0);
const sum = nums.reduce((acc, cur) => acc + cur, 0);
Searching and reordering
nums.includes(2);
nums.find(x => x > 2);
nums.sort();
nums.reverse();
nums.join('-');
Modern helpers
const nested = [1, [2, 3], [4, [5]]];
nested.flat(2); // [1,2,3,4,5]
const arr2 = [1, 2, 3];
const updated = arr2.with(1, 99); // [1,99,3] non-mutating
console.log(arr2.at(-1)); // 3
DOM Methods
Selection
document.getElementById('myId');
document.querySelector('.myClass');
document.querySelectorAll('p');
Creation and manipulation
const div = document.createElement('div');
div.textContent = 'Hello';
document.body.appendChild(div);
div.remove();
Attributes and classes
div.setAttribute('id', 'newDiv');
div.classList.add('highlight');
div.classList.toggle('active');
div.getAttribute('id');
div.removeAttribute('id');
Events
function onClick(e) { console.log('clicked', e.target); }
div.addEventListener('click', onClick);
div.removeEventListener('click', onClick);
Utilities
const rect = div.getBoundingClientRect();
div.scrollIntoView({ behavior: 'smooth' });
div.closest('section');
div.matches('.highlight');
Event Propagation
Phases
- Capturing phase: event travels from the window down to the target.
- Target phase: event reaches the target element.
- Bubbling phase: event bubbles up from the target to the window.
Example
<div id="outer">
<button id="btn">Click</button>
</div>
<script>
const outer = document.getElementById('outer');
const btn = document.getElementById('btn');
// Capture listener
outer.addEventListener('click', () => console.log('outer capture'), true);
// Bubble listener
outer.addEventListener('click', () => console.log('outer bubble'), false);
btn.addEventListener('click', (e) => {
console.log('button clicked');
// e.stopPropagation(); // stops further propagation
});
</script>
Stopping propagation
e.stopPropagation()prevents the event from reaching other listeners in later phases.e.stopImmediatePropagation()prevents other listeners on the same element from running.
Use cases
- Prevent duplicate handling when parent and child both listen for the same event.
- Implement delegated event handling by listening on a parent and using
event.target.
Promises vs Observables and RxJS
Promise example
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => resolve('done'), 1000);
});
myPromise.then(result => console.log(result)).catch(err => console.error(err));
Observable example
import { Observable } from 'rxjs';
const myObservable = new Observable(observer => {
observer.next('first');
setTimeout(() => {
observer.next('second');
observer.complete();
}, 500);
});
const subscription = myObservable.subscribe({
next: value => console.log('value:', value),
error: err => console.error(err),
complete: () => console.log('completed')
});
// subscription.unsubscribe(); // cancel if needed
BehaviorSubject example
import { BehaviorSubject } from 'rxjs';
const loggedIn$ = new BehaviorSubject(false);
loggedIn$.next(true);
loggedIn$.subscribe(value => console.log('loggedIn:', value));
RxJS Operators Examples
map
import { of } from 'rxjs';
import { map } from 'rxjs/operators';
of(1,2,3).pipe(map(x => x * 2)).subscribe(console.log); // 2,4,6
filter
import { filter } from 'rxjs/operators';
of(1,2,3,4).pipe(filter(x => x % 2 === 0)).subscribe(console.log); // 2,4
switchMap
import { fromEvent, of } from 'rxjs';
import { debounceTime, switchMap } from 'rxjs/operators';
const input = document.querySelector('input');
fromEvent(input, 'input').pipe(
debounceTime(300),
switchMap(e => of(`results for ${e.target.value}`))
).subscribe(console.log);
mergeMap
import { mergeMap } from 'rxjs/operators';
of(1,2,3).pipe(mergeMap(x => of(x * 10))).subscribe(console.log); // 10,20,30
take and takeUntil
import { interval, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
const stop$ = new Subject();
interval(1000).pipe(takeUntil(stop$)).subscribe(console.log);
setTimeout(() => stop$.next(), 5000); // stop after 5s
Conclusion
This revision adds hoisting, temporal dead zone, and event propagation to the earlier coverage of closures, IIFEs, function invocation methods, this, function types, array methods, DOM APIs, Promises, Observables, and RxJS operators. Use the summary for quick revision and the detailed sections for examples and deeper understanding.
If you want, I can convert this into a printable one‑page cheat sheet, flashcards for study, or a small demo page with runnable examples.