JavaScript Intermediate Content
This content has been divided into two parts for better readability:
- Part 1 (Current): Objects, Arrays, DOM Manipulation, and Events
- Part 2: Asynchronous JavaScript, Fetch API, ES6+ Features, Modules, and Practice Exercises
JavaScript Objects
Objects are collections of key-value pairs and are fundamental to JavaScript. They allow you to store related data and functionality together.
Creating Objects
There are several ways to create objects in JavaScript:
Object Literals
// Object literal syntax
const person = {
firstName: "John",
lastName: "Doe",
age: 30,
email: "[email protected]",
isEmployed: true,
hobbies: ["reading", "swimming", "coding"],
address: {
street: "123 Main St",
city: "New York",
country: "USA"
}
};
Constructor Functions
// Constructor function
function Person(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.getFullName = function() {
return this.firstName + " " + this.lastName;
};
}
const john = new Person("John", "Doe", 30);
console.log(john.getFullName()); // "John Doe"
ES6 Classes
// ES6 Class syntax
class Person {
constructor(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
getFullName() {
return this.firstName + " " + this.lastName;
}
getAge() {
return this.age;
}
}
const jane = new Person("Jane", "Smith", 25);
console.log(jane.getFullName()); // "Jane Smith"
Object.create()
// Object.create() method
const personProto = {
getFullName: function() {
return this.firstName + " " + this.lastName;
}
};
const john = Object.create(personProto);
john.firstName = "John";
john.lastName = "Doe";
john.age = 30;
console.log(john.getFullName()); // "John Doe"
Accessing Object Properties
There are two ways to access object properties:
// Dot notation
console.log(person.firstName); // "John"
console.log(person.address.city); // "New York"
// Bracket notation
console.log(person["lastName"]); // "Doe"
// Bracket notation is useful when property name is dynamic
const propertyName = "age";
console.log(person[propertyName]); // 30
Object Methods
Methods are functions that are stored as object properties.
const person = {
firstName: "John",
lastName: "Doe",
getFullName: function() {
return this.firstName + " " + this.lastName;
},
// Shorthand method syntax (ES6)
greet() {
return `Hello, my name is ${this.firstName}`;
}
};
console.log(person.getFullName()); // "John Doe"
console.log(person.greet()); // "Hello, my name is John"
Object Destructuring
Object destructuring allows you to extract properties from objects and bind them to variables.
const person = {
firstName: "John",
lastName: "Doe",
age: 30,
address: {
street: "123 Main St",
city: "New York",
country: "USA"
}
};
// Basic destructuring
const { firstName, lastName, age } = person;
console.log(firstName); // "John"
console.log(lastName); // "Doe"
console.log(age); // 30
// Nested destructuring
const { address: { city, country } } = person;
console.log(city); // "New York"
console.log(country); // "USA"
// Assigning to new variable names
const { firstName: fName, lastName: lName } = person;
console.log(fName); // "John"
console.log(lName); // "Doe"
// Default values
const { zipCode = "10001" } = person.address;
console.log(zipCode); // "10001" (default value since it doesn't exist)
Object Methods and Properties
JavaScript provides several built-in methods for working with objects:
Method/Property | Description | Example |
---|---|---|
Object.keys() |
Returns an array of a given object's own enumerable property names | Object.keys(person) |
Object.values() |
Returns an array of a given object's own enumerable property values | Object.values(person) |
Object.entries() |
Returns an array of a given object's own enumerable property [key, value] pairs | Object.entries(person) |
Object.assign() |
Copies all enumerable own properties from one or more source objects to a target object | Object.assign({}, person, { age: 31 }) |
Object.freeze() |
Freezes an object, preventing new properties from being added and existing properties from being removed or modified | Object.freeze(person) |
Object.seal() |
Seals an object, preventing new properties from being added and marking all existing properties as non-configurable | Object.seal(person) |
hasOwnProperty() |
Returns a boolean indicating whether the object has the specified property as its own property | person.hasOwnProperty('firstName') |
const person = {
firstName: "John",
lastName: "Doe",
age: 30
};
// Object.keys()
console.log(Object.keys(person)); // ["firstName", "lastName", "age"]
// Object.values()
console.log(Object.values(person)); // ["John", "Doe", 30]
// Object.entries()
console.log(Object.entries(person));
// [["firstName", "John"], ["lastName", "Doe"], ["age", 30]]
// Object.assign()
const updatedPerson = Object.assign({}, person, { age: 31, email: "[email protected]" });
console.log(updatedPerson);
// { firstName: "John", lastName: "Doe", age: 31, email: "[email protected]" }
// Spread operator (alternative to Object.assign)
const updatedPerson2 = { ...person, age: 32, email: "[email protected]" };
console.log(updatedPerson2);
// { firstName: "John", lastName: "Doe", age: 32, email: "[email protected]" }
Prototypes and Inheritance
JavaScript uses a prototype-based inheritance model. Every object has a prototype, which is another object that it inherits properties and methods from.
// Constructor function
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
// Adding a method to the prototype
Person.prototype.getFullName = function() {
return this.firstName + " " + this.lastName;
};
const john = new Person("John", "Doe");
console.log(john.getFullName()); // "John Doe"
// Inheritance with constructor functions
function Employee(firstName, lastName, position) {
// Call the parent constructor
Person.call(this, firstName, lastName);
this.position = position;
}
// Inherit the Person prototype
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
// Add a method to Employee prototype
Employee.prototype.getDetails = function() {
return `${this.getFullName()}, ${this.position}`;
};
const jane = new Employee("Jane", "Smith", "Developer");
console.log(jane.getFullName()); // "Jane Smith"
console.log(jane.getDetails()); // "Jane Smith, Developer"
ES6 Class Inheritance
ES6 classes provide a cleaner syntax for implementing inheritance.
// Parent class
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
getFullName() {
return this.firstName + " " + this.lastName;
}
}
// Child class
class Employee extends Person {
constructor(firstName, lastName, position) {
// Call parent constructor
super(firstName, lastName);
this.position = position;
}
getDetails() {
return `${this.getFullName()}, ${this.position}`;
}
}
const john = new Employee("John", "Doe", "Manager");
console.log(john.getFullName()); // "John Doe"
console.log(john.getDetails()); // "John Doe, Manager"
JavaScript Arrays
Arrays are ordered collections of values. They are used to store multiple values in a single variable.
Creating Arrays
// Array literal syntax
const fruits = ["Apple", "Banana", "Orange", "Mango"];
// Array constructor
const numbers = new Array(1, 2, 3, 4, 5);
// Empty array
const emptyArray = [];
// Array with mixed data types
const mixedArray = [1, "Hello", true, null, { name: "John" }, [1, 2, 3]];
Accessing Array Elements
const fruits = ["Apple", "Banana", "Orange", "Mango"];
// Accessing by index (zero-based)
console.log(fruits[0]); // "Apple"
console.log(fruits[2]); // "Orange"
// Length property
console.log(fruits.length); // 4
// Last element
console.log(fruits[fruits.length - 1]); // "Mango"
Modifying Arrays
const fruits = ["Apple", "Banana", "Orange"];
// Changing an element
fruits[1] = "Pear";
console.log(fruits); // ["Apple", "Pear", "Orange"]
// Adding elements
fruits.push("Mango"); // Add to end
console.log(fruits); // ["Apple", "Pear", "Orange", "Mango"]
fruits.unshift("Strawberry"); // Add to beginning
console.log(fruits); // ["Strawberry", "Apple", "Pear", "Orange", "Mango"]
// Removing elements
fruits.pop(); // Remove from end
console.log(fruits); // ["Strawberry", "Apple", "Pear", "Orange"]
fruits.shift(); // Remove from beginning
console.log(fruits); // ["Apple", "Pear", "Orange"]
// Splice - add/remove elements at any position
// splice(start, deleteCount, item1, item2, ...)
fruits.splice(1, 1, "Kiwi", "Banana");
console.log(fruits); // ["Apple", "Kiwi", "Banana", "Orange"]
Array Methods
JavaScript provides many powerful methods for working with arrays:
Method | Description | Example |
---|---|---|
concat() |
Merges two or more arrays and returns a new array | array1.concat(array2) |
join() |
Joins all elements of an array into a string | array.join(", ") |
slice() |
Returns a shallow copy of a portion of an array | array.slice(1, 3) |
indexOf() |
Returns the first index at which a given element can be found | array.indexOf("Apple") |
lastIndexOf() |
Returns the last index at which a given element can be found | array.lastIndexOf("Apple") |
includes() |
Determines whether an array includes a certain value | array.includes("Apple") |
reverse() |
Reverses the order of the elements in an array | array.reverse() |
sort() |
Sorts the elements of an array | array.sort() |
const fruits = ["Apple", "Banana", "Orange", "Mango"];
const vegetables = ["Carrot", "Broccoli"];
// concat
const food = fruits.concat(vegetables);
console.log(food);
// ["Apple", "Banana", "Orange", "Mango", "Carrot", "Broccoli"]
// join
const fruitString = fruits.join(", ");
console.log(fruitString); // "Apple, Banana, Orange, Mango"
// slice
const citrus = fruits.slice(1, 3);
console.log(citrus); // ["Banana", "Orange"]
// indexOf
console.log(fruits.indexOf("Orange")); // 2
console.log(fruits.indexOf("Pear")); // -1 (not found)
// includes
console.log(fruits.includes("Mango")); // true
console.log(fruits.includes("Pear")); // false
// reverse (modifies the original array)
fruits.reverse();
console.log(fruits); // ["Mango", "Orange", "Banana", "Apple"]
// sort (modifies the original array)
fruits.sort();
console.log(fruits); // ["Apple", "Banana", "Mango", "Orange"]
Higher-Order Array Methods
JavaScript provides several higher-order methods that take functions as arguments, allowing for powerful array transformations:
Method | Description | Example |
---|---|---|
forEach() |
Executes a provided function once for each array element | array.forEach(callback) |
map() |
Creates a new array with the results of calling a function for every array element | array.map(callback) |
filter() |
Creates a new array with all elements that pass the test implemented by the provided function | array.filter(callback) |
reduce() |
Executes a reducer function on each element of the array, resulting in a single output value | array.reduce(callback, initialValue) |
find() |
Returns the first element in the array that satisfies the provided testing function | array.find(callback) |
findIndex() |
Returns the index of the first element in the array that satisfies the provided testing function | array.findIndex(callback) |
some() |
Tests whether at least one element in the array passes the test implemented by the provided function | array.some(callback) |
every() |
Tests whether all elements in the array pass the test implemented by the provided function | array.every(callback) |
const numbers = [1, 2, 3, 4, 5];
const people = [
{ name: "John", age: 25 },
{ name: "Jane", age: 30 },
{ name: "Bob", age: 20 },
{ name: "Alice", age: 35 }
];
// forEach
numbers.forEach(number => {
console.log(number * 2);
}); // Logs: 2, 4, 6, 8, 10
// map
const doubled = numbers.map(number => number * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
const names = people.map(person => person.name);
console.log(names); // ["John", "Jane", "Bob", "Alice"]
// filter
const evenNumbers = numbers.filter(number => number % 2 === 0);
console.log(evenNumbers); // [2, 4]
const adults = people.filter(person => person.age >= 30);
console.log(adults); // [{ name: "Jane", age: 30 }, { name: "Alice", age: 35 }]
// reduce
const sum = numbers.reduce((total, number) => total + number, 0);
console.log(sum); // 15
const totalAge = people.reduce((total, person) => total + person.age, 0);
console.log(totalAge); // 110
// find
const firstEven = numbers.find(number => number % 2 === 0);
console.log(firstEven); // 2
const jane = people.find(person => person.name === "Jane");
console.log(jane); // { name: "Jane", age: 30 }
// some
const hasEven = numbers.some(number => number % 2 === 0);
console.log(hasEven); // true
// every
const allPositive = numbers.every(number => number > 0);
console.log(allPositive); // true
// Chaining methods
const result = numbers
.filter(number => number % 2 === 0)
.map(number => number * 3)
.reduce((total, number) => total + number, 0);
console.log(result); // 18 (2*3 + 4*3)
Array Destructuring
Array destructuring allows you to extract values from arrays and assign them to variables.
const numbers = [1, 2, 3, 4, 5];
// Basic destructuring
const [first, second, third] = numbers;
console.log(first); // 1
console.log(second); // 2
console.log(third); // 3
// Skip elements
const [a, , c] = numbers;
console.log(a); // 1
console.log(c); // 3
// Rest pattern
const [head, ...tail] = numbers;
console.log(head); // 1
console.log(tail); // [2, 3, 4, 5]
// Default values
const [x, y, z = 10] = [1, 2];
console.log(x); // 1
console.log(y); // 2
console.log(z); // 10 (default value)
// Swapping variables
let m = 1;
let n = 2;
[m, n] = [n, m];
console.log(m); // 2
console.log(n); // 1
Spread Operator with Arrays
The spread operator (...
) allows an array to be expanded in places where zero or more arguments or elements are expected.
const numbers1 = [1, 2, 3];
const numbers2 = [4, 5, 6];
// Combine arrays
const combined = [...numbers1, ...numbers2];
console.log(combined); // [1, 2, 3, 4, 5, 6]
// Copy an array
const copy = [...numbers1];
console.log(copy); // [1, 2, 3]
// Insert elements in the middle
const inserted = [...numbers1.slice(0, 2), 10, ...numbers1.slice(2)];
console.log(inserted); // [1, 2, 10, 3]
// Use with functions
function sum(a, b, c) {
return a + b + c;
}
console.log(sum(...numbers1)); // 6 (1 + 2 + 3)
DOM Manipulation
The Document Object Model (DOM) is a programming interface for HTML and XML documents. It represents the page so that programs can change the document structure, style, and content.
Selecting DOM Elements
JavaScript provides several methods to select elements from the DOM:
Method | Description | Example |
---|---|---|
getElementById() |
Returns the element with the specified ID | document.getElementById("myId") |
getElementsByClassName() |
Returns a live HTMLCollection of elements with the specified class name | document.getElementsByClassName("myClass") |
getElementsByTagName() |
Returns a live HTMLCollection of elements with the specified tag name | document.getElementsByTagName("div") |
querySelector() |
Returns the first element that matches a specified CSS selector | document.querySelector("#myId") |
querySelectorAll() |
Returns a static NodeList of all elements that match a specified CSS selector | document.querySelectorAll(".myClass") |
// Select by ID
const header = document.getElementById("header");
// Select by class name
const items = document.getElementsByClassName("item");
// Select by tag name
const paragraphs = document.getElementsByTagName("p");
// Select using CSS selectors
const firstButton = document.querySelector("button");
const allButtons = document.querySelectorAll("button");
// Combining selectors
const activeItems = document.querySelectorAll(".item.active");
const navLinks = document.querySelectorAll("nav a");
// Selecting children
const firstChild = document.querySelector("ul > li:first-child");
const lastChild = document.querySelector("ul > li:last-child");
Modifying DOM Elements
Once you've selected elements, you can modify their content, attributes, and styles:
Changing Content
const element = document.getElementById("myElement");
// Change text content
element.textContent = "New text content";
// Change HTML content
element.innerHTML = "Bold text and italic text";
// Create text node
const textNode = document.createTextNode("Text node content");
element.appendChild(textNode);
Modifying Attributes
const link = document.getElementById("myLink");
// Get attribute
const href = link.getAttribute("href");
console.log(href);
// Set attribute
link.setAttribute("href", "https://example.com");
link.setAttribute("target", "_blank");
// Check if attribute exists
const hasTarget = link.hasAttribute("target");
console.log(hasTarget); // true
// Remove attribute
link.removeAttribute("target");
// Using properties (for standard attributes)
link.href = "https://example.org";
link.id = "newId";
link.className = "link active";
Modifying Styles
const element = document.getElementById("myElement");
// Using the style property
element.style.color = "red";
element.style.backgroundColor = "#f0f0f0";
element.style.padding = "10px";
element.style.borderRadius = "5px";
// Using CSS classes
element.className = "active highlight";
// Using classList (modern approach)
element.classList.add("active");
element.classList.remove("highlight");
element.classList.toggle("selected");
element.classList.replace("old-class", "new-class");
const hasClass = element.classList.contains("active");
console.log(hasClass); // true
Creating and Removing Elements
JavaScript allows you to dynamically create, insert, and remove elements from the DOM:
Creating Elements
// Create a new element
const newDiv = document.createElement("div");
// Add content
newDiv.textContent = "This is a new div";
// Add attributes
newDiv.id = "newDiv";
newDiv.className = "container";
// Add styles
newDiv.style.color = "blue";
newDiv.style.backgroundColor = "#f0f0f0";
// Create a complex element
const newList = document.createElement("ul");
for (let i = 1; i <= 3; i++) {
const listItem = document.createElement("li");
listItem.textContent = `Item ${i}`;
newList.appendChild(listItem);
}
Adding Elements to the DOM
const parentElement = document.getElementById("parent");
const referenceElement = document.getElementById("reference");
// Append at the end of parent
parentElement.appendChild(newDiv);
// Insert before a reference element
parentElement.insertBefore(newList, referenceElement);
// Modern insertion methods
parentElement.append(newDiv); // Can append multiple nodes and text
parentElement.prepend(newDiv); // Insert at the beginning
referenceElement.before(newDiv); // Insert before reference
referenceElement.after(newDiv); // Insert after reference
referenceElement.replaceWith(newDiv); // Replace reference with new element
Removing Elements
const elementToRemove = document.getElementById("removeMe");
// Remove element (old way)
elementToRemove.parentNode.removeChild(elementToRemove);
// Modern way
elementToRemove.remove();
// Remove all children
const parent = document.getElementById("parent");
while (parent.firstChild) {
parent.removeChild(parent.firstChild);
}
// Alternative way to remove all children
parent.innerHTML = "";
Traversing the DOM
You can navigate through the DOM tree using various properties:
const element = document.getElementById("myElement");
// Parent
const parent = element.parentNode; // or element.parentElement
// Children
const children = element.children; // HTMLCollection of child elements
const firstChild = element.firstElementChild;
const lastChild = element.lastElementChild;
const childCount = element.childElementCount;
// Siblings
const nextSibling = element.nextElementSibling;
const previousSibling = element.previousElementSibling;
// All nodes (including text nodes)
const childNodes = element.childNodes;
const firstNode = element.firstChild;
const lastNode = element.lastChild;
const nextNode = element.nextSibling;
const previousNode = element.previousSibling;
JavaScript Events
Events are actions or occurrences that happen in the browser, which can be detected and responded to with JavaScript. Examples include clicks, key presses, form submissions, and page loads.
Event Handlers
There are several ways to attach event handlers to elements:
HTML Attribute (Inline)
<button onclick="alert('Button clicked!')">Click Me</button>
DOM Property
const button = document.getElementById("myButton");
button.onclick = function() {
alert("Button clicked!");
};
// Using arrow function
button.onclick = () => {
alert("Button clicked!");
};
addEventListener Method (Recommended)
const button = document.getElementById("myButton");
// Add event listener
button.addEventListener("click", function() {
alert("Button clicked!");
});
// Using arrow function
button.addEventListener("click", () => {
alert("Button clicked!");
});
// Using named function
function handleClick() {
alert("Button clicked!");
}
button.addEventListener("click", handleClick);
// Remove event listener
button.removeEventListener("click", handleClick);
Common Events
JavaScript supports many types of events:
Category | Events |
---|---|
Mouse Events | click , dblclick , mousedown , mouseup , mouseover , mouseout , mousemove |
Keyboard Events | keydown , keyup , keypress |
Form Events | submit , reset , change , input , focus , blur |
Window Events | load , resize , scroll , unload , beforeunload |
Document Events | DOMContentLoaded |
Drag Events | dragstart , drag , dragend , dragenter , dragover , dragleave , drop |
The Event Object
When an event occurs, the browser creates an event object that contains information about the event. This object is automatically passed to the event handler function.
const button = document.getElementById("myButton");
button.addEventListener("click", function(event) {
// The event object
console.log(event);
// Common properties
console.log(event.type); // "click"
console.log(event.target); // The element that triggered the event
console.log(event.currentTarget); // The element that the event listener is attached to
console.log(event.timeStamp); // Time when the event occurred
// Mouse event properties
console.log(event.clientX, event.clientY); // Mouse coordinates relative to the viewport
console.log(event.pageX, event.pageY); // Mouse coordinates relative to the document
console.log(event.button); // Which mouse button was pressed
// Keyboard event properties
// console.log(event.key); // The key value
// console.log(event.code); // The physical key code
// console.log(event.altKey, event.ctrlKey, event.shiftKey); // Modifier keys
// Prevent default behavior
event.preventDefault();
// Stop propagation
event.stopPropagation();
});
Event Propagation
When an event occurs on an element, it first runs the handlers on it, then on its parent, then all the way up on other ancestors. This is called event bubbling.
<div id="outer">
<div id="inner">
<button id="button">Click Me</button>
</div>
</div>
<script>
document.getElementById("outer").addEventListener("click", function() {
console.log("Outer div clicked");
});
document.getElementById("inner").addEventListener("click", function() {
console.log("Inner div clicked");
});
document.getElementById("button").addEventListener("click", function() {
console.log("Button clicked");
});
// When the button is clicked, the output will be:
// "Button clicked"
// "Inner div clicked"
// "Outer div clicked"
</script>
Stopping Propagation
document.getElementById("button").addEventListener("click", function(event) {
console.log("Button clicked");
event.stopPropagation(); // Prevents the event from bubbling up
});
Event Delegation
Event delegation is a technique where you attach a single event listener to a parent element instead of multiple listeners on child elements. It takes advantage of event bubbling.
<ul id="menu">
<li data-action="save">Save</li>
<li data-action="load">Load</li>
<li data-action="delete">Delete</li>
</ul>
<script>
// Instead of adding event listeners to each li
document.getElementById("menu").addEventListener("click", function(event) {
// Check if the clicked element is an li
if (event.target.tagName === "LI") {
const action = event.target.getAttribute("data-action");
console.log("Action:", action);
// Perform action based on the data attribute
switch (action) {
case "save":
saveData();
break;
case "load":
loadData();
break;
case "delete":
deleteData();
break;
}
}
});
function saveData() { console.log("Saving data..."); }
function loadData() { console.log("Loading data..."); }
function deleteData() { console.log("Deleting data..."); }
</script>
Custom Events
You can create and dispatch your own custom events using the CustomEvent constructor.
// Create a custom event
const customEvent = new CustomEvent("userLogin", {
detail: {
username: "john_doe",
timestamp: new Date()
},
bubbles: true,
cancelable: true
});
// Listen for the custom event
document.addEventListener("userLogin", function(event) {
console.log("User logged in:", event.detail.username);
console.log("Time:", event.detail.timestamp);
});
// Dispatch the event
document.dispatchEvent(customEvent);