惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

K
Kaspersky official blog
小众软件
小众软件
Engineering at Meta
Engineering at Meta
博客园 - 三生石上(FineUI控件)
WordPress大学
WordPress大学
G
Google Developers Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
V2EX
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Google DeepMind News
Google DeepMind News
Security Archives - TechRepublic
Security Archives - TechRepublic
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
C
Check Point Blog
aimingoo的专栏
aimingoo的专栏
罗磊的独立博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
MongoDB | Blog
MongoDB | Blog
L
LINUX DO - 热门话题
酷 壳 – CoolShell
酷 壳 – CoolShell
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
H
Help Net Security
Martin Fowler
Martin Fowler
G
GRAHAM CLULEY
Simon Willison's Weblog
Simon Willison's Weblog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - Franky
V
Vulnerabilities – Threatpost
云风的 BLOG
云风的 BLOG
博客园_首页
C
Cybersecurity and Infrastructure Security Agency CISA
量子位
Stack Overflow Blog
Stack Overflow Blog
Recent Announcements
Recent Announcements
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
I
Intezer
Scott Helme
Scott Helme
A
About on SuperTechFans
博客园 - 司徒正美
Hacker News: Ask HN
Hacker News: Ask HN
The GitHub Blog
The GitHub Blog
Forbes - Security
Forbes - Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园 - 聂微东
人人都是产品经理
人人都是产品经理
The Cloudflare Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Spread Privacy
Spread Privacy
T
Tailwind CSS Blog
S
Security Affairs
宝玉的分享
宝玉的分享

Dmitri Pavlutin Blog

Pure Functions in JavaScript: A Beginner's Guide Record Type in TypeScript: A Quick Intro How to Write Comments in React: The Good, the Bad and the Ugly 4 Ways to Create an Enum in JavaScript React forwardRef(): How to Pass Refs to Child Components TypeScript Function Types: A Beginner's Guide How to Use v-model to Access Input Values in Vue Mastering Vue refs: From Zero to Hero Environment Variables in JavaScript: process.env 5 Must-Know Differences Between ref() and reactive() in Vue How to Destructure Props in Vue (Composition API) Triangulation in Test-Driven Development How to Use nextTick() in Vue Programming to Interface Vs to Implementation A Smarter JavaScript Mapper: array.flatMap() Array Grouping in JavaScript: Object.groupBy() How to Access ES Module Metadata using import.meta JSON Modules in JavaScript How to Trim Strings in JavaScript TypeScript Function Overloading How to Debounce and Throttle Callbacks in Vue How to Show/Hide Elements in Vue Sparse vs Dense Arrays in JavaScript How to Fill an Array with Initial Values in JavaScript Covariance and Contravariance in TypeScript What are Higher-Order Functions in JavaScript? How to Use TypeScript with React Components Index Signatures in TypeScript How to Use React useReducer() Hook unknown vs any in TypeScript A Guide to React Context and useContext() Hook How to Use Promise.any() 2 Ways to Remove a Property from an Object in JavaScript 'return await promise' vs 'return promise' in JavaScript How to Use Promise.allSettled() How to Use fetch() with JSON JavaScript Promises: then(f,f) vs then(f).catch(f) What is a Promise in JavaScript? How to Use Promise.all() A Simple Guide to Component Props in React Don't Stop Me Now: How to Use React useTransition() hook A Simple Explanation of JavaScript Variables: const, let, var ES Modules Dynamic Import How to Memoize with React.useMemo() How to Cleanup Async Effects in React Why Math.max() Without Arguments Returns -Infinity How to Debounce and Throttle Callbacks in React Don't Confuse Function Expressions and Function Declarations in JavaScript How to Use ES Modules in Node.js Solving a Mystery Behavior of parseInt() in JavaScript How to Use Array Reduce Method in JavaScript 3 Ways to Merge Arrays in JavaScript A Guide to Jotai: the Minimalist React State Management Library The Difference Between Values and References in JavaScript How to Implement a Queue in JavaScript A Helpful Algorithm to Determine "this" value in JavaScript React useRef() Hook Explained in 3 Steps 7 Interview Questions on "this" keyword in JavaScript. Can You Answer Them? How to Greatly Enhance fetch() with the Decorator Pattern What's a Method in JavaScript? array.sort() Does Not Simply Sort Numbers in JavaScript How to Solve the Infinite Loop of React.useEffect() The New Array Method You'll Enjoy: array.at(index) What's the Difference between DOM Node and Element? Why Promises Are Faster Than setTimeout()? Everything About Callback Functions in JavaScript How React Updates State 5 Mistakes to Avoid When Using React Hooks 5 Best Practices to Write Quality JavaScript Variables Type checking in JavaScript: typeof and instanceof operators 3 Ways to Check if a Variable is Defined in JavaScript React Forms Tutorial: Access Input Values, Validate, Submit Forms Prototypal Inheritance in JavaScript How to Timeout a fetch() Request How to Learn JavaScript If You're a Beginner A Simple Explanation of React.useEffect() A Simple Explanation of JavaScript Iterators How to Use React Controlled Inputs Everything about null in JavaScript How to Use Fetch with async/await Getting Started with Arrow Functions in JavaScript An Interesting Explanation of async/await in JavaScript Front-end Architecture: Stable and Volatile Dependencies Is it Safe to Compare JavaScript Strings? How to Access Object's Keys, Values, and Entries in JavaScript What Actually is a String in JavaScript? 3 Ways to Shallow Clone Objects in JavaScript (w/ bonuses) Checking if an Array Contains a Value in JavaScript JavaScript Event Delegation: A Beginner's Guide How to Parse URL in JavaScript: hostname, pathname, query, hash 3 Ways to Detect an Array in JavaScript How to Get the Screen, Window, and Web Page Sizes in JavaScript 3 Ways to Check If an Object Has a Property/Key in JavaScript How to Compare Objects in JavaScript Object.is() vs Strict Equality Operator in JavaScript Own and Inherited Properties in JavaScript 5 Differences Between Arrow and Regular Functions How to Use Object Destructuring in JavaScript Your Guide to React.useCallback() 5 JavaScript Scope Gotchas
7 Interview Questions on JavaScript Closures. Can You Answer Them?
Dmitri Pavlutin · 2021-02-09 · via Dmitri Pavlutin Blog

Every JavaScript developer must know what a closure is. During a JavaScript coding interview there's a good chance you'll get asked about the concept of closures.

I compiled a list of 7 interesting and increasingly challenging questions on JavaScript closures.

Take a pencil and a piece of paper, and try to answer the questions without looking at the answers, or running the code. In my estimation, you would need about 30 minutes.

Have fun!

If you need a refresh on closures, I recommend checking the post A Simple Explanation of JavaScript Closures.

Table of Contents

  • Questions 1: Closures raise your hand
  • Questions 2: Lost in parameters
  • Questions 3: Who's who
  • Questions 4: Tricky closure
  • Questions 5: Right or wrong message
  • Questions 6: Restore encapsulation
  • Questions 7: Smart multiplication
  • Summary

Questions 1: Closures raise your hand

Consider the following functions clickHandler, immediate, and delayedReload:


let countClicks = 0;

button.addEventListener('click', function clickHandler() {

countClicks++;

});



const result = (function immediate(number) {

const message = `number is: ${number}`;

return message;

})(100);



setTimeout(function delayedReload() {

location.reload();

}, 1000);


Which of these 3 functions access outer scope variables?

Expand answer
  1. clickHandler accesses the variable countClicks from the outer scope.
  2. immediate doesn't access any variables from the outer scope.
  3. delayedReload accesses the global variable location from the global scope (aka the outermost scope).

Questions 2: Lost in parameters

What will log to console the following code snippet:


(function immediateA(a) {

return (function immediateB(b) {

console.log(a); // What is logged?

})(1);

})(0);


Expand answer

0 is logged to the console. Open the demo.

immediateA is called with the argument 0, thus a parameter is 0.

immediateB function, being nested into immediateA function, is a closure that captures a variable from the outer immediateA scope, where a is 0. Thus console.log(a) logs 0.

Questions 3: Who's who

What will log to console the following code snippet:


let count = 0;

(function immediate() {

if (count === 0) {

let count = 1;

console.log(count); // What is logged?

}

console.log(count); // What is logged?

})();


Expand answer

1 and 0 is logged to the console. Open the demo.

The first statement let count = 0 declares a variable count.

immediate() is a closure that captures the count variable from the outer scope. Inside of the immediate() function scope count is 0.

However, inside the conditional, another let count = 1 declares a local variable count, which overwrites count from outer the scope. The first console.log(count) logs 1.

The second console.log(count) logs 0, since here count variable is accessed from the outer scope.

Questions 4: Tricky closure

What will log to console the following code snippet:


for (var i = 0; i < 3; i++) {

setTimeout(function log() {

console.log(i); // What is logged?

}, 1000);

}


Expand answer

3, 3, 3 is logged to console. Open the demo.

The code snippet executes in 2 phases.

Phase 1

  1. for() iterating 3 times. During each iteration a new function log() is created, which captures the variable i. setTimout() schedules log() for execution after 1000ms.
  2. When for() cycle completes, i variable has value 3.

Phase 2

The second phase happens after 1000ms:

  1. setTimeout() executes the scheduled log() functions. log() reads the current value of variable i, which is 3, and logs to console 3.

That's why 3, 3, 3 is logged to the console.

Side challenge: how would you fix this example to log 0, 1, 2 values after passing 1 second? Write your solution in a comment below!

Questions 5: Right or wrong message

What will log to console the following code snippet:


function createIncrement() {

let count = 0;

function increment() {

count++;

}

let message = `Count is ${count}`;

function log() {

console.log(message);

}

return [increment, log];

}

const [increment, log] = createIncrement();

increment();

increment();

increment();

log(); // What is logged?


Expand answer

'Count is 0' is logged to console. Open the demo.

increment() function has been called 3 times, effectively incrementing count to value 3.

message variable exists within the scope of createIncrement() function. Its initial value is 'Count is 0'. However, even if count variable has been incremented a few times, message variable always holds 'Count is 0'.

log() function is a closure that captures message variable from the createIncrement() scope. console.log(message) logs 'Count is 0' to console.

Side challenge: how would you fix log() function to return the message having the actual count value? Write your solution in a comment below!

Questions 6: Restore encapsulation

The following function createStack() creates instances of stack data structure:


function createStack() {

return {

items: [],

push(item) {

this.items.push(item);

},

pop() {

return this.items.pop();

}

};

}

const stack = createStack();

stack.push(10);

stack.push(5);

stack.pop(); // => 5

stack.items; // => [10]

stack.items = [10, 100, 1000]; // Encapsulation broken!


The stack works as expected, but with one small problem. Anyone can modify items array directly because stack.items property is exposed.

That's an issue since it breaks the encapsulation of the stack: only push() and pop() methods should be public, but stack.items or any other details shouldn't be accessible.

Refactor the above stack implementation, using the concept of closure, such that there is no way to access items array outside of createStack() function scope:


function createStack() {

// Write your code here...

}

const stack = createStack();

stack.push(10);

stack.push(5);

stack.pop(); // => 5

stack.items; // => undefined


Expand answer

Here's a possible refactoring of createStack():


function createStack() {

const items = [];

return {

push(item) {

items.push(item);

},

pop() {

return items.pop();

}

};

}

const stack = createStack();

stack.push(10);

stack.push(5);

stack.pop(); // => 5

stack.items; // => undefined


Open the demo.

items has been moved to a variable inside createStack() scope.

Thanks to this change, from the outside of createStack() scope, there is no way to access or modify items array. items is now a private variable, and the stack is encapsulated: only push() and pop() method are public.

push() and pop() methods, being closures, capture items variable from createStack() function scope.

Questions 7: Smart multiplication

Write a function multiply() that multiples 2 numbers:


function multiply(num1, num2) {

// Write your code here...

}


If multiply(num1, numb2) is invoked with 2 arguments, it should return the multiplication of the 2 arguments.

But if invoked with 1 argument const anotherFunc = multiply(num1), the function should return another function. The returned function when called anotherFunc(num2) performs the multiplication num1 * num2.


multiply(4, 5); // => 20

multiply(3, 3); // => 9

const double = multiply(2);

double(5); // => 10

double(11); // => 22


Expand answer

Here's a possible implementation of multiply() function:


function multiply(number1, number2) {

if (number2 !== undefined) {

return number1 * number2;

}

return function doMultiply(number2) {

return number1 * number2;

};

}

multiply(4, 5); // => 20

multiply(3, 3); // => 9

const double = multiply(2);

double(5); // => 10

double(11); // => 22


Open the demo.

If number2 parameter is not undefined, then the function simply returns number1 * number2.

But if number2 is undefined, it means that multiply() function has been called with one argument. In such a case let's return a function doMultiply() that when later invoked performs the actual multiplication.

doMultiply() is a closure because it captures number1 variable from multiply() scope.

Summary

Compare your answers with the answers in the post:

  • You have a good understanding of closures if you answered correctly 5 or more questions
  • But you need a good refresher on closures if you answered correctly less than 5 questions. I recommend checking my post A Simple Explanation of JavaScript Closures.

Ready for a new challenge? Try to solve the 7 Interview Questions on "this" keyword in JavaScript.