Video guide
13:36 · 8 May 2024
JavaScript Interview Questions & Answers
Chapters 7 sections
Interview questions in this video:
- 01
1. What is event bubbling in JavaScript?
When an event fires on an element, the browser runs the handler on that element first, then walks up the DOM — parent, grandparent, all the way to the root — running every handler it finds on the way.
Click a button inside a form: the button's onclick runs, then the form's, then the document's. That upward traversal is bubbling.
DOM eventsEvent propagation - 02
2. What is event capturing, and how is it different from bubbling?
Capturing is the same traversal in the opposite direction: from the root down to the target, before the target's own handler runs. Then the bubbling phase goes back up.
It exists for historical reasons — Microsoft went one way, Netscape the other — and today capturing is opt-in via the third argument of addEventListener. In practice it's rarely used.
Capture phaseaddEventListener - 03
3. What is debouncing and when should you use it?
Debouncing delays a function until calls stop arriving for a set interval. Type in a search bar and the request fires half a second after the last keystroke — not on every letter.
Use it for high-frequency user events (typing, resizing) so you don't DDoS your own backend with a request per keypress.
Rate limitingSearch inputs - 04
4. console.log('first'); setTimeout(() => console.log('second'), 0); console.log('third'); — what prints, in what order?
first, third, second.
setTimeout with 0ms doesn't run immediately — its callback goes to the task queue and waits for the next tick of the event loop. The synchronous logs run first; the timeout callback runs when the call stack is empty.
Event loopTask queuesetTimeout - 05
5. What is the difference between prototypal inheritance and class inheritance?
Class inheritance relates classes via extends. Prototypal inheritance relates objects via the prototype chain: when you access a property that doesn't exist on an object, JavaScript walks up its prototype references until it finds it or runs out.
It's how JavaScript did code reuse and polymorphism before classes existed — and it's still what class syntax compiles down to.
Prototype chainObject model - 06
6. Is extending built-in prototypes (like String.prototype) a good idea?
No. It's an obscure global change: it can break on other platforms and runtimes, and other developers won't expect your custom methods on primitives.
If you want portable, extendable code, keep helpers as plain functions.
Monkey patchingPortability - 07
7. What does an async function return, and why?
Always a promise. async is syntax sugar over promises: the function body gets wrapped, and the returned promise resolves with whatever the function returns.
That's the whole relationship between async/await and promises — await just unwraps them in sequence.
async/awaitPromises - 08
8. What is a pure function and why are pure functions useful?
Same input, same output, no side effects — nothing outside the function changes.
Pure functions are deterministic and trivial to test, which is why functional patterns (and most state libraries) are built on them.
Functional programmingDeterminism - 09
9. What is polyfilling, and what are its drawbacks?
A polyfill is extra code that implements a language or platform feature for browsers that don't have it — e.g. replacing spread syntax for an old browser, via tooling like Babel.
The cost: a bigger bundle and more code to parse, so performance suffers. The smart move is shipping polyfills only to the browsers that need them.
BabelBrowser supportBundle size - 10
10. What is a closure? Give a practical example.
A function that remembers the scope where it was created. Declare a variable, define a function next to it, export that function — wherever it runs later, it still has access to that variable.
That's why a factory function can return a greeter that keeps using the name you gave the factory, long after the factory returned.
Lexical scopeFactory functions - 11
11. What is the drawback of closures?
Memory. Everything in the enclosed scope stays referenced for as long as the function lives, so the garbage collector can't reclaim it.
It's one reason JavaScript is memory-hungry — and why engineers from C++ backgrounds wince at careless closures.
Garbage collectionMemory pressure
Transcript
Hi folks, what's up? Senior Dev team, and today we're back with senior JavaScript questions. Bogdan, are you ready? Let's go. Awesome. So, question number one, this is a real question I've got in uh myself when doing interviews um a few years ago. And I know people are still asking it. What is event bubbling in JavaScript? So basically, we have a web page and we're going to have different elements in it that are nested into inside each other. So imagine we have this form and let me color this differently so we can see it. I have a button over here. That's going to submit the form. What happens with event bubbling? It's that when I click this button, the web browser will look for event handlers, and the way it will look for the on click handler on this um on this button is that it will traverse traverse. It will traverse the dome and look first to the event handler on this button and call that one. And then on this form, and then all the way up to the root element. So, whenever you have an event that happens on a specific element, it will first try to run the event handler on that element, and then all the other event handlers attach. All the way to the uh root element into the HTML element. Understood. Right, we talked about bubbling. What about capturing? So event capturing, it's pretty much the other way around, where the browser will look. At all the event handlers starting from the top all the way down, we're going to have a first phase where we do event capturing, we go down. Then a second one where we run the on click on the target, and then a third one where we bubble. I think it was Microsoft that introduced capturing back when they were building the first browser. Netscape, however, went into the direction of bubbling. And nowadays we have both behaviors, but capturing is pretty much hidden and it can only turn it on
API is extra option and it's most likely almost never used. Understood. Now, we're going to move on with the next question. What is debouncing? Like and when should we use debounces? Um, so function debouncing, it's very useful whenever you are handling some sort of events. So imagine you are building a website, it has a search bar, and as users type, they get different suggestions, like when you're building google.com.
Um, you might not want to make a request to your back end every time somebody types a single letter. So that's when you can debounce the event handler. So let's say you debounce it with an interval of half a second. If somebody calls a function and in an interval of half a second, they call it again, you'd always take into account this last execution. So it's almost like waiting for half a second so they do nothing and then executing.
And in that way, you can avoid invoking something too many times, you can avoid DOSing your own back end, kind of denial of service because you're sending too many requests. And so it's very useful when you're dealing with user interfaces and there's some user events that the user maybe uh will will trigger many times, specifically when you're when they're typing. Awesome. Awesome. Since your link, I want you to open up that link and I want you to take a look at that code and tell me in which order will the console logs be printed in this code?
Yeah. Okay, so okay, line two. I see a console log first, this will definitely print to the console because it's synchronous. Um, then we have the set timeout, which is basically set to zero. But probably this will get pushed to the next tick, just because of how set timeout works. So, even if this is set to zero, we probably will have to wait until the next tick of the event loop. Um and this part, this will go in before that tick.
So I would expect first, then third, and then two, just because set timeout will push this callback to the next tick of the event loop. Can you clean the console and run this again with a refresh? So the first and the third I bring printed out and the set timeout sends the second one to to the next tick. Awesome. Then um we will move on with another very exciting topic and I want you to still open up that code and scroll down a bit because we will talk about prototypal inheritance.
Uh the first thing I want you to talk about is, you know, what's the difference between prototypal inheritance and class inheritance? The the main difference is that prototypal inheritance is based on the prototype property on an object. Class inheritance is done with the extend um keyword. It's you when you inherit classes, it's literally classes inheriting from each other, rather with prototypal inheritance, you have objects related to each other, and they do that with the prototype property.
So in JavaScript, if you're using any object and you try to access a method on that object, JavaScript will check if it's the does this function exists or a property on this object. And if it doesn't, it will look for the proto property and see if there's any um parent down the prototypal chain, if there's any parent to this object, and then check that property on that one too. So, it's basically a way to have some sort of inheritance in a language that traditionally didn't supported any inheritance, which is JavaScript.
And it was a way to achieve some sort of object-oriented flavor in in JavaScript in the early days when we we literally have no classes and there was no way to reuse code or to to have some sort of polymorphism. Awesome, understood now. For example, like looking at this code, to extend the behavior of that string class that you have there, we want to change the string prototype. Is that a good idea?
Probably not. The reason for that is if you want your code to be portable, you really don't want to modify any of the primitive prototypes. Um it's usually a very obscure change we're making in the code, and it can happen that if we go over to a different platform, like we want to run this in Node.js, or in a different browser, you can have all sorts of issues. So we really try to avoid extending this. And the other thing is you might want your code base to be extendable by many or other developers that are not familiar with our specific extension. So this is usually a very bad idea. Awesome. Understood. Cool. Uh we're going to move on to a whole different topic. Uh we will talk about async functions. What does an async function returns and why? Mhm. Okay. So basically, async await is just a syntax sugar for promises. And whenever you write a sync in front of a function, it will basically wrap that code in a promise and return a promise that will resolve with the return of that function. So whenever you have an async function, that function will return a promise that will end up resolving with whatever the return of that function is. You already answered my um next next question, which has, what is the relationship between async await and and promises and you said it very well. Now, let's talk a bit about what is a pure function and when are pure function useful in JavaScript. A pure function, it's very useful when you're using functional programming, because it really does not modify anything else. It has no what we call side effects. You really give an input and you get an output and there is no other change to any global state of the system or any call outside the system and they are extremely good because they're very deterministic. So you always know that your code given a certain input, you'll get a certain output. They're extremely easy to test, it's heavily used in functional programming, but it's also heavily used in most JavaScript code bases I've worked on because it really makes everything a lot simpler. Cool. By the way, we have a a few more questions to go. Are you ready? Yeah, let's go. Awesome. Very quick on, what is polyfilling in JavaScript and
What would be some drawbacks to polyfilling your code? Uh sure, so polyfilling is when you add extra code to make up for the fact that the browsers you ship your code to do not have a specific language feature. So let's say back in the days you wanted to use the spread operator, it's not possible to use the spread operator in Internet Explorer 11. You have to ship your code to Internet Explorer 11 because your users use that.
Then you basically replace, you take your code base and whenever you had a spread operator, you replace it with a function, let's say. Literally string replacements. Um, and you can do that with Bab tools like Babel. The big disadvantage is you're shipping a lot more code. So your bundle becomes a lot bigger. Um, you have performance issues, right? Because all that code has to get interpreted. So polyfills are usually a drawback and there's very smart way to um, to work around that is to only ship polyfills to do specific browsers, really beautiful browsers sniffing.
Yeah, that's one of the tragedies of uh software web developers, right? We have to support, you know, all kind of browsers and they are not always up to date and they don't always have a shared understanding of of um, yeah, of the implementation. So we have to ship those polyfills to to make up for that. Uh. Awesome. Another question which is a cornerstone question in JavaScript. And we will talk about closureists.
Closures, closures, closures. You probably heard about closures. Um, I want you to, yeah, just define a closure as um, you know, in the in the the straight way possible you can in the most straight way possible you can. And maybe give me a real life example of where would you use that in JavaScript. Um, sure. Yeah, closures are not a JavaScript specific concept that you can find them in different languages.
But it basically means that um functions enclose um different variables that are there when the function is declared and by enclosing means they remember that. So basically it means whenever you import or use a function, you also get by default all the scope where that function was created. So if there was a variable at the root level, the function has access to that forever until you never use that function again.
And I can demonstrate that really quickly with the code you send me before, let me just share my screen. So basically, if I would have a function here that says say hello, hello, um, and it will just let's say it just console.log some sort of variables that I have here, let's say I have a variable called name, and that will be your name, and we're just going to console log that. If I were to import this or let's say I export this function, if someone will import and run this, the function will still work, because even if they provide an argument or not, it will actually look in the function scope and then in the global scope and find this variable.
Even if this variable is not present where this function is being called, it's only present in this module. Another way you could show this is if you return here another function, let's say, you actually create, say I say create, say hello, and you actually return a function that is say hello, and it does pretty much the same. It console logs the name, but in this case, I'll put a name in this scope.
So scope is basically whatever you see that's surrounded by um, curly brackets. So right now, if I use say hello outside here, it will still work. So if I actually go ahead and say say hello and this is equal to the create say hello function, and then I call this say hello, say, it will still work. I'll get no exception even if in this scope I do not have a name. We got to that point the function is not you don't only get the function, you get the whole scope, the whole lexical environment.
You know, what's the drawback of this? The drawback is you're putting a lot of pressure on the memory because everything that's in this scope, it's still a reference by this function, as long as this function is being used, so we cannot remove it from memory, we cannot release that memory with uh by, you know, by the garbage collection algorithms. Basically, in simple words, JavaScript cannot clean up, it cannot really get rid of anything that it's in the scope of this function.
And that means um you put a lot of pressure in memory. That's why traditionally, we all know that JavaScript is not a super memory efficient language. It actually needs a lot of RAM memory. This is why um a lot of developers coming from, you know, C++, languages are a lot more careful with the garbage collection. You get all these memes on the internet, oh, JavaScript, you know, a bad language. Well, Bogdan, this was it for today.
If you have any question that you would like Bogdan and I to address in one of those videos, just drop it in the comments, uh we'll pick it up and add it to one of our next videos. And finally, if you want Bogdan and I to personally mentor you to become a confident, competent, senior developer, then click the link uh below the kindly link, you can book a short call with me, we're going to get to know each other, see, hey, you know, can we help you? What are you struggling with? Can this be a fit?
And after that, if you'll be interested, we can talk about you uh working with us, helping you get your developer career to a whole new level. With that being said, thank you so much, Bogdan, for today and we will see you in the next one.