JavaScript Basics

JavaScript is a client-side scripting language mainly used for web development. Unlike server-side languages like PHP, JavaScript is executed directly in the user's browser and enables interactive and dynamic web pages.

Note

This learning material is based on course content and completed practice examples. It covers the basic concepts of JavaScript.

Main Features of JavaScript

  • Client-side language (runs in the browser)
  • Dynamically typed (variables don't require explicit type declaration)
  • Object-oriented and event-driven
  • Enables DOM manipulation (Document Object Model)
  • Can be embedded in HTML files or included as an external file

Areas of Application

  • Creating interactive websites
  • Form validation
  • Loading dynamic content (AJAX)
  • Animations and visual effects
  • Single-Page Applications (SPAs)
  • Server-side development (Node.js)

Basic JavaScript Syntax

JavaScript code can be included in an HTML file in various ways:


<script>
    // JavaScript code goes here
</script>

Or as an external file:


<script src="myscript.js"></script>

Important Syntax Rules

  • Statements end with a semicolon ;
  • JavaScript is case-sensitive
  • Comments are marked with // for single-line or /* */ for multi-line comments

Variables and Data Types

Variable Declaration

In JavaScript, variables can be declared using let, const, or var (outdated):


// Variable declaration with let
let a = 17, b = 23, c;
c = a + b;

// Constants with const (value cannot be changed)
const PI = 3.14159;

// Variable declaration with var (older method)
var name = "Max";
Important

The use of var should be avoided as it can lead to unexpected behaviors. Instead, use let for mutable variables and const for constants.

Example from 07_js_variablen.html:


let a = 17, b = 23, c;
c = a + b;
console.log(c); // Output: 40

Data Types in JavaScript

JavaScript has the following basic data types:

  • Number: Integers and floating point numbers
  • String: Text and character strings
  • Boolean: Truth values (true or false)
  • Object: Complex data structures
  • Array: Ordered lists (technically an object)
  • Undefined: A variable without an assigned value
  • Null: An empty or non-existent value

Output Methods

JavaScript offers various methods to output content:


// Output in the developer console
console.log("Hello World");
console.log(c); // Output of a variable
console.log("The content of c is:", c); // Output multiple values

// Display alert box
alert("The value of c is: " + c);

// Display confirmation dialog
let decision = confirm("Do you really want to do this?");
console.log("decision=", decision);

// Display input prompt
let fn = prompt("Please enter your first name:");
console.log("The entered first name was:", fn);

// Output in the HTML document
document.write('

The entered first name is: ' + fn + '

');
Caution

Using document.write() after a page has loaded overwrites the entire content. Therefore, use this method with caution.

Conditions and Branching

if/else Conditions

With if statements, decisions can be made based on conditions:


let z = Math.random(); // Random number between 0 and 1

if(z > 0.5) {
    console.log("z is greater than 0.5:", z);
} else {
    console.log("z is less than or equal to 0.5:", z);
}

Multiple conditions can be linked using else if:


let fn = prompt("Please enter your first name:");

if(fn == "Alex") {
    console.log("Hello Alexander");
} else if(fn == "Sabine") {
    console.log("Hi Sabine");
} else if(fn == "Thomas" || fn == "Tom") {
    console.log("Hi Tom");
} else {
    console.log("Hello stranger");
}

switch Statements

The switch statement provides an alternative to multiple if/else blocks:


let fn = prompt("Please enter your first name:");

switch(fn) {
    case "Alex":
        console.log("Hello Alexander");
        break;
    
    case "Sabine":
        console.log("Hi Sabine");
        break;
        
    case "Thomas":
    case "Tom":
        console.log("Hi Tom");
        break;
        
    default:
        console.log("Hello stranger");
}
Note

The break statement is important to end execution after a matching case. Without break, execution would continue into the next case block.

An interesting example of switch with true:


let z2 = Math.random();

switch(true) {
    case z2 < 0.2:
        console.log("Very small number", z2);
        break;
    
    case z2 < 0.5:
        console.log("Medium number", z2);
        break;
        
    case z2 < 0.8:
        console.log("Larger number", z2);
        break;
        
    default:
        console.log("Large number", z2);
}

Loops

for Loop

The for loop is used when the number of iterations is known:


for(let i = 0; i < 10; i++) {
    console.log("i=", i);
}

Example with decrementing and step size:


for(let i = 25; i > -23; i -= 3.34) {
    console.log("i=", i);
}

while Loop

The while loop is used when the number of iterations is not known in advance:


let z = Math.random();
console.log("(1) z=", z);

while(z < 0.5) {
    z = Math.random();
    console.log("(2) z=", z);
}

console.log("(3) z=", z);
Beware of Infinite Loops

With while loops, it must be ensured that the condition is eventually met, otherwise an infinite loop will occur:


// Infinite loop!
let z = 0.3;
while(z < 0.5) {
    console.log("z=", z);
    // z never changes, so the loop runs endlessly
}

do-while Loop

The do-while loop executes the code at least once before checking the condition:


let z2;
do {
    z2 = Math.random();
    console.log("(2a) z2=", z2);
} while(z2 < 0.5);

console.log("(3a) z2=", z2);

Arrays

Creating Arrays

Arrays are ordered lists that can contain different data types:


// Create array with literal notation
let a = [];

// Create array with constructor notation
let b = new Array();

// Array with initialized values
let colors = ["Red", "Green", "Blue"];

Assigning array values:


let a = [];
a[0] = "First entry";
a[1] = 42;
a[3] = 7; // Index 2 remains empty
console.log(a); // Output: ["First entry", 42, undefined, 7]

Accessing Arrays


let a = [];
a[3] = 7;
console.log(a[3]); // Output: 7

// Accessing arrays with variables
let x = 3;
console.log(a[x]); // Output: 7

Array Iteration

Traversing an array with a for loop:


// Traverse array forward
for(let i = 0; i < a.length; i++) {
    console.log("a[" + i + "]=", a[i]);
}

// Traverse array backward
for(let i = a.length-1; i >= 0; i--) {
    console.log("a[" + i + "]=", a[i]);
}

// Output every second entry
for(let i = 0; i < a.length; i += 2) {
    console.log("a[" + i + "]=", a[i]);
}

Multidimensional Arrays:


// Array with people (first and last name)
let people = [];
people[0] = ["Uwe", "Mutz"];
people[1] = ["Silvia", "Mutz"];
people[2] = ["Harald", "Maier"];
people[3] = ["Ernst", "August"];

console.log(people);

Array Methods

JavaScript provides various methods to add or remove elements from arrays:

Mnemonic to Remember

The length of the method name corresponds to the impact on the array:

  • pop() – short word, makes the array shorter (removes element at the end)
  • push() – longer word, makes the array longer (adds element at the end)

  • shift() – short word, makes the array shorter (removes element at the beginning)
  • unshift() – longer word, makes the array longer (adds element at the beginning)

Overview of Array Methods


// Create array
let numbers = [1, 2, 3];
console.log(numbers); // Output: [1, 2, 3]
                
// push() - adds at the END (longer word = array becomes longer)
numbers.push(4);
console.log(numbers); // Output: [1, 2, 3, 4]
                
// pop() - removes at the END (shorter word = array becomes shorter)
let lastNumber = numbers.pop();
console.log(numbers); // Output: [1, 2, 3]
console.log(lastNumber); // Output: 4
                
// unshift() - adds at the BEGINNING (longer word = array becomes longer)
numbers.unshift(0);
console.log(numbers); // Output: [0, 1, 2, 3]
                
// shift() - removes at the BEGINNING (shorter word = array becomes shorter)
let firstNumber = numbers.shift();
console.log(numbers); // Output: [1, 2, 3]
console.log(firstNumber); // Output: 0
                
// splice() - for changes at ANY position
// splice(startIndex, numberOfItemsToRemove, elementsToAdd...)
numbers.splice(1, 1); // Remove 1 element from index 1
console.log(numbers); // Output: [1, 3]
                
numbers.splice(1, 0, 2); // Insert element 2 at index 1
console.log(numbers); // Output: [1, 2, 3]
                
numbers.splice(1, 1, 4, 5); // Replace 1 element at index 1 with 4, 5
console.log(numbers); // Output: [1, 4, 5, 3]
Important

The splice() method is more versatile than push(), pop(), shift(), and unshift() because it can work at any position in the array. It can remove elements, add elements, or do both simultaneously.

Functions

Function Declaration

Functions are reusable blocks of code that perform specific tasks. They can be defined in different ways:


// Function declaration
function f0() {
    let a = 17, b = 23, c;
    c = a + b;
    console.log("f0: c=", c);
}
            
// Function expression (anonymous function)
let greeting = function() {
    console.log("Hello World!");
};
            
// Immediately Invoked Function Expression (IIFE)
(function() {
    console.log("I am executed immediately!");
})();
            
// Function call
f0();
Note

Functions defined using function declaration are loaded through "hoisting" before the actual execution of the code and can therefore be called before their definition. This is not possible with function expressions.

Parameters and Return Values

Functions with parameters accept values that are used within the function. With return, functions can return values:


// Function with parameters, without return value
function f1(a, b) {
    let c = a + b;
    console.log("f1: c=", c);
}
            
// Function without parameters, with return value
function f2() {
    let a = 17, b = 23, c;
    c = a + b;
    console.log("f2: c=", c);
    return c;    // returns the value
}
            
// Function with parameters and return value
function f3(a, b) {
    let c = a + b;
    console.log("f3: c=", c);
    return c;
}

Function calls with parameters and return values:


f1(17, 23); // Call with parameters, no return value
            
let result = f2(); // Return value is stored in variable
console.log("result=", result);
            
let sum = f3(17, 23); // Passes values and stores the result
console.log("sum=", sum);
Important to Understand

When a function returns a value with return, this value must be stored in a variable if you want to use it further.

Functions with multiple return values (as an array):


function f4(a, b, c) {
    let sum = a + b + c;
    let average = sum / 3;
    return [sum, average]; // Return multiple values as an array
}
            
let results = f4(2, 3, 4);
console.log("Sum:", results[0], "Average:", results[1]);

Functions with optional parameters and default values:


function f5(a, b, c = 0, d = 0) {
    // c and d are optional and initialized with 0 if not specified
    let sum = a + b + c + d;
    let average = sum / 4;
    return [sum, average];
}
            
let e3 = f5(2, 3); // c and d are initialized with 0
console.log("e3=", e3);

Functions with rest parameters for a variable number of arguments:


function f7(...numbers) {
    // numbers is an array with all passed arguments
    let sum = 0;
    for(let i = 0; i < numbers.length; i++) {
        sum += numbers[i];
    }
    let average = numbers.length > 0 ? sum / numbers.length : 0;
    return [sum, average];
}
            
let e7 = f7(); // No parameters
let e8 = f7(1, 2, 3, 4, 5, 6, 7, 8); // Multiple parameters

Arrow Functions

Arrow functions are a shorter syntax for functions available in newer JavaScript versions:


// Traditional function
function add(a, b) {
    return a + b;
}
            
// As arrow function
const add2 = (a, b) => a + b;  // Short form without curly braces automatically returns
            
// Arrow function with code block
const calc = (a, b) => {
    const result = a + b;
    return result;  // With curly braces, return is required
};
            
// Arrow function without parameters
const sayHello = () => console.log("Hello World!");
Note

Arrow functions don't have their own this, but inherit this from the surrounding context. This makes them particularly useful for event handlers and callbacks, where traditional functions often have problems with this.

For single-line arrow functions without curly braces, the return is implicit - the value is automatically returned.

Objects

Creating Objects

Objects are collections of properties (key-value pairs):


// Create empty object
let o = {};

// Assign properties
o["FN"] = "Uwe";
o["LN"] = "Mutz";
console.log(o);

// Object with initialized properties
let o2 = {
    FN: "Silvia",
    LN: "Mutz"
};
console.log(o2);

Accessing Properties

Object properties can be accessed in two ways:


// Bracket notation
    console.log(o2["FN"]); // Output: Silvia
                        
    // Dot notation
    console.log(o2.FN); // Output: Silvia
                        
// Dynamic access with variables
    let x = "FN";
    console.log(o2[x]); // Output: Silvia
    console.log(o2.x);  // Output: undefined (there is no property 'x')

Iterating through objects:


for(let property in o2) {
    console.log(property + ":", o2[property]);
}

DOM Manipulation

The Document Object Model (DOM) is a programming interface for HTML and XML documents. It represents the structure of a document as a tree structure where each node is an object representing a part of the document.

DOM Selectors

Elements in the DOM can be selected in various ways:


// Select a single element
let img = document.querySelector("img");
                        
// Select multiple elements
let paragraphs = document.querySelectorAll("p");
                        
// Access the first paragraph element
let firstParagraph = document.querySelector("p");
                        
// Access the second paragraph
let secondParagraph = document.querySelectorAll("p")[1];
                        
// Select elements by ID
let button = document.querySelector("#btn0");

Editing DOM Elements

Properties of DOM elements can be changed directly:


// Change image source
document.querySelector("img").src = "images/image2.jpg";
                        
// Set alternative text and title
document.querySelector("img").alt = "This is the alternative text";
document.querySelector("img").title = "A lion...";
                        
// Change HTML content
document.querySelector("p").innerHTML = "A <strong>small</strong> test";
                        
// Manage CSS classes
console.log("Class list:", document.querySelectorAll("p")[1].classList);
                        
// Toggle class (add/remove)
document.querySelectorAll("p")[1].classList.toggle("a");

Event Handling

Events allow reacting to user actions:

Inline Event Handlers


<button type="button" id="btn0" onclick="document.querySelector('img').src = 'images/image2.jpg';">
    change the image
</button>

addEventListener Method


document.addEventListener("DOMContentLoaded", () => {
    const btn0 = document.querySelector("#btn0");
    
    btn0.addEventListener("click", () => {
        document.querySelector('img').src = 'images/image2.jpg';
    });
});

The DOMContentLoaded event:


document.addEventListener("DOMContentLoaded", function() {
    console.log("DOMContentLoaded has occurred");
    // Now the DOM is fully loaded and can be manipulated
});
Note

The DOMContentLoaded event is triggered when the HTML document has been completely loaded and parsed. It doesn't wait for stylesheets, images, and frames to load.

Various Event Types:


const btn0 = document.querySelector("#btn0");
const img0 = document.querySelector("img");
                        
// Click event
btn0.addEventListener("click", () => {
    img0.src = 'images/image2.jpg';
});
                        
// Double-click event
btn0.addEventListener("dblclick", () => {
    img0.src = 'images/image3.jpg';
});
                        
// Mouse over element
img0.addEventListener("mouseover", () => {
    img0.src = "images/image4.jpg";
});
                        
// Mouse leaves element
img0.addEventListener("mouseout", () => {
    img0.src = "images/image1.jpg";
});

Form Events


document.addEventListener("DOMContentLoaded", () => {
    const frm = document.querySelector("form");
    frm.addEventListener("submit", (ev) => {
        ev.preventDefault(); // Prevents the form from being submitted by default
        
        // Form validation
        const pwd0 = document.querySelector("[name='P0']").value;
        if(pwd0.length >= 8) {
            // Password length is ok
            const pwd1 = document.querySelector("[name='P1']").value;
            if(pwd0 == pwd1) {
                // Passwords match
                frm.submit(); // Submit form
            } else {
                document.querySelector("#errors").innerHTML = "Unfortunately, the passwords do not match";
            }
        } else {
            document.querySelector("#errors").innerHTML = "Unfortunately, the chosen password is too short";
        }
    });
});

Time-controlled Functions

setTimeout

setTimeout executes code once after a specific delay:


let gbl_to; // Global variable for the timeout
                        
document.addEventListener("DOMContentLoaded", () => {
    // Executes the removeButton function after 3 seconds
    gbl_to = setTimeout(removeButton, 3000);
                            
    const btn0 = document.querySelector("#btn0");
    btn0.addEventListener("click", () => {
        clearTimeout(gbl_to); // Delete timeout
        console.log("The timeout has been deleted");
    });
});
                        
function removeButton() {
    document.querySelector("#btn0").remove();
    console.log("The timeout has been executed");
}

setInterval

setInterval executes code repeatedly at regular intervals:


let gbl_itv; // Global variable for the interval
                        
document.addEventListener("DOMContentLoaded", () => {
    const btnPLAY = document.querySelector("#btnPlay");
    const btnSTOP = document.querySelector("#btnStop");
                            
    btnPLAY.addEventListener("click", () => {
        // Start interval that calls the browse function every 2 seconds
        clearInterval(gbl_itv);
        gbl_itv = setInterval(() => { browse(1); }, 2000);
    });
                            
    btnSTOP.addEventListener("click", () => {
        clearInterval(gbl_itv);
    });
});

Practical Example: Image Gallery

This example shows how to create a simple image gallery with JavaScript:

HTML Structure


<img src="images/gallery/image0.jpg" alt=".." id="pic">
<div id="control">
    <button type="button" id="btnBack">‹</button>
    <button type="button" id="btnForward">›</button>
    <button type="button" id="btnPlay">Play</button>
    <button type="button" id="btnStop">Stop</button>
</div>

CSS Styling


img {
    width: 20em;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    object-position: center;
    display: block;
    margin: 1em auto;                     
    border: 2px solid grey;
    padding: 0.5em;
    border-radius: 0.2em;
}
#control {
    text-align: center;
}

JavaScript Functionality


let images = [
    "images/gallery/image0.jpg",
    "images/gallery/image1.jpg",
    "images/gallery/image2.jpg",
    "images/gallery/image3.jpg",
    "images/gallery/image4.jpg"
];
let imageCounter = 0; // Index of the current image
let gbl_itv; // Variable for the interval
let gbl_itvrunning = false;
                        
document.addEventListener("DOMContentLoaded", () => {
    const btnFWD = document.querySelector("#btnForward");
    const btnBCK = document.querySelector("#btnBack");
    const btnPLAY = document.querySelector("#btnPlay");
    const btnSTOP = document.querySelector("#btnStop");
                            
    btnFWD.addEventListener("click", () => {
        browse(1);
    });
                            
    btnBCK.addEventListener("click", () => {
        browse(-1);
    });
                            
    btnPLAY.addEventListener("click", () => {
        startInterval();
    });
                            
    btnSTOP.addEventListener("click", () => {
        stopInterval();
    });
});
                        
function browse(direction) {
    clearInterval(gbl_itv);
                            
    imageCounter += direction;
    switch(true) {
        case imageCounter == images.length:
            imageCounter = 0;
            break;
        case imageCounter == -1:
            imageCounter = images.length - 1;
            break;
    }
    document.querySelector("#pic").src = images[imageCounter];
    
    if(gbl_itvrunning) {
        startInterval();
    }
}
                        
function startInterval() {
    clearInterval(gbl_itv);
    gbl_itv = setInterval(() => { browse(1); }, 2000);
    gbl_itvrunning = true;
}
                        
function stopInterval() {
    clearInterval(gbl_itv);
    gbl_itvrunning = false;
}

Additional Exercises for the Image Gallery

Here are some extension ideas for the image gallery that you can implement independently:

Note

The following exercises build on the basic example of the image gallery. Try to solve the tasks yourself before looking at the solutions.

Exercise 1: Read Images from HTML Code

Instead of hard-coding the image paths in the JavaScript array, the images should be read from the HTML code.

Task: Implement an image gallery that reads existing <img> tags from the HTML DOM, stores them in an array, and then uses them for the gallery.

HTML Structure


<div id="gallery">
    <img src="images/gallery/image0.jpg" alt="..">
    <img src="images/gallery/image1.jpg" alt="..">
    <img src="images/gallery/image2.jpg" alt="..">
    <img src="images/gallery/image3.jpg" alt="..">
    <img src="images/gallery/image4.jpg" alt="..">
    <div id="control">
        <button type="button" id="btnBack">‹</button>
        <button type="button" id="btnForward">›</button>
        <button type="button" id="btnPlay">Play</button>
        <button type="button" id="btnStop">Stop</button>
    </div>
</div>

JavaScript Solution


let images = [];
let imageCounter = 0; // Index of the current image
let gbl_itv; // Variable for the interval
let gbl_itvrunning = false;
                        
document.addEventListener("DOMContentLoaded", () => {
    // Read images and remove them from the DOM
    const htmlimages = document.querySelectorAll("#gallery img");
    for(let i = 0; i < htmlimages.length; i++) {
        images.push(htmlimages[i].src);
        htmlimages[i].remove();
    }
                            
    // Create new image element for display
    const gallery = document.querySelector("#gallery");
    gallery.innerHTML = '' + gallery.innerHTML;
                            
    // Event handlers for buttons
    const btnFWD = document.querySelector("#btnForward");
    const btnBCK = document.querySelector("#btnBack");
    const btnPLAY = document.querySelector("#btnPlay");
    const btnSTOP = document.querySelector("#btnStop");
                            
    btnFWD.addEventListener("click", () => {
        browse(1);
    });
                            
    btnBCK.addEventListener("click", () => {
        browse(-1);
    });
                            
    btnPLAY.addEventListener("click", () => {
        startInterval();
    });
                            
    btnSTOP.addEventListener("click", () => {
        stopInterval();
    });
});
                        
function browse(direction) {
    clearInterval(gbl_itv);
                            
    imageCounter += direction;
    switch(true) {
        case imageCounter == images.length:
            imageCounter = 0;
            break;
        case imageCounter == -1:
            imageCounter = images.length - 1;
            break;
    }
    document.querySelector("#pic").src = images[imageCounter];
                            
    if(gbl_itvrunning) {
        startInterval();
    }
}
                        
function startInterval() {
    clearInterval(gbl_itv);
    gbl_itv = setInterval(() => { browse(1); }, 2000);
    gbl_itvrunning = true;
}
                        
function stopInterval() {
    clearInterval(gbl_itv);
    gbl_itvrunning = false;
}

Exercise 2: Dynamically Generate Gallery

Create an image gallery where the entire HTML code for the gallery is dynamically generated with JavaScript.

Task: Implement an image gallery whose HTML structure (image and controls) is completely generated by JavaScript.

HTML Structure (minimal)


<!doctype html>
<html lang="en">
    <head>
        <title>Image Gallery</title>
        <meta charset="utf-8">
        <!-- CSS and JavaScript here -->
    </head>
    <body>
        <!-- Empty body, content is generated by JS -->
    </body>
</html>

JavaScript Solution


let images = [
    "images/gallery/image0.jpg",
    "images/gallery/image1.jpg",
    "images/gallery/image2.jpg",
    "images/gallery/image3.jpg",
    "images/gallery/image4.jpg"
];
let imageCounter = 0; // Index of the current image
let gbl_itv; // Variable for the interval
let gbl_itvrunning = false;
                        
document.addEventListener("DOMContentLoaded", () => {
    // Generate HTML code for the gallery
    const body = document.querySelector("body");
    body.innerHTML += '';
                            
    // Event handlers for buttons
    const btnFWD = document.querySelector("#gallery #btnForward");
    const btnBCK = document.querySelector("#gallery #btnBack");
    const btnPLAY = document.querySelector("#gallery #btnPlay");
    const btnSTOP = document.querySelector("#gallery #btnStop");
                            
    btnFWD.addEventListener("click", () => {
        browse(1);
    });
                            
    btnBCK.addEventListener("click", () => {
        browse(-1);
    });
                            
    btnPLAY.addEventListener("click", () => {
        startInterval();
    });
                            
    btnSTOP.addEventListener("click", () => {
        stopInterval();
    });
});
                        
function browse(direction) {
    clearInterval(gbl_itv);
                            
    imageCounter += direction;
    switch(true) {
        case imageCounter == images.length:
            imageCounter = 0;
            break;
        case imageCounter == -1:
            imageCounter = images.length - 1;
            break;
    }
    document.querySelector("#gallery #pic").src = images[imageCounter];
                            
    if(gbl_itvrunning) {
        startInterval();
    }
}
                        
function startInterval() {
    clearInterval(gbl_itv);
    gbl_itv = setInterval(() => { browse(1); }, 2000);
    gbl_itvrunning = true;
}
                        
function stopInterval() {
    clearInterval(gbl_itv);
    gbl_itvrunning = false;
}

Exercise 3: Transition Effects

Extend the image gallery with a fade effect during image transitions.

Task: Implement an image gallery where the image transition is realized with a smooth fade effect.

HTML Structure


<div id="gallery">
    <div id="pics">
        <img src="images/gallery/image0.jpg" alt="..">
        <img src="images/gallery/image1.jpg" alt="..">
        <img src="images/gallery/image2.jpg" alt="..">
        <img src="images/gallery/image3.jpg" alt="..">
        <img src="images/gallery/image4.jpg" alt="..">
    </div>
    <div id="control">
        <button type="button" id="btnBack">‹</button>
        <button type="button" id="btnForward">›</button>
        <button type="button" id="btnPlay">Play</button>
        <button type="button" id="btnStop">Stop</button>
    </div>
</div>

CSS Styling


img {
    object-fit: cover;
    object-position: center;
    display: block;
                            
    position: absolute;
    left: 0px;
    top: 0px;
    width: 100%;
    height: 100%;
                            
    opacity: 100;
    transition: opacity 1s;
}
#control {
    text-align: center;
}
#pics {
    position: relative;
    width: 20em;
    aspect-ratio: 16 / 9;
    margin: 1em auto;
                            
    border: 2px solid grey;
    padding: 0.5em;
    border-radius: 0.2em;
}
                        
.fade {
    opacity: 0;
}

JavaScript Solution


let images = [];
let imageCounter = 0; // Index of the current image
let gbl_itv; // Variable for the interval
let gbl_itvrunning = false;
                        
document.addEventListener("DOMContentLoaded", () => {
    // Read images and set z-index
    const htmlimages = document.querySelectorAll("#gallery img");
    for(let i = 0; i < htmlimages.length; i++) {
        images.push(htmlimages[i].src);
        htmlimages[i].style = "z-index:" + (-i);
    }
                            
    // Event handlers for buttons
    const btnFWD = document.querySelector("#btnForward");
    const btnBCK = document.querySelector("#btnBack");
    const btnPLAY = document.querySelector("#btnPlay");
    const btnSTOP = document.querySelector("#btnStop");
                            
    btnFWD.addEventListener("click", () => {
        browse(1);
    });
                            
    btnBCK.addEventListener("click", () => {
        browse(-1);
    });
                            
    btnPLAY.addEventListener("click", () => {
        startInterval();
    });
                            
    btnSTOP.addEventListener("click", () => {
        stopInterval();
    });
});
                        
function browse(direction) {
    clearInterval(gbl_itv);
    if(direction == -1) {
        // back without animation
        const pics = document.querySelectorAll("#pics img");
        for(let i = 0; i < pics.length; i++) {
            let z = pics[i].style["z-index"];
            if(z == -pics.length + 1) {
                z = 1;
            }
            pics[i].style["z-index"] = z - 1;
        }
        setImageCounter(direction);
    }
    else {
        fadeOut();
        gbl_to = setTimeout(() => { reorderImages(direction); }, 1000);
    }
}
                        
function fadeOut() {
    const pic = document.querySelectorAll("#pics img")[imageCounter];
    pic.classList.add("fade");
}
                        
function reorderImages(direction) {
    const pics = document.querySelectorAll("#pics img");
    pics[imageCounter].style["z-index"] = -pics.length;
    for(let i = 0; i < pics.length; i++) {
        let z = pics[i].style["z-index"];
        pics[i].style["z-index"] = parseInt(z) + 1;
    }
    pics[imageCounter].classList.remove("fade");
    setImageCounter(direction);
    if(gbl_itvrunning) {
        startInterval();
    }
}
                        
function setImageCounter(direction) {
    imageCounter += direction;
    switch(true) {
        case imageCounter == images.length:
            imageCounter = 0;
            break;
        case imageCounter == -1:
            imageCounter = images.length - 1;
            break;
    }
}
                        
function startInterval() {
    clearInterval(gbl_itv);
    gbl_itv = setInterval(() => { browse(1); }, 3000);
    gbl_itvrunning = true;
}
                        
function stopInterval() {
    clearInterval(gbl_itv);
    gbl_itvrunning = false;
}

Best Practices

  • Use of let and const: Use let for variable variables and const for constants instead of var.
  • Event Delegation: Use event delegation to handle events efficiently for multiple elements.
  • Avoiding Global Variables: Limit the use of global variables and use local variables within functions instead.
  • Comments and Documentation: Document your code with meaningful comments.
  • Function-oriented Programming: Divide complex tasks into smaller, reusable functions.
  • Separation of Logic and Presentation: Keep JavaScript code, HTML, and CSS separate.
  • Error Handling: Implement appropriate error handling with try/catch blocks.

Summary

This learning material covers the basics of JavaScript, with a special focus on:

  • JavaScript syntax and data types
  • Variables and output methods
  • Conditions and loops
  • Arrays and objects
  • Functions and parameters
  • DOM manipulation and event handling
  • Time-controlled functions
  • Practical example of an image gallery

By combining theoretical concepts and practical examples, a comprehensive understanding of JavaScript basics should be achieved.

DE