- Lab
- Core Tech

Guided: Functions and Closures with JavaScript
This Guided Code Lab will teach you the fundamentals of functions and closures in JavaScript. You'll learn how to create and use named functions, anonymous functions, and closures while building a practical alarm clock application.

Path Info
Table of Contents
-
Challenge
Introduction
Welcome to the lab Guided: Functions and Closures with JavaScript.
In this lab, you'll work on implementing functions and a closure to create an alarm clock application in JavaScript with the following features:
-
Display the current time in real-time.
-
Allow users to set alarms by specifying a time and a label.
-
Show a list of set alarms.
-
Trigger an alert when an alarm time matches the current time.
The application displays the current time, updating it every second. To set an alarm, users fill out a form by entering the desired alarm time and label. Upon form submission, the alarm is added to the list of alarms displayed on the page. When an alarm time matches the current time, an alert is triggered, notifying the user. Triggered alarms are automatically removed from the list. ---
Familiarizing with the Program Structure
The application is built with HTML, CSS, and JavaScript. It includes the following files:
-
index.html
: The HTML file that defines the structure and layout of the application. -
styles.css
: The CSS file that contains the styles for the visual appearance of the application. -
script.js
: The JavaScript file that contains the necessary functions and logic for the alarm clock functionality.
You'll focus on the
script.js
file. This file is partially completed, containing the necessary DOM element definitions and some function declarations.You can switch to the Web Browser tab to review the application. To load your latest changes, click on the Refresh button located at the top-left corner of the tab. Initially, the application will not display the current time, and you won't be able to set alarms. However, you can explore its options and familiarize with the user interface.
Start by examining the provided code and understanding the program structure. When you're ready, dive into the coding process. If you encounter any problems, remember that a
solution
directory is available for reference or to verify your code. -
-
Challenge
Named Functions
What are Named Functions?
In JavaScript, named functions are a way to define reusable blocks of code that can be called with a specific name. Named functions help in organizing code, promoting reusability, and improving code readability.
To define a named function, you use the
function
keyword followed by the function name, a list of parameters enclosed in parentheses (optional), and the function body enclosed in curly braces:function functionName(parameter1, parameter2) { // Function body // Code to be executed }
Functions can accept parameters, which are values that the function expects to receive when it is called.
To call a named function, you simply use the function name followed by parentheses and pass any required arguments:
functionName(argument1, argument2);
The parameters act as placeholders for the actual values (arguments) that will be passed to the function.
For example, the following snippet defines a function named
greet
that takes aname
parameter:function greet(name) { console.log("Hello, " + name + "!"); }
You can call the
greet
function with the argumentJohn
like this:greet("John"); // Output: Hello, John!
Functions can also return a value using the
return
statement. The returned value can be used by the code that called the function:function multiply(a, b) { return a * b; } let result = multiply(2, 3); console.log(result); // Output: 6
Here, the
multiply
function returns the product ofa
andb
, which is then assigned to theresult
variable.Variables declared inside a function are only accessible within that function. This is known as function scope. It helps in avoiding naming conflicts and keeps the variables encapsulated within the function.
function calculateArea(width, height) { let area = width * height; return area; } console.log(area); // Error: area is not defined
In this case,
area
is a local variable inside thecalculateArea
function and cannot be accessed outside of it.In the next tasks, you'll implement a function to format the time shown in the application in a specific format. In the
script.js
file, locate theformatTime
function. This function should take hours, minutes, and optionally seconds as parameters and return a formatted time string in the desired format. -
Challenge
Anonymous Functions
What are Anonymous Functions?
Anonymous functions are functions without a name. They are often used when a function is needed as a value or as an argument to another function.
To define an anonymous function, you use the
function
keyword followed by a list of parameters enclosed in parentheses (optional), and the function body enclosed in curly braces:function (parameter1, parameter2) { // Function body // Code to be executed }
Anonymous functions are commonly used in combination with function expressions, where the function is assigned to a variable. This variable holds a reference to the function, allowing you to invoke the function using the variable name:
const greet = function (name) { console.log("Hello, " + name + "!"); }; greet("John"); // Output: Hello, John!
In this example, the variable
greet
holds a reference to an anonymous function that takes aname
parameter and logs a greeting message.Anonymous functions are also used as arguments to other functions, such as
setTimeout()
,setInterval()
, oraddEventListener()
. These functions expect a callback function as an argument, which is executed when a specific event occurs or after a certain time delay.For example, say you want to execute a function every
2
seconds usingsetInterval()
:setInterval(function () { console.log("Repeated message"); }, 2000);
In this case, an anonymous function is passed as the first argument to
setInterval()
. The function will be executed every2000
milliseconds (2
seconds).You can also use arrow functions to define anonymous functions in a concise way. The syntax is the following:
(parameters) => { // Function body // Code to be executed }
If the function has only one parameter, the parentheses can be omitted:
parameter => { // Function body // Code to be executed }
If the function body consists of a single expression, the curly braces can be omitted, and the expression will be implicitly returned:
(parameters) => expression
Here's an example of using an arrow function with
setInterval()
:setInterval(() => { console.log("Repeated message"); }, 2000);
In this case, an arrow function is passed as the first argument to
setInterval()
. Notice that the arrow function doesn't define any parameters, however, the parentheses are still required.In the next tasks, you'll implement the anonymous function passed to a
setInterval()
function used by the application. In thescript.js
file, locate the anonymous function passed tosetInterval()
, inside theinitializeApp()
function. This function should update the current time shown in the HTML page every second. By getting the current timestamp usingnew Date()
and assigning it to thenow
variable inside the anonymous function passed tosetInterval
, you ensure that the current date and time are obtained at each interval (every second). This is necessary because you want to display the updated time on the web page continuously. If you placed this line outside the anonymous function, it would only get the current time once, and the displayed time would not update every second as intended. -
Challenge
Closures
What is a Closure?
A closure is a function that has access to variables in its outer (enclosing) lexical scope, even after the outer function has returned. In other words, a closure allows a function to "remember" and access variables from its outer scope, even when the function is executed in a different scope.
To create a closure, you simply define a function inside another function. The inner function has access to the variables and parameters of the outer function, as well as any variables defined in its own scope.
Here's a simple example of a closure:
function outerFunction(x) { let y = 10; function innerFunction() { console.log(x + y); } return innerFunction; } const closure = outerFunction(5); closure(); // Output: 15
In this example,
outerFunction
takes a parameterx
and defines a variabley
. It also defines aninnerFunction
that accesses bothx
andy
. TheouterFunction
returns theinnerFunction
, which is assigned to the variableclosure
. Whenclosure
is invoked, it still has access to the variablesx
andy
from the outer function, even thoughouterFunction
has already finished executing.Closures are often used to create private state and encapsulate data. By defining variables inside the outer function and returning an object or functions that access those variables, you can create a closure that maintains its own private data.
Here's an example of using a closure for encapsulation:
function createCounter() { let count = 0; return { increment: function () { count++; }, getCount: function () { return count; } }; } const counter = createCounter(); counter.increment(); counter.increment(); console.log(counter.getCount()); // Output: 2
In this example,
createCounter
is a function that returns an object with two methods:increment
andgetCount
. Thecount
variable is defined insidecreateCounter
and is not directly accessible from outside the function. Theincrement
method modifies thecount
variable, and thegetCount
method retrieves its current value. This way, thecount
variable is encapsulated and can only be accessed and modified through the returned object.Closures are also commonly used with event handlers and callbacks. When an event handler is defined inside another function, it forms a closure and can access variables from its outer scope.
Here's an example of using a closure with an event handler:
function setupButton(buttonId) { let count = 0; document.getElementById(buttonId).addEventListener('click', function () { count++; console.log(`Button clicked ${count} times`); }); } setupButton('myButton');
In this example,
setupButton
takes abuttonId
parameter and sets up a click event handler for the button with that ID. The event handler is defined insidesetupButton
and forms a closure, allowing it to access thecount
variable. Each time the button is clicked, thecount
variable is incremented, and the current count is logged to the console.In the next tasks, you'll use a closure to encapsulate the alarm-related functionality and data within the
createAlarmManager
function, and use it in other parts of the program. In thescript.js
file, locate thecreateAlarmManager
function. This function will serve as a closure to encapsulate the alarm-related data and functions. You'll move the necessary elements inside thecreateAlarmManager
function to create a proper closure. After completing the task, thecreateAlarmManager
function should contain thealarms
array and all the related functions within its scope. ThesetInterval
call and the returned object withaddAlarm
anddisplayAlarms
functions should remain unchanged. In thescript.js
file, locate theinitializeApp
function. This function is responsible for setting up the initial state of the application and handling user interactions. You'll add the necessary code to display the initial state of alarms using thealarmManager
closure. By callingalarmManager.displayAlarms()
after creating an instance of the alarm manager, you ensure that the initial state of alarms is displayed correctly when the application starts. In thescript.js
file, locate theinitializeApp
function. Inside this function, find the anonymous function passed toalarmForm.addEventListener('submit', ...)
. This anonymous function handles the form submission event for adding a new alarm. You'll modify the code to register the new alarm using thealarmManager
closure. -
Challenge
Conclusion
Congratulations on successfully completing this Code Lab!
To try the application, navigate to the Web Browser tab. Then, click the Refresh button located in the top-left corner to load your changes. You can also click the New Tab button in the top-right corner to open the application in a new browser tab. As a test, set an alarm for the nearest minute in the future. Wait to see how an alert window is triggered at that time.
For simplicity, the application uses an element of type
<input type="time">
to allow the user to specify the alarm time. However, the display format of this element may vary depending on your browser and system locale settings. While some browsers might use a 12-hour format with AM/PM, others may use a 24-hour format. Keep this in mind when testing and using the alarm clock application. ---Extending the Program
Consider exploring these ideas to further enhance your skills and expand the capabilities of the alarm clock program:
-
Ensure consistent time format. To provide a consistent user experience across different browsers and systems, consider implementing custom input fields or using a library that allows you to enforce a certain time format (or even allow the user to choose one) for the alarm time input.
-
Allow editing and deleting alarms. Implement functionality that allows users to edit the time and label of existing alarms, as well as delete alarms they no longer need. This will provide users with more control over their alarm settings and help keep the alarm list organized.
-
Implement custom alarm sounds. Enhance the alarm clock by allowing users to choose custom sounds for each alarm. You can provide a selection of predefined sounds or even allow users to upload their own audio files. This will make the alarm experience more personalized and engaging.
-
Persist alarms across page refreshes. Use the browser's local storage API to store the alarm data so that the alarms persist even if the user refreshes the page or closes the browser. This way, users won't lose their alarm settings, and the alarm clock will maintain its state across sessions.
-
Implement recurring alarms. Extend the alarm clock to support recurring alarms that can be set to repeat daily, weekly, or on specific days of the week. This will be useful for users who have regular schedules or need to be reminded of recurring events or tasks. ---
Related Courses on Pluralsight's Library
If you're interested in further honing your JavaScript skills or exploring more topics, Pluralsight offers several excellent courses in the following path:
These courses cover many aspects of JavaScript programming. Check them out to continue your learning journey in JavaScript!
-
What's a lab?
Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.
Provided environment for hands-on practice
We will provide the credentials and environment necessary for you to practice right within your browser.
Guided walkthrough
Follow along with the author’s guided walkthrough and build something new in your provided environment!
Did you know?
On average, you retain 75% more of your learning if you get time for practice.