1. What is the difference between let and var?
| Feature | var | let |
|---|---|---|
| Availability | Available from the beginning of JavaScript | Introduced in ES6 |
| Scope | Function scope | Block scope |
| Hoisting | Hoisted and initialized with undefined | Hoisted but not initialized (Temporal Dead Zone) |
| Redeclaration | Can be redeclared in the same scope | Cannot be redeclared in the same scope |
| Global object property | Becomes a property of the global object (window) | Does not become a property of the global object |
Example:
function userDetails(username) {
if (username) {
console.log(salary); // undefined (hoisted)
console.log(age); // ReferenceError: Cannot access 'age' before initialization
let age = 30;
var salary = 10000;
}
console.log(salary); // 10000 (function scope)
console.log(age); // ReferenceError: age is not defined (block scope)
}
userDetails("John");2. What is Hoisting?
Hoisting is JavaScript's behavior where variable and function declarations are moved to the top of their containing scope during the compilation phase, before the code is executed.
console.log(myVar); // undefined
var myVar = 10;
console.log(myVar); // 10
// Function declaration (fully hoisted)
myFun(); // "Hi"
function myFun() {
console.log('Hi');
}
// Function expression (not hoisted)
mySum(); // ReferenceError: mySum is not defined
const mySum = function(a, b) {
return a + b;
};Key Points:
- Function declarations: Fully hoisted, can be called before definition
- Function expressions: Not hoisted
varvariables: Hoisted but initialized withundefinedlet/constvariables: Hoisted but not initialized (Temporal Dead Zone)- Class declarations: Not hoisted
3. What is the difference between Reference types and Primitive types?
Primitive Types
Store the actual value directly. They are immutable.
let num = 5; // Number
let str = 'Hi'; // String
let bool = true; // Boolean
let und = undefined; // Undefined (variable declared but not assigned)
let nul = null; // Null (intentional absence of value)
let sym = Symbol('id'); // Symbol (unique identifier)
let big = 1234567890123456789012345678901234567890n; // BigIntReference Types
Store a reference (memory address) to the value. They are mutable.
let arr = [1, 2, 3]; // Array
let obj = {name: "alice", age: 22}; // Object
let func = function() { // Function
console.log('hi');
};
let date = new Date(); // DateKey Differences:
| Primitive Types | Reference Types |
|---|---|
| Stored in Stack memory | Stored in Heap memory |
| Copy creates a new value | Copy creates a reference to the same value |
| Compared by value | Compared by reference |
| Immutable | Mutable |
4. Difference between arrow functions and regular functions
Regular Functions
function regularFunc() {
console.log(this); // Depends on how called
}
const obj = {
method: function() {
console.log(this); // Refers to obj
}
};Characteristics:
- Have their own
thiscontext - Can be used as constructors with
new - Have
argumentsobject - Have
prototypeproperty - Can use
yieldin generator functions
Arrow Functions
const arrowFunc = () => {
console.log(this); // Inherits from parent scope
};
const obj = {
method: () => {
console.log(this); // Refers to parent scope, not obj
}
};Characteristics:
- Inherit
thisfrom surrounding lexical scope - Cannot be used as constructors (no
newkeyword) - No
argumentsobject (use rest parameters instead) - No
prototypeproperty - Shorter syntax
- Implicit return when using concise body
5. How does the this keyword work in different contexts?
The this keyword refers to different objects depending on how and where it's used.
// 1. Global context
console.log(this); // In browser: Window object
// In Node.js: Global object
// 2. Function context (non-strict mode)
function showThis() {
console.log(this); // Window object (in browser)
}
// 3. Function context (strict mode)
function showThisStrict() {
'use strict';
console.log(this); // undefined
}
// 4. Object method
const obj = {
name: "John",
method: function() {
console.log(this.name); // "John"
}
};
// 5. Constructor function
function Person(name) {
this.name = name;
}
const person = new Person("Alice");
console.log(person.name); // "Alice"
// 6. Event handlers
button.addEventListener('click', function() {
console.log(this); // The button element
});
// 7. Arrow function (lexical this)
const arrowObj = {
name: "Bob",
method: () => {
console.log(this.name); // undefined (inherits from outer scope)
}
};Rules for this binding:
- Default binding: Global object (or undefined in strict mode)
- Implicit binding: Object to the left of the dot
- Explicit binding: Using
call(),apply(), orbind() newbinding: The newly created object- Arrow functions: Lexical this from enclosing scope
6. Difference between Synchronous and Asynchronous JavaScript
Synchronous JavaScript
- Code executes sequentially, line by line
- Each operation must complete before the next one starts
- Blocking operations can freeze the UI
console.log("First"); // Executes first
console.log("Second"); // Waits for first to complete
console.log("Third"); // Waits for second to complete
// Output: First, Second, ThirdAsynchronous JavaScript
- Code can continue executing while waiting for operations to complete
- Non-blocking operations allow the UI to remain responsive
- Uses callbacks, promises, or async/await
console.log("First"); // Executes immediately
setTimeout(() => {
console.log("Second"); // Executes after 1 second
}, 1000);
console.log("Third"); // Executes immediately (doesn't wait for timeout)
// Output: First, Third, SecondJavaScript's Event Loop
JavaScript is single-threaded but handles asynchronicity through:
- Call Stack: Where synchronous code executes
- Web APIs: Browser-provided APIs for async operations
- Callback Queue: Holds callbacks waiting to be executed
- Event Loop: Checks if call stack is empty, then pushes callbacks from queue
Common Async Patterns
// 1. Callbacks (older style)
function fetchData(callback) {
setTimeout(() => {
callback("Data received");
}, 1000);
}
// 2. Promises (ES6)
function fetchDataPromise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data received");
}, 1000);
});
}
// 3. Async/Await (ES2017)
async function getData() {
const data = await fetchDataPromise();
console.log(data);
}Key Concepts:
- Callbacks: Functions passed as arguments to be executed later
- Promises: Objects representing eventual completion/failure of async operations
- Async/Await: Syntactic sugar for promises, makes async code look synchronous
- Microtasks vs Macrotasks: Promise callbacks (microtasks) have higher priority than setTimeout (macrotasks)
Summary
JavaScript's core concepts like variable scoping, hoisting, type systems, function behavior, this context, and asynchronicity are fundamental to writing effective code and are frequently tested in interviews. Understanding these concepts helps you write more predictable, efficient, and maintainable JavaScript applications.