Skip to main content

JavaScript Fundamentals

JavaScript is the programming language of the web and forms the foundation for modern frameworks like Next.js. Before diving into more advanced concepts, it's essential to understand the fundamentals of JavaScript. This guide will walk you through the core concepts you need to know.

Introduction to JavaScript

JavaScript is a high-level, interpreted programming language that enables interactive web pages. Originally designed for client-side scripting, it now runs everywhere from browsers to servers (via Node.js) and forms the backbone of modern web applications like those built with Next.js.

In Next.js development, solid JavaScript knowledge is crucial as you'll be using it to:

  • Handle user interactions
  • Manage application state
  • Process data
  • Create dynamic interfaces
  • Implement client-side and server-side logic

Variables and Data Types

Variable Declaration

JavaScript offers three ways to declare variables:

javascript
// Using var (older method, function-scoped)
var name = "John";

// Using let (block-scoped, can be reassigned)
let age = 25;

// Using const (block-scoped, cannot be reassigned)
const isStudent = true;

For modern JavaScript development, it's recommended to use let and const instead of var.

Primitive Data Types

JavaScript has six primitive data types:

javascript
// String
let name = "John Doe";

// Number
let age = 25;
let price = 19.99;

// Boolean
let isOnline = true;

// Null
let emptyValue = null;

// Undefined
let notDefined;

// Symbol (ES6)
let uniqueId = Symbol("id");

Complex Data Types

JavaScript also has complex data types:

javascript
// Object
const person = {
name: "John",
age: 30,
isStudent: false
};

console.log(person.name); // Output: John
console.log(person["age"]); // Output: 30

// Array
const fruits = ["Apple", "Banana", "Orange"];
console.log(fruits[0]); // Output: Apple
console.log(fruits.length); // Output: 3

// Function
function greet(name) {
return `Hello, ${name}!`;
}

console.log(greet("Sarah")); // Output: Hello, Sarah!

Control Flow

Conditional Statements

javascript
const age = 18;

// If, else if, else
if (age > 18) {
console.log("You are an adult");
} else if (age === 18) {
console.log("You just became an adult");
} else {
console.log("You are a minor");
}

// Output: You just became an adult

// Ternary operator
const status = age >= 18 ? "Adult" : "Minor";
console.log(status); // Output: Adult

// Switch statement
const fruit = "Apple";
switch (fruit) {
case "Orange":
console.log("Orange is $0.59 per pound");
break;
case "Apple":
console.log("Apple is $0.32 per pound");
break;
default:
console.log("Sorry, we are out of " + fruit);
}
// Output: Apple is $0.32 per pound

Loops

JavaScript offers several types of loops:

javascript
// For loop
for (let i = 0; i < 5; i++) {
console.log(i);
}
// Output: 0 1 2 3 4

// While loop
let count = 0;
while (count < 3) {
console.log(`Count: ${count}`);
count++;
}
// Output: Count: 0 Count: 1 Count: 2

// Do-while loop
let num = 0;
do {
console.log(`Number: ${num}`);
num++;
} while (num < 2);
// Output: Number: 0 Number: 1

// For...of loop (for iterables like arrays)
const colors = ["red", "green", "blue"];
for (const color of colors) {
console.log(color);
}
// Output: red green blue

// For...in loop (for object properties)
const person = { name: "John", age: 30, job: "Developer" };
for (const key in person) {
console.log(`${key}: ${person[key]}`);
}
// Output: name: John age: 30 job: Developer

Functions

Functions are one of the fundamental building blocks in JavaScript.

Function Declaration

javascript
function add(a, b) {
return a + b;
}

console.log(add(5, 3)); // Output: 8

Function Expression

javascript
const multiply = function(a, b) {
return a * b;
};

console.log(multiply(4, 2)); // Output: 8

Arrow Functions (ES6)

javascript
const divide = (a, b) => a / b;

console.log(divide(10, 2)); // Output: 5

// Multiline arrow function
const calculateArea = (width, height) => {
const area = width * height;
return area;
};

console.log(calculateArea(5, 3)); // Output: 15

Default Parameters

javascript
function greet(name = "Guest") {
return `Hello, ${name}!`;
}

console.log(greet()); // Output: Hello, Guest!
console.log(greet("John")); // Output: Hello, John!

Objects and Arrays

Working with Objects

Objects are collections of key-value pairs.

javascript
// Creating an object
const user = {
firstName: "John",
lastName: "Doe",
age: 30,
email: "[email protected]",

// Method inside object
getFullName: function() {
return `${this.firstName} ${this.lastName}`;
}
};

// Accessing properties
console.log(user.firstName); // Output: John
console.log(user["lastName"]); // Output: Doe

// Calling a method
console.log(user.getFullName()); // Output: John Doe

// Adding new properties
user.location = "New York";
console.log(user.location); // Output: New York

// Object destructuring
const { firstName, age } = user;
console.log(firstName, age); // Output: John 30

Working with Arrays

Arrays are ordered collections of items.

javascript
// Creating an array
const fruits = ["Apple", "Banana", "Orange"];

// Accessing elements
console.log(fruits[0]); // Output: Apple

// Adding elements
fruits.push("Mango");
console.log(fruits); // Output: ["Apple", "Banana", "Orange", "Mango"]

// Removing the last element
const lastFruit = fruits.pop();
console.log(lastFruit); // Output: Mango
console.log(fruits); // Output: ["Apple", "Banana", "Orange"]

// Array methods
const numbers = [1, 2, 3, 4, 5];

// map - creates a new array by applying a function to each element
const doubled = numbers.map(num => num * 2);
console.log(doubled); // Output: [2, 4, 6, 8, 10]

// filter - creates a new array with elements that pass the test
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // Output: [2, 4]

// reduce - reduces the array to a single value
const sum = numbers.reduce((total, num) => total + num, 0);
console.log(sum); // Output: 15

// Array destructuring
const [first, second, ...rest] = numbers;
console.log(first, second, rest); // Output: 1 2 [3, 4, 5]

Template Literals and String Methods

Template literals provide an easy way to create strings with embedded expressions.

javascript
const name = "John";
const age = 30;

// Using template literals
const greeting = `Hello, my name is ${name} and I am ${age} years old.`;
console.log(greeting);
// Output: Hello, my name is John and I am 30 years old.

// Multiline strings
const multiLine = `This is line 1.
This is line 2.
This is line 3.`;
console.log(multiLine);
/*
Output:
This is line 1.
This is line 2.
This is line 3.
*/

// Common string methods
const text = "JavaScript is amazing";
console.log(text.length); // Output: 21
console.log(text.toUpperCase()); // Output: JAVASCRIPT IS AMAZING
console.log(text.toLowerCase()); // Output: javascript is amazing
console.log(text.includes("Script")); // Output: true
console.log(text.split(" ")); // Output: ["JavaScript", "is", "amazing"]
console.log(text.substring(0, 10)); // Output: JavaScript

Modern JavaScript Features (ES6+)

Spread and Rest Operators

javascript
// Spread operator with arrays
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2];
console.log(combined); // Output: [1, 2, 3, 4, 5, 6]

// Spread operator with objects
const userBasic = { name: "John", age: 30 };
const userDetailed = {
...userBasic,
email: "[email protected]",
location: "New York"
};
console.log(userDetailed);
// Output: { name: "John", age: 30, email: "[email protected]", location: "New York" }

// Rest parameter
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // Output: 15

Destructuring

javascript
// Object destructuring
const person = {
name: "John",
age: 30,
location: "New York",
social: {
twitter: "@john",
facebook: "john.doe"
}
};

// Basic destructuring
const { name, age } = person;
console.log(name, age); // Output: John 30

// Destructuring with new variable names
const { name: fullName, age: years } = person;
console.log(fullName, years); // Output: John 30

// Nested destructuring
const { social: { twitter, facebook } } = person;
console.log(twitter, facebook); // Output: @john john.doe

// Array destructuring
const colors = ["red", "green", "blue"];
const [primary, secondary, tertiary] = colors;
console.log(primary, tertiary); // Output: red blue

// Skipping elements
const numbers = [1, 2, 3, 4, 5];
const [first, , third, ...rest] = numbers;
console.log(first, third, rest); // Output: 1 3 [4, 5]

Promises and Async/Await

Promises are used for handling asynchronous operations.

javascript
// Creating a promise
const fetchData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve({ id: 1, name: "Data" });
} else {
reject("Failed to fetch data");
}
}, 1000);
});
};

// Using promises with then/catch
fetchData()
.then(data => console.log("Success:", data))
.catch(error => console.error("Error:", error));
// After 1 second, Output: Success: {id: 1, name: "Data"}

// Using async/await (more modern approach)
async function getData() {
try {
const data = await fetchData();
console.log("With async/await:", data);
} catch (error) {
console.error("Error with async/await:", error);
}
}

getData();
// After 1 second, Output: With async/await: {id: 1, name: "Data"}

Practical Examples for Next.js

Let's look at some JavaScript patterns commonly used in Next.js applications:

1. Component State Management

javascript
// In a React/Next.js component
import { useState } from 'react';

function Counter() {
// Using the state hook
const [count, setCount] = useState(0);

// Event handlers
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);

return (
<div>
<h2>Count: {count}</h2>
<button onClick={decrement}>-</button>
<button onClick={increment}>+</button>
</div>
);
}

export default Counter;

2. Data Fetching

javascript
// In a Next.js page or component
import { useState, useEffect } from 'react';

function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
async function fetchUsers() {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users');

if (!response.ok) {
throw new Error('Failed to fetch');
}

const data = await response.json();
setUsers(data);
setLoading(false);
} catch (err) {
setError(err.message);
setLoading(false);
}
}

fetchUsers();
}, []);

if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;

return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}

export default UserList;

3. Form Handling

javascript
import { useState } from 'react';

function ContactForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
message: ''
});
const [submitted, setSubmitted] = useState(false);

const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prevData => ({
...prevData,
[name]: value
}));
};

const handleSubmit = async (e) => {
e.preventDefault();

try {
// In a real app, you'd send this data to your API
console.log('Submitting:', formData);

// Simulate API call
await new Promise(resolve => setTimeout(resolve, 1000));

setSubmitted(true);
setFormData({ name: '', email: '', message: '' });
} catch (error) {
console.error('Error submitting form:', error);
}
};

if (submitted) {
return <div>Thank you for your message!</div>;
}

return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="name">Name:</label>
<input
type="text"
id="name"
name="name"
value={formData.name}
onChange={handleChange}
required
/>
</div>

<div>
<label htmlFor="email">Email:</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleChange}
required
/>
</div>

<div>
<label htmlFor="message">Message:</label>
<textarea
id="message"
name="message"
value={formData.message}
onChange={handleChange}
required
/>
</div>

<button type="submit">Submit</button>
</form>
);
}

export default ContactForm;

Summary

In this guide, we've covered the essential JavaScript fundamentals needed for Next.js development:

  • Variables and data types
  • Control flow structures
  • Functions and their different forms
  • Working with objects and arrays
  • Template literals and string manipulation
  • Modern JavaScript features (ES6+)
  • Promises and async/await for asynchronous operations
  • Practical examples in the context of Next.js

Understanding these fundamentals provides a solid foundation for developing with Next.js. As you work with Next.js, you'll combine these JavaScript concepts with React principles to build powerful web applications.

Additional Resources

To continue learning JavaScript for Next.js development:

  1. MDN JavaScript Guide - Comprehensive JavaScript documentation
  2. JavaScript.info - Modern JavaScript tutorial
  3. Eloquent JavaScript - Free book about JavaScript programming

Exercises

Try these exercises to reinforce your JavaScript skills:

  1. Create a function that takes an array of objects (each with name and age properties) and returns an array of names for people over 18.
  2. Build a simple todo list using objects and arrays. Include functionality to add, remove, and mark todos as completed.
  3. Create a function that fetches data from an API and handles potential errors using try/catch and async/await.
  4. Practice object and array destructuring by extracting specific data from a complex nested object.
  5. Write a utility function that takes a string and returns it with the first letter of each word capitalized.

By mastering these JavaScript fundamentals, you'll be well-prepared to tackle more advanced Next.js concepts and build sophisticated applications with confidence.



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)