
Understanding core JavaScript concepts is essential for acing a junior developer interview. This article covers common interview questions, providing explanations and code snippets to illustrate each concept.
1. What is the difference between var
, let
, and const
?
var
declares a function-scoped or globally-scoped variable, while let
and const
are block-scoped. const
also prevents reassignment of the variable.
Variables declared with var
can be re-declared in the same scope and attach to the global object when declared globally, which may cause unexpected behavior. In contrast, let
and const
throw errors when re-declared in the same block and remain block-scoped.
var globalVar = 'old';
if (true) {
var globalVar = 'new'; // Re-declared in the same scope
let blockLet = 'block';
const blockConst = 'constant';
}
console.log(globalVar); // 'new'
Sources:
2. Explain hoisting.
Hoisting is JavaScript's behavior of moving declarations to the top of their scope before code execution. Function declarations and variable declarations using var
are hoisted, whereas let
and const
are not initialized until the code executes.
During hoisting, declarations are moved but assignments stay in place. Calling a variable before assignment returns undefined
. Only function declarations are fully hoisted, while function expressions and arrow functions behave like variables.
console.log(a); // undefined
var a = 5;
Source:
3. What are closures?
A closure occurs when a function retains access to its lexical scope even when executed outside that scope. Closures are commonly used for data privacy and creating factory functions. This ability to remember the surrounding scope allows functions to maintain private variables, enabling patterns like once functions, memoization, and currying.
function makeCounter() {
let count = 0;
return function () {
count++;
return count;
};
}
const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
Source:
4. What is event bubbling?
Event bubbling is the propagation of events from the deepest target element upward through the DOM tree. You can stop propagation with event.stopPropagation()
.
Events first trigger on the innermost element, then bubble up to ancestors unless the handler stops propagation. The opposite phase is event capturing, which triggers handlers from the root down before the bubbling phase.
<div id="outer">
<button id="inner">Click me</button>
</div>
const outer = document.getElementById('outer');
const inner = document.getElementById('inner');
outer.addEventListener('click', () => console.log('Outer clicked'));
inner.addEventListener('click', e => {
console.log('Inner clicked');
// e.stopPropagation(); // Uncomment to stop bubbling
});
Source:
5. How do promises and async/await
handle asynchronous code?
Promises represent the eventual result of an asynchronous operation. async/await
simplifies promise-based code by allowing asynchronous logic to be written in a synchronous style. They provide methods like then
and catch
for chaining actions once the asynchronous task finishes or fails. When used with async
functions, you can handle errors using try/catch
, making asynchronous code easier to read.
function fetchData() {
return new Promise(resolve => {
setTimeout(() => resolve('Done'), 1000);
});
}
async function run() {
const result = await fetchData();
console.log(result); // 'Done'
}
run();
Sources:
6. What are the primitive data types in JavaScript?
JavaScript has seven primitive data types: string
, number
, bigint
, boolean
, undefined
, symbol
, and null
. These types are immutable, meaning their values cannot be changed once created. Non-primitive types like objects and arrays are mutable and passed by reference.
const name = 'Jane';
const age = 30;
const big = 123n;
const active = true;
let unknown;
const id = Symbol('id');
const empty = null;
Source:
7. How does this
work in JavaScript?
this
is determined by how a function is called. In the global context, this
refers to the global object (window
in browsers). Inside an object method, this
refers to that object. Arrow functions do not have their own this
; they inherit it from the surrounding scope. Methods like call
, apply
, and bind
can explicitly set the this
value.
const obj = {
value: 42,
regular() {
console.log(this.value); // 42
},
arrow: () => {
console.log(this.value); // undefined in most cases
},
};
obj.regular();
obj.arrow();
Source:
8. What is the difference between ==
and ===
?
==
compares values after performing type coercion, which can lead to unexpected results. ===
checks both value and type without coercion, making it the preferred choice for most comparisons.
0 == '0'; // true
0 === '0'; // false
Source:
9. Explain the event loop in JavaScript.
The event loop handles asynchronous operations by coordinating the call stack and task queues. When the stack is empty, the loop processes messages from the queue, executing callbacks. Promises use the microtask queue, which has priority over the macrotask queue used by setTimeout
.
console.log('start');
setTimeout(() => console.log('timeout'), 0);
Promise.resolve().then(() => console.log('promise'));
console.log('end');
// Output: start, end, promise, timeout
Source:
10. What is destructuring assignment?
Destructuring allows extracting values from arrays or properties from objects into distinct variables, making code more concise and readable.
const [first, second] = [1, 2];
const { name, age } = { name: 'Jane', age: 30 };
Source:
References
- MDN Web Docs – Comprehensive JavaScript documentation.
- JavaScript.info – Tutorials and explanations on core JavaScript concepts.