A function is a mapping from inputs to outputs plus optional side effects. Treat functions as units of behavior. Understand two orthogonal axes: (1) how functions are created/declared and (2) how they behave at runtime (scope, this, side effects, closures).
-
Declaration
function f(a){ return a+1; }
- Hoisted with binding. Safe to call before the line where defined.
- Named for stack traces and recursion.
-
Expression
const f = function(a){ return a+1; };
- Not hoisted. Useful for assigning or passing.
-
Named Function Expression
const f = function g(a){ return a+1; };
gavailable only inside the function for recursion.
-
IIFE (Immediately Invoked Function Expression)
(function(){ /* isolated scope */ })();
- Useful for module-like isolation before ES modules existed.
Pitfall: var hoisting with function expressions can produce undefined and runtime errors.
- Parameters are local bindings.
- Functions return
undefinedby default if noreturn. - The
argumentsobject is array-like for non-arrow functions. Prefer rest parameters.
Example:
function sum(...nums){
return nums.reduce((s,n)=>s+n,0);
}- Syntax:
const f = (a) => a*2. - No own
this.thisis lexical from enclosing scope. - No
argumentsobject. - Not constructible (
newfails). - Best for short callbacks or functions that should inherit
this.
Pitfall: Using arrow functions as object methods loses intended this.
-
Default:
function greet(name = "Guest"){ return `Hi ${name}`; }
-
Rest collects trailing args:
function concat(...parts){ return parts.join(''); }
Edge: Default parameters evaluated at call time.
- Closure: function + preserved lexical environment.
- Use cases: data privacy, factories, memoization.
- Memory: closures keep references to outer variables; avoid retaining large objects unintentionally.
Example (counter):
function counter(){
let n = 0;
return () => ++n;
}Common bug: closures in loops capturing same variable (use let to fix).
- Functions that accept or return functions.
- Use for composition, currying, decorators, middleware.
Implement compose, curry:
const compose = (f,g) => x => f(g(x));
const curry = fn => a => b => fn(a,b);- Pure: deterministic, no external side effects. Testable and cacheable.
- Impure: mutate external state, read from I/O, use randomness/time.
Prefer pure functions inside business logic. Isolate impure code at boundaries.
- Memoize
- Once
- Debounce / Throttle (related to events)
- Partial application / Currying
- Factory functions vs classes
Examples:
function memoize(fn){
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const val = fn(...args);
cache.set(key, val);
return val;
};
}- Write
multiplyAll(...nums)returning product. - Implement
once(fn)— runsfnonly the first time. - Convert a callback API to return a Promise.
- Implement
curry(fn)that curries a 2-arg function. - Show closure leak: create and then remove closure reference safely.
-
Which is true about arrow functions?
- a) They have their own
this - b) They cannot be used as constructors
- c) They create their own
argumentsobject - d) They are hoisted
- a) They have their own
-
What does
function f(){}hoisting mean?- a) Function available after definition only
- b) Function binding created at parse time and available anywhere in scope
- c) Function is blocked by
let
-
Which is a pure function?
- a)
x => x * 2 - b)
() => Date.now() - c)
() => Math.random()
- a)
- Implement
sum(...nums)usingreduce. - Implement
memoize.
const sum = (...nums) => nums.reduce((s,n)=>s+n,0);- See memoize above.
Objects are collections of key→value bindings; arrays are ordered collections. Both are reference types. Behavior depends on mutability, identity, and prototype chain.
-
Literal:
const obj = { a:1, b(){ return 2; } };
-
Property attributes:
writable,enumerable,configurable. -
Object.definePropertyfor precise control. -
Symbolfor hidden/unique keys.
Example:
const s = Symbol('id');
obj[s] = 123;Define computed properties while preserving encapsulation:
const user = {
first: 'A', last: 'B',
get full(){ return `${this.first} ${this.last}`; },
set full(v){ [this.first,this.last] = v.split(' '); }
};thisdetermined at call time.- Methods:
obj.method()→this=obj. - Use
bindto fixthis. - Arrow functions inherit
thislexically.
Pitfall: detaching a method loses this.
const m = obj.method;
m(); // wrong `this`- Every object has
[[Prototype]](__proto__). Object.create(proto)creates object with specified prototype.- Constructor functions +
.prototypeused historically. - ES6
classis syntactic sugar over prototype chain.
Pitfall: Mutating prototypes of built-ins can break code.
- Non-mutating:
map,filter,slice,concat - Mutating:
push,pop,splice,sort,reverse - Prefer immutability in pure functions; use spread or
sliceto copy. - Sparse arrays have holes; many array operations skip holes.
Reduce pattern:
const flatten = arr => arr.reduce((acc,x) => acc.concat(Array.isArray(x)? flatten(x) : x), []);-
Objects:
const {a, b:alias = 2, ...rest} = obj;
-
Arrays:
const [first, ...tail] = arr;
-
Spread to copy/merge:
const copy = {...obj};
Edge: Spread performs shallow copy only.
-
JSON.stringifyloses functions,undefined,Symbol. -
JSON.parsegives raw objects, not class instances. -
Use
structuredClone(modern) for deep clone when available:const clone = structuredClone(obj);
Pitfalls: circular references cause JSON.stringify to throw.
Object.freeze()shallow freeze.- Libraries: Immer, immutable.js.
- For reliable immutability, copy on write.
- Arrays are fastest for dense numeric-indexed data.
- Avoid creating many small objects in hot loops.
- Use
Map/Setfor frequent key-based operations.
- Implement
unique(arr)returning unique values usingSet. - Deep clone an object with nested arrays (no third-party libs). Show pitfalls.
- Use
reduceto group array of objects by a key. - Implement
pluck(arr, key)returns array of values for key. - Demonstrate difference between mutating and non-mutating
sort.
-
Which method returns a new array?
- a) forEach
- b) map
- c) push
- d) splice Answer: b
-
What is
typeof null?- a) object
- b) null
- c) undefined
-
What happens when you
JSON.stringifya function?- a) Serialized as string
- b) Ignored (omitted)
- c) Throws error
- Use
reduceto compute frequency map of words from["a","b","a"]. - Implement shallow copy of an object without
Object.assign.
const freq = arr => arr.reduce((m,x)=> (m[x]=(m[x]||0)+1,m), {});const copy = {...obj};The DOM is a live tree representation of the document. Interactions happen by selecting nodes, changing nodes, and responding to events. Structure, performance, and security are primary constraints.
- Node types: Element, Text, Comment.
documentis the root.- Properties vs attributes:
el.idvsel.getAttribute('id'). - Live vs static collections:
getElementsByClassNamereturns liveHTMLCollection.querySelectorAllreturns staticNodeList.
document.getElementById(id)— fastest for single ID.document.querySelector(selector)— flexible, slightly slower.- Prefer
querySelectorfor consistency unless profiling shows bottleneck.
Example:
const btn = document.querySelector('#submit');-
textContentfor plain text. -
innerHTMLparses HTML (security risk). -
Use
.classListto toggle classes:el.classList.add('is-active'); el.classList.toggle('open', shouldOpen);
-
Avoid inline styles where CSS classes suffice.
Security note: never insert user content via innerHTML without sanitization.
-
Create node:
const li = document.createElement('li'); li.textContent = 'Item'; list.appendChild(li);
-
Remove:
el.remove();
-
Use
DocumentFragmentfor batch inserts to reduce reflows.
-
Use
addEventListener(type, handler, options). -
Remove with
removeEventListenerand same function reference. -
Event delegation: attach single listener to parent and detect target via
event.target.closest(selector).- Reduces listeners and improves performance for dynamic lists.
Example:
list.addEventListener('click', e => {
const btn = e.target.closest('.btn');
if (!btn) return;
// handle
});- Default is bubbling (child → parent).
- Use
{ capture: true }to listen during capture phase. - Most code uses bubbling.
submitevent onform. Usee.preventDefault()to stop native submit.FormDatato gather form values safely.- Validate on
input/change. Use built-in constraints (required,pattern) for accessibility and progressive enhancement.
Example:
form.addEventListener('submit', e=>{
e.preventDefault();
const data = new FormData(form);
fetch('/submit', { method: 'POST', body: data });
});- Use semantic HTML (
<button>,<label>,<header>). - Manage focus programmatically:
element.focus(). - Use ARIA only when necessary. Keep tab order logical.
- Batch DOM writes. Read then write to avoid layout thrashing.
- Use
requestAnimationFramefor visual updates. - Remove event listeners when elements are removed to avoid leaks.
- Observe DOM changes efficiently.
const obs = new MutationObserver(records => { /* handle */ });
obs.observe(target, { childList:true, subtree:true });Use to react to structural changes without polling.
- Build a dynamic todo list: add, toggle complete, remove. Use event delegation.
- Implement debounce for an input
keyuphandler. - Create a modal component that traps focus and is keyboard-accessible.
- Demonstrate inserting 1000 list items with
DocumentFragmentand without, measure FPS.
-
Which is safest for inserting user-generated text?
- a) innerHTML
- b) textContent
- c) insertAdjacentHTML
-
Event delegation is useful because:
- a) It avoids propagation
- b) It reduces number of listeners for dynamic children
- c) It disables default behavior
-
querySelectorAllreturns:- a) Live NodeList
- b) Static NodeList
- Implement a single event listener on a
<ul>that toggles.doneclass for clicked<li>items. Model answer:
ul.addEventListener('click', e=>{
const li = e.target.closest('li');
if(!li || !ul.contains(li)) return;
li.classList.toggle('done');
});ES6+ introduced syntactic constructs and primitives that map more clearly to modern programming abstractions: modules, lexical scoping, asynchronous primitives, and better data structures. Understand semantics rather than syntax sugar.
- Backtick strings allow interpolation and multiline.
const msg = `Hi ${name}\nLine 2`;- Tagged templates let you process template parts.
function tag(parts, ...vals){ /* sanitize etc */ }
tag`Hello ${name}`;Use for safe HTML templating or custom interpolation.
-
Named export:
export function f(){} import { f } from './mod.js';
-
Default export:
export default function(){} import f from './mod.js';
-
Dynamic import:
const mod = await import('./mod.js');
-
Modules run in strict mode and have module scope.
Caveats: ESM vs CommonJS in Node. Use top-level await carefully.
- Default values and nested patterns.
const { a: { b = 2 } = {} } = obj;- Use destructuring for function parameters to reduce boilerplate.
Pitfall: destructuring null or undefined throws. Provide defaults.
- Spread for copying arrays/objects shallowly.
- Rest in parameter position gathers remaining items.
- Order matters: rest must be last in parameter list.
classis syntactic sugar; prototype chain remains.constructor,super,staticmethods, private fields (#).
class Base { #id; constructor(id){ this.#id = id; } }- Beware subclassing built-ins (Array) historically tricky.
- Promise states: pending → fulfilled/rejected.
thenchain returns new promises enabling pipeline.Promise.allrejects fast on first rejection.Promise.allSettledwaits for all results.asyncfunction returns a Promise.awaitpauses the async function until promise settles.awaitdoes not block event loop.
Error handling:
try{
const res = await fetch(url);
} catch(err){
// handle
}Microtask queue: resolved promises schedule microtasks which run before the next macrotask. This order matters for concurrency reasoning.
a?.bshort-circuits ifaisnullorundefined.x ?? yreturnsyonly ifxisnullorundefined.- Difference vs
||:0 || 'fallback'yields'fallback';0 ?? 'fallback'yields0.
- Arrow functions are not suited for methods meant to be dynamic
this. - They are suitable for callbacks and short functions that need lexical
this.
Map,Set,WeakMap,WeakSetfor different lifetime semantics.for...offor iterables.for...initerates keys (not recommended for arrays).Symbolfor unique property keys.BigIntfor integers beyondNumber.MAX_SAFE_INTEGER.
- Convert callback pyramid to
async/await. - Implement dynamic import to load feature module on demand.
- Create a class with private fields and static factory method.
- Demonstrate
Promise.allSettledusage and show how to process partial failures.
-
What does
a ?? breturn ifais0?- a) b
- b) 0
-
Which statement about
import()is true?- a) It returns the module synchronously
- b) It returns a Promise resolving to the module
-
classin JS:- a) Is a new runtime model different from prototypes
- b) Is syntactic sugar over prototypes
-
Implement:
- a. A function
fetchJson(url)returning parsed JSON withasync/awaitand error handling. - b. Use
Promise.allSettledto fetch multiple URLs and return successes only.
- a. A function
Model answers (short)
a.
async function fetchJson(url){
const res = await fetch(url);
if(!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}b.
async function fetchMany(urls){
const results = await Promise.allSettled(urls.map(u=>fetchJson(u)));
return results.filter(r=>r.status==='fulfilled').map(r=>r.value);
}Build a small single-page app (no frameworks) that:
-
Loads a list of items (simulate fetch with
Promise). -
Renders items using
DocumentFragment. -
Allows adding items via a form. Validate input.
-
Uses event delegation for item controls (edit, delete, toggle).
-
Stores data in
localStorage(serialize/deserialize with JSON). -
Expose a module structure:
api.js,ui.js,app.js. -
Provide unit-like tests (simple assertions) for:
memoizefunction.sumusingreduce.uniquefunction.
- Correct use of modules and
import/export. - No memory leaks. Event handlers removed properly.
- Clear separation: pure business logic vs DOM side effects.
- Use of modern features where appropriate (arrow functions, destructuring, optional chaining).
- Code readability: meaningful names, comments where needed.
- Tests present and passing.
- Functions MCQ answers: Functions section answers listed inline.
- Objects & Arrays MCQ answers: inline.
- DOM MCQ answers: inline.
- ES6+ MCQ answers: inline.
- Coding model answers: inline after respective sections.