1. Variables: var, let, and const
Variables allow us to store data.
JavaScript provides three ways to declare variables:
varletconst
var
var is the older way of declaring variables.
var framework = "React"; console.log(framework); // React However, var has some important problems.
For example, it is function-scoped rather than block-scoped.
if (true) { var framework = "React"; } console.log(framework); // React The variable escapes the if block.
This behavior can create unexpected bugs.
let
let allows you to declare variables that can be reassigned.
let age = 25; age = 26; console.log(age); // 26 Unlike var, let is block-scoped.
if (true) { let framework = "React"; } console.log(framework); // ReferenceError const
const declares a variable that cannot be reassigned.
const framework = "React"; framework = "Vue"; // TypeError However, const does not make objects immutable.
const user = { name: "Alice", }; user.name = "Bob"; console.log(user.name); // Bob The object can be modified because the reference remains the same.
But you cannot reassign the variable:
const user = { name: "Alice", }; user = { name: "Bob" }; // TypeError Which one should you use?
In modern JavaScript:
- Use
constby default. - Use
letwhen reassignment is necessary. - Avoid
varin modern code.
You'll see const everywhere in React.
2. Data Types
JavaScript has several primitive data types.
const name = "Alice"; // String const age = 25; // Number const isDeveloper = true; // Boolean const score = null; // Null let result; // Undefined const id = Symbol("id"); // Symbol const bigNumber = 123n; // BigInt JavaScript also has objects.
const user = { name: "Alice", age: 25, }; Arrays are also objects in JavaScript.
const numbers = [1, 2, 3]; console.log(typeof numbers); // "object" Understanding undefined vs. null
undefined usually means a value hasn't been assigned.
let username; console.log(username); // undefined null represents an intentionally empty value.
const selectedUser = null; One unusual JavaScript behavior:
console.log(typeof null); // "object" This is a historical JavaScript quirk.
3. Operators and Comparisons
JavaScript supports arithmetic operators:
const a = 10; const b = 3; console.log(a + b); // 13 console.log(a - b); // 7 console.log(a * b); // 30 console.log(a / b); // 3.333... console.log(a % b); // 1 Equality operators
Always understand the difference between == and ===.
console.log(5 == "5"); // true console.log(5 === "5"); // false == performs type coercion.
=== compares values without performing that coercion.
Prefer === and !== in modern JavaScript.
Logical operators
const isLoggedIn = true; const isAdmin = false; console.log(isLoggedIn && isAdmin); // false console.log(isLoggedIn || isAdmin); // true console.log(!isLoggedIn); // false These operators are particularly useful in React.
4. Truthy and Falsy Values
JavaScript doesn't always require a Boolean value in conditions.
Some values behave like true, while others behave like false.
Falsy values
The main falsy values are:
false 0 -0 0n "" null undefined NaN Everything else is generally truthy, including empty arrays and empty objects.
console.log(Boolean([])); // true console.log(Boolean({})); // true Example
const username = ""; if (username) { console.log("Username exists"); } else { console.log("Username is empty"); } This concept becomes extremely important when using conditional rendering in React.
5. Scope: Where Variables Exist
Scope determines where a variable can be accessed.
JavaScript has several important types of scope.
Global scope
const framework = "React"; function showFramework() { console.log(framework); } showFramework(); // React The function can access the global variable.
Function scope
function example() { const message = "Hello"; console.log(message); } example(); // Hello console.log(message); // ReferenceError The variable exists only inside the function.
Block scope
if (true) { const message = "Hello"; let framework = "React"; } console.log(message); // ReferenceError Variables declared with let and const are block-scoped.
6. Hoisting
Hoisting describes JavaScript's behavior of processing declarations before executing code.
It does not mean JavaScript physically moves your code.
var hoisting
console.log(framework); var framework = "React"; // undefined The declaration is available, but the assignment hasn't happened yet.
Conceptually, this behaves similarly to:
var framework; console.log(framework); framework = "React"; let and const
console.log(framework); let framework = "React"; // ReferenceError Variables declared with let and const are also processed before execution, but they cannot be accessed before their declaration is initialized.
This period is called the Temporal Dead Zone (TDZ).
Function declarations
Function declarations can be called before their definition.
sayHello(); function sayHello() { console.log("Hello!"); } This works because function declarations are hoisted with their function definition.
7. Functions
Functions are reusable blocks of code.
Function declaration
function add(a, b) { return a + b; } console.log(add(5, 3)); // 8 Function expression
const add = function (a, b) { return a + b; }; console.log(add(5, 3)); // 8 Arrow functions
Arrow functions are widely used in modern JavaScript and React.
const add = (a, b) => { return a + b; }; For a single expression, you can simplify the syntax:
const add = (a, b) => a + b; Single parameter
const square = number => number * number; console.log(square(4)); // 16 Returning an object
Remember to wrap the object in parentheses:
const createUser = (name) => ({ name: name, active: true, }); console.log(createUser("Alice")); Arrow functions and this
Arrow functions do not create their own this.
They inherit this from the surrounding lexical scope.
This is especially important when working with callbacks and React event handlers.
8. Callback Functions
A callback is a function passed into another function.
function greet(name, callback) { console.log(`Hello, ${name}`); callback(); } function sayGoodbye() { console.log("Goodbye!"); } greet("Alice", sayGoodbye); Output:
Hello, Alice Goodbye! Callbacks are everywhere in JavaScript.
For example:
const numbers = [1, 2, 3]; numbers.map((number) => number * 2); The arrow function is a callback passed to map().
React uses callbacks for event handlers:
<button onClick={() => console.log("Clicked!")}> Click me </button> 9. Closures
A closure happens when a function remembers variables from its surrounding scope, even after that outer function has finished executing.
function createCounter() { let count = 0; return function () { count++; return count; }; } const counter = createCounter(); console.log(counter()); // 1 console.log(counter()); // 2 console.log(counter()); // 3 Why does this work?
The returned function still has access to the count variable from createCounter().
This is a closure.
Closures are fundamental to understanding many JavaScript patterns, including how React hooks preserve state between renders.
10. Arrays
Arrays store multiple values in a single variable.
const frameworks = ["React", "Vue", "Angular"]; console.log(frameworks[0]); // React Important array methods
map()
Transforms every element.
const numbers = [1, 2, 3]; const doubled = numbers.map((number) => number * 2); console.log(doubled); // [2, 4, 6] filter()
Returns elements that satisfy a condition.
const numbers = [1, 2, 3, 4]; const evenNumbers = numbers.filter((number) => number % 2 === 0); console.log(evenNumbers); // [2, 4] find()
Returns the first matching element.
const users = [ { id: 1, name: "Alice" }, { id: 2, name: "Bob" }, ]; const user = users.find((user) => user.id === 2); console.log(user); // { id: 2, name: "Bob" } reduce()
Accumulates values.
const numbers = [1, 2, 3, 4]; const total = numbers.reduce((sum, number) => sum + number, 0); console.log(total); // 10 some() and every()
const numbers = [2, 4, 6]; console.log(numbers.some((number) => number > 5)); // true console.log(numbers.every((number) => number % 2 === 0)); // true These methods are used constantly when working with API data and rendering lists in React.
11. Objects
Objects store data using key-value pairs.
const user = { name: "Alice", age: 25, role: "Frontend Developer", }; Access properties
console.log(user.name); // Alice console.log(user["age"]); // 25 Add properties
user.country = "Germany"; Update properties
user.age = 26; Delete properties
delete user.role; Objects are essential for understanding React props, state, and API responses.
12. Destructuring
Destructuring allows you to extract values from arrays and objects.
Object destructuring
const user = { name: "Alice", age: 25, role: "Developer", }; const { name, age } = user; console.log(name); // Alice console.log(age); // 25 Rename properties
const { name: username } = user; console.log(username); // Alice Default values
const { country = "Unknown" } = user; console.log(country); // Unknown Array destructuring
const colors = ["red", "green", "blue"]; const [first, second] = colors; console.log(first); // red console.log(second); // green Destructuring in React
You'll frequently see this:
function UserProfile({ name, age }) { return ( <div> <h2>{name}</h2> <p>{age}</p> </div> ); } This is object destructuring applied to function parameters.
13. Spread Operator (...)
The spread operator expands values from arrays or objects.
Copy an array
const numbers = [1, 2, 3]; const copiedNumbers = [...numbers]; console.log(copiedNumbers); // [1, 2, 3] Combine arrays
const first = [1, 2]; const second = [3, 4]; const combined = [...first, ...second]; console.log(combined); // [1, 2, 3, 4] Copy and update an object
const user = { name: "Alice", age: 25, }; const updatedUser = { ...user, age: 26, }; console.log(updatedUser); // { name: "Alice", age: 26 } Why is this important in React?
React state should generally be updated immutably.
Instead of modifying an existing object:
user.age = 26; You create a new object:
const updatedUser = { ...user, age: 26, }; This pattern is fundamental to React state updates.
14. Rest Parameters
The rest operator collects multiple arguments into an array.
function sum(...numbers)<...