JavaScript
Data Types
8 types: Number, BigInt, String, Boolean, Null, Undefined, Symbol, Object
typeof "abc" // "string"
typeof 42 // "number"
typeof null // "object" ← JS bug, null is NOT an object
typeof undefined // "undefined"
typeof {} // "object"
typeof [] // "object" (use Array.isArray())
typeof function(){} // "function"
Primitives are passed by value. Objects/Arrays are passed by reference.
var / let / const
var | let | const | |
|---|---|---|---|
| Scope | Function | Block | Block |
| Hoisted | Yes (as undefined) | Yes (TDZ) | Yes (TDZ) |
| Re-declare | Yes | No | No |
| Re-assign | Yes | Yes | No |
TDZ (Temporal Dead Zone): let/const exist in scope from declaration start but cannot be accessed before the line they're declared on — ReferenceError.
Variable Shadowing:
function test() {
var a = "Hello";
let b = "Bye";
if (true) {
let a = "Hi"; // ✅ legal shadowing
let b = "Good"; // ✅ legal shadowing
// var b = "Bad"; // ❌ illegal — var leaks to function scope, conflicts with let b
}
}
Hoisting
JS executes in 2 phases:
- Creation: Allocates memory —
var→undefined, functions → full definition,let/const→ TDZ - Execution: Runs code line by line
console.log(x); // undefined (var is hoisted)
var x = 5;
console.log(y); // ReferenceError (let TDZ)
let y = 5;
greet(); // "Hello" (function declaration fully hoisted)
function greet() { console.log("Hello"); }
hi(); // TypeError: hi is not a function (function expression not hoisted)
var hi = function() { console.log("Hi"); }
Scope & Closures
Closure: A function that remembers its outer variables even after the outer function has returned.
function createCounter() {
let count = 0; // private — not accessible outside
return function() {
return ++count;
};
}
const counter = createCounter();
counter(); // 1
counter(); // 2
Common Gotcha (loop + closure):
// Bug: all callbacks print 3
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Fix: use let (block-scoped per iteration)
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // 0, 1, 2
}
this Keyword
this is determined at call time, not definition time.
| Call style | this value |
|---|---|
obj.method() | obj |
method() (standalone) | undefined (strict) / window (sloppy) |
new Constructor() | new object |
| Arrow function | Inherits from lexical scope |
Arrow functions never have their own this — .call(), .apply(), .bind() cannot override it.
bind / call / apply
const user = { name: "Alice" };
function greet(greeting) { console.log(`${greeting}, ${this.name}`); }
greet.call(user, "Hello"); // runs immediately, args individually
greet.apply(user, ["Hello"]); // runs immediately, args as array
const bound = greet.bind(user); // returns new function, does NOT run
bound("Hello");
Objects & Prototype
Reference semantics: copying an object copies the reference.
const a = { x: 1 };
const b = a;
b.x = 2;
console.log(a.x); // 2 — same object
Prototype chain: JS looks up missing properties along __proto__ chain up to Object.prototype.
const animal = { breathes: true };
const dog = Object.create(animal); // dog.__proto__ === animal
dog.name = "Rex";
console.log(dog.breathes); // true — found on prototype
Writing always goes to the object itself, not the prototype.
Promises & Async/Await
3 states: Pending → Fulfilled / Rejected (immutable once settled)
Promise static methods
| Method | Behavior | Failure |
|---|---|---|
Promise.all(arr) | Wait for all to fulfill | Fail-fast on first rejection |
Promise.allSettled(arr) | Wait for all to finish | Never rejects, returns {status, value/reason} |
Promise.race(arr) | First to settle wins | Returns first result/error |
Promise.any(arr) | First to fulfill wins | Rejects only if all fail (AggregateError) |
// Sequential — slow (each waits for previous)
const a = await fetchA();
const b = await fetchB();
// Parallel — fast
const [a, b] = await Promise.all([fetchA(), fetchB()]);
Microtask queue: Promise callbacks (.then, .catch) run before setTimeout/setInterval macrotasks.
Event Loop
Call Stack → Microtask Queue → Macrotask Queue
(Promises, queueMicrotask) (setTimeout, setInterval, I/O)
console.log("1");
setTimeout(() => console.log("2"), 0);
Promise.resolve().then(() => console.log("3"));
console.log("4");
// Output: 1, 4, 3, 2
// Microtasks (Promises) always run before macrotasks (setTimeout)
Array Operations Complexity
| Operation | Time |
|---|---|
push() / pop() | O(1) |
shift() / unshift() | O(n) |
slice() / filter() / map() / reduce() | O(n) |
sort() | O(n log n) |
concat() | O(m + n) |
indexOf() / find() | O(n) |
Map & Set Complexity
| Operation | Map | Set |
|---|---|---|
get/set/has/delete | O(1) | O(1) |
clear() | O(n) | O(n) |
Map vs Object: Map keys can be any type (including objects). Map is iterable and has .size. Object keys are always strings/Symbols.
WeakMap: Keys must be objects. Weak references — entries auto-removed when key is GC'd. Not iterable.
JSON
JSON.stringify(obj) // Object → JSON string
JSON.parse(json) // JSON string → Object
See Also
- [[JavaScript DOM Notes]] — DOM tree, manipulation, events
- [[JavaScript Function Code Examples for Interviews]] — debounce, throttle, currying, polyfills, Promise implementations
- [[Java Script Language Topics]] — complexity tables reference