What is a closure in JavaScript?
A closure is a function that keeps access to the variables of the scope it was created in, even after that scope has finished. Each outer call creates a separate set.
JavaScriptfunction makeCounter() { let count = 0; return { increment: () => ++count, get: () => count, }; } const a = makeCounter(); const b = makeCounter(); a.increment(); a.increment(); b.increment(); console.log(a.get(), b.get());aandbcount separately, and nothing outside can touchcount. More in closures.What is hoisting in JavaScript?
Declarations are processed before the code runs, so names exist from the start of their scope. Function declarations are hoisted with their body,
varasundefined, andlet,constandclasscannot be used before their line.JavaScriptconsole.log(greet()); console.log(typeof later); function greet() { return 'hoisted'; } var later = () => 'not yet'; try { console.log(notYet); } catch (e) { console.log(e.name); } let notYet = 1;A function expression assigned to
varbehaves like thevar, sotypeof laterisundefined.What is the temporal dead zone?
The temporal dead zone is the time between entering a scope and the line that declares a
let,constorclass; touching the name then throws aReferenceError.JavaScriptfunction check() { try { return value; } catch (e) { return e.message; } } console.log(check()); const value = 1; console.log(check());It is about when code runs, not where it is written: the second call, after the declaration, returns
1.What is scope in JavaScript, and what is lexical scope?
Scope is where a name is visible: global, module, function or block (
let,const,classinside{}). Lexical scope means a function sees the variables where it was written, not where it is called.const level = 'global'; function outer() { const level = 'outer'; return function inner() { return level; // 'outer', found by walking up where inner was defined }; }Lookups walk outward to the global scope, and a name never found throws a
ReferenceError.What do arrow functions pushed in a
varloop return when called?JavaScriptconst fns = []; for (var i = 0; i < 3; i++) { fns.push(() => i); } console.log(fns.map(f => f()).join(' '));varmakes oneishared by all three arrows, and it is3by the time they run. Withlet, each iteration gets its owniand it prints0 1 2.What is an IIFE and why was it used?
An IIFE (immediately invoked function expression) is defined and called in one expression, giving its variables a private scope.
JavaScriptconst config = (() => { const secret = 'abc123'; return { masked: secret.slice(0, 2) + '****' }; })(); console.log(config.masked, typeof secret);Modules and block scope replaced it for privacy; it survives as
(async () => { ... })()to useawaitat the top level of a script.How do you write a memoize function?
Memoization caches results by argument, so a repeated call returns the stored answer. A closure holds the cache.
JavaScriptfunction memoize(fn) { const cache = new Map(); return n => { if (cache.has(n)) return cache.get(n); const result = fn(n); cache.set(n, result); return result; }; } let calls = 0; const square = memoize(n => { calls++; return n * n; }); square(4); square(4); square(5); console.log(calls);callsis2because the secondsquare(4)hit the cache. It suits only pure functions, and an unbounded cache leaks memory.Practice it: Climbing Stairs, Fibonacci Number
What is the difference between debounce and throttle?
Debounce runs once after calls stop for a set time; throttle runs at most once per time window. Debounce suits search boxes, throttle suits scroll handlers.
JavaScriptfunction debounce(fn, ms) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), ms); }; } function throttle(fn, ms) { let last = 0; return (...args) => { const now = Date.now(); if (now - last >= ms) { last = now; fn(...args); } }; } const search = debounce(q => console.log('searching', q), 50); search('j'); search('ja'); search('jav'); const onScroll = throttle(y => console.log('scroll', y), 1000); onScroll(1); onScroll(2); onScroll(3);This prints
scroll 1at once (calls 2 and 3 fall in the same window), thensearching jav50 ms later.What is variable shadowing, and what is illegal shadowing in JavaScript?
Shadowing is declaring a variable with the same name in an inner scope; inside it, the inner one hides the outer. Illegal shadowing is a
varin a block that already sits in the scope of aletwith that name:varwould escape the block and clash, so it is aSyntaxError.JavaScriptlet level = 'global'; function show() { let level = 'function'; { let level = 'block'; console.log(level); } console.log(level); } show(); console.log(level); try { new Function('let a = 1; { var a = 2; }'); } catch (e) { console.log(e.name); } new Function('var b = 1; { let b = 2; }'); console.log('let inside var scope is fine');The reverse, a
letin a block inside avar's scope, is allowed.How do you write a
oncefunction that runs a callback only one time?Return a wrapper that closes over a flag and the first result: the first call runs the function, later calls return the saved result.
JavaScriptfunction once(fn) { let called = false; let result; return function (...args) { if (!called) { called = true; result = fn.apply(this, args); } return result; }; } const connect = once((name) => { console.log('connecting as', name); return 42; }); console.log(connect('ada'), connect('bob'));It logs
connecting as adaonce, then42 42. Using a regularfunctionfor the wrapper keepsthis, so it also works on methods. It is the same closure pattern as a counter, used for initialization code.
JavaScript Closures, Scope and Hoisting Interview Questions
How JavaScript decides which variable a name refers to, and the closure patterns built on it.