JavaScript is the backbone of modern web development. Whether you're just starting or looking to solidify your foundation, understanding these core concepts is essential for every developer.
Table of Contents
1. Variables and Data Types
JavaScript has three ways to declare variables: var,
let, and const.
// Variable declarations
var oldVariable = "I'm function scoped";
let mutableVariable = "I can be reassigned";
const constantVariable = "I cannot be reassigned";
// Data Types
const primitiveTypes = {
string: "Hello World",
number: 42,
boolean: true,
null: null,
undefined: undefined,
symbol: Symbol('unique'),
bigint: 9007199254740991n
};
// Complex Types
const complexTypes = {
object: { key: "value" },
array: [1, 2, 3],
function: function() { return "I'm a function"; }
};
Key Points:
-
letandconstare block-scoped (ES6+) -
constdoesn't make objects immutable, just prevents reassignment - JavaScript has dynamic typing (variables can change type)
2. Hoisting and Temporal Dead Zone
JavaScript moves variable and function declarations to the top of their scope during compilation.
// Function declaration is hoisted
sayHello(); // Works
function sayHello() {
console.log("Hello!");
}
// Variable declaration is hoisted but not initialization
console.log(myVar); // undefined (not ReferenceError)
var myVar = 5;
// let/const are hoisted but in Temporal Dead Zone (TDZ)
console.log(myLet); // ReferenceError
let myLet = 10;
Common Pitfall:
Always declare variables before use. let and
const exist in TDZ until declaration.
3. Scope and Closures
JavaScript has function scope (ES5) and block scope (ES6+). Closures allow functions to remember their lexical scope.
// Global scope
const globalVar = "I'm global";
function outerFunction() {
// Outer function scope
const outerVar = "I'm outer";
return function innerFunction() {
// Inner function scope
const innerVar = "I'm inner";
console.log(globalVar); // Can access global
console.log(outerVar); // Can access outer (closure)
};
}
const myClosure = outerFunction();
myClosure(); // Still remembers outerVar
Practical Use:
Closures are used for data privacy, currying functions, and in React hooks.
4. Functions and Arrow Functions
Functions are first-class citizens in JavaScript. Arrow functions
(ES6+) have concise syntax and lexical this.
// Function declarations
function traditionalFunction(a, b) {
return a + b;
}
// Function expression
const anonymousFunction = function(a, b) {
return a + b;
};
// Arrow function
const arrowFunction = (a, b) => a + b;
// 'this' behavior
const obj = {
name: "My Object",
traditionalMethod: function() {
console.log(this.name); // 'My Object'
},
arrowMethod: () => {
console.log(this.name); // undefined (lexical this)
}
};
5. Objects and Prototypes
JavaScript uses prototypal inheritance. Objects can inherit properties from other objects.
// Object literal
const person = {
name: "Alice",
greet() {
console.log(`Hello, I'm ${this.name}`);
}
};
// Constructor function
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, I'm ${this.name}`);
};
const alice = new Person("Alice");
// Class syntax (ES6)
class ModernPerson {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, I'm ${this.name}`);
}
}
const bob = new ModernPerson("Bob");
Prototype Chain:
When accessing a property, JavaScript looks up the prototype
chain until it finds the property or reaches null.
6. Asynchronous JavaScript
JavaScript is single-threaded but handles async operations with callbacks, promises, and async/await.
// Callback (old way)
function fetchData(callback) {
setTimeout(() => {
callback("Data received");
}, 1000);
}
// Promise
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data received");
}, 1000);
});
}
// Async/Await (modern)
async function getData() {
try {
const data = await fetchData();
console.log(data);
} catch (error) {
console.error(error);
}
}
// Event loop example
console.log("Start");
setTimeout(() => console.log("Timeout"), 0);
Promise.resolve().then(() => console.log("Promise"));
console.log("End");
// Output order:
// Start
// End
// Promise
// Timeout
7. ES6+ Features
Modern JavaScript introduced many powerful features that are now essential.
// Destructuring
const { name, age } = { name: "Alice", age: 30 };
// Spread/Rest
const numbers = [1, 2, 3];
const newNumbers = [...numbers, 4, 5];
function sum(...nums) {
return nums.reduce((total, num) => total + num, 0);
}
// Template literals
const greeting = `Hello ${name}, you are ${age} years old!`;
// Default parameters
function greet(name = "Guest") {
return `Hello ${name}!`;
}
// Modules (see next section)
import { myFunction } from './myModule.js';
8. Modules and Import/Export
JavaScript modules help organize code into reusable pieces.
// mathUtils.js - Exporting
export const PI = 3.14159;
export function sum(a, b) {
return a + b;
}
// Default export
export default function multiply(a, b) {
return a * b;
}
// app.js - Importing
import { PI, sum } from './mathUtils.js';
import multiply from './mathUtils.js'; // default import
// Dynamic imports
const loadModule = async () => {
const module = await import('./mathUtils.js');
console.log(module.sum(2, 3));
};
Best Practice:
Use named exports for multiple utilities and default exports for single-purpose modules.