This module is about functional programming and the oriented programming paradigm. You will learn what scope is in JavaScript. You’ll explore the differences between var, let and const. And you’ll learn how to use classes and inheritance in object oriented programming. Additionally, you’ll explore how to use write JavaScript using modern features like spread and rest. You will build code that can manipulate the DOM and handle events. And you will use JSON in JavaScript. After completing this module, you will be able to:
Learning Objectives
- Outline the tenets of the functional programming and object-oriented programming paradigm
- Describe how scope works in JavaScript
- List the differences between var, let, and const
- Use classes and inheritance in OOP in JavaScript
- Use JSON in JavaScript
- Build code that manipulates the DOM and handles events
- Write JavaScript code using more modern features like spread, rest, template strings, and modules
- Introduction to Functional Programming
- Video: Introduction to functional programming
- Reading: Return values from functions
- Video: Function calling and recursion
- Video: Introduction to scope
- Reading: The functional programming paradigm
- Programming Assignment: Building a functional program
- Video: Scoping with var, let and const
- Video: Comparing var, let and const
- Practice Quiz: Knowledge check: Introduction to Functional Programming
- Reading: Additional resources
- Introduction to Object-Oriented Programming
- Video: Introduction to object-oriented programming
- Video: Classes
- Reading: Object Oriented Programming principles
- Reading: Constructors
- Video: Inheritance
- Reading: Creating classes
- Reading: Default Parameters
- Reading: Designing an OO Program
- Programming Assignment: Building an object-oriented program
- Practice Quiz: Knowledge check: Introduction to Object-Oriented Programming
- Reading: Additional resources
- Advanced Javascript Features
- Video: De-structuring arrays and objects
- Reading: For of loops and objects
- Video: For- of loops and objects
- Reading: Template literals examples
- Video: Working with template literals
- Programming Assignment: Array and object iteration
- Video: Data Structures
- Reading: Data Structures examples
- Video: Spread operator
- Video: Rest operator
- Reading: Using Spread and Rest
- Practice Quiz: Knowledge check: Advanced JavaScript Features
- Reading: Additional resources
- Javascript in the Browser
- Task 5: Add an event listener
Introduction to Functional Programming
Video: Introduction to functional programming
Key Points:
- Programming paradigms are different approaches to writing code, similar to various styles in human languages.
- Functional programming (FP) focuses on clear separation between data and functions.
- Data exists outside functions and can be passed as arguments.
- Functions receive data, perform operations, and return results.
- Unlike object-oriented programming (OOP), data and functions aren’t bundled in objects.
- The example calculates currency conversion using a function named
convertCurrency
that multipliesamount
byrate
. - The function’s output is used to update a variable holding the converted currency value.
- This demonstrates how FP separates data and logic cleanly for solving problems.
Overall:
Functional programming offers a distinct approach to code structure and data manipulation, with its emphasis on data immutability and pure functions. By understanding its principles, developers can choose the programming paradigm best suited for their specific needs and goals.
** Welcome to the Wonderful World of Functional Programming in JavaScript!**
In this tutorial, we’ll dive into the core concepts of functional programming (FP) and explore how to apply them in JavaScript to create more elegant, maintainable, and bug-resistant code.
Here’s a roadmap of our journey:
- Paradigm Shift: Understanding the FP mindset and its key principles.
- Functions as First-Class Citizens: Treating functions like any other data type, passing them around, and returning them from other functions.
- Immutability: Embracing the concept of non-mutating data to ensure predictability and reduce side effects.
- Pure Functions: Functions that always produce the same output for the same input, making testing and reasoning easier.
- Higher-Order Functions: Functions that operate on other functions, like
map
,filter
, andreduce
, unlocking powerful data manipulation techniques. - Recursion: Solving problems by breaking them down into smaller, self-similar subproblems, often leading to elegant and concise solutions.
- JavaScript’s FP Arsenal: Exploring built-in FP features like arrow functions,
const
,let
, and template literals. - Common FP Patterns: Mastering techniques like function composition and currying to create modular and reusable code.
- Real-World Examples: Applying FP to solve practical problems in JavaScript, such as data processing, asynchronous programming, and user interface design.
Get ready to:
- Think declaratively, focusing on what you want to achieve rather than how to achieve it step by step.
- Embrace immutability and pure functions for cleaner code and easier reasoning.
- Master higher-order functions for elegant data transformations.
- Unleash the power of recursion for concise problem-solving.
- Write more concise, expressive, and bug-free JavaScript code.
**Let’s embark on this exciting adventure together! **
In functional programming, the data and functions that work on that data are combined inside objects.
False
Correct! In functional programming, data and functions that operate on it are clearly separated, not combined inside objects.
When you listen to
a lecture in class, the language used is
probably very formal. Grammar rules are observed, and syntax and vocabulary can get quite complex
based on the topic. Some other examples
of the use of formal language can be found in courts and other
legal institutions. Now let’s consider
the way people talk in their everyday life. There’s lots of slang, grammar rules are
bent and broken, and the entire delivery
is colloquial. There are many styles in
every human language, and they all perform the exact same function,
communication. The same can also be said
about computer languages. They too have various styles, also known as
programming paradigms. Just like in human languages, no one style is better
suited than the other. In programming, there are
two commonly used paradigms. Functional programming,
sometimes abbreviated as FP, and object-oriented programming, sometimes abbreviated as OOP. You can think of
these paradigms as different approaches
to writing code. But the result is
still the same, instructing a computer to
perform a set of operations. In this lesson, you will learn about functional
programming. Let’s now focus on the
functional programming style. There is a clear distinction between data and functions in functional programming as data can exist outside of functions. For example, you may recall
that when functions need some data you pass them the values in the
form of arguments. Then the function
perform some work on the given data and returns some values that you can then use somewhere else
in your program. An alternative paradigm is the object-oriented
programming paradigm, where you combine both data
and functions into objects. You’ll learn more about object oriented
programming later. Now let’s examine a
practical implementation of the functional
programming style using a coding example to calculate
currency conversion. In this example of
functional programming, let me start by giving
my program some data. The purpose of the program is to perform currency conversions. Notice that I already have
a variable declared with the name currencyOne and
assigned it the value of 100. Next, I’ll add two more
variables, currencyTwo, which is assigned a value of 0, and exchangeRate,
which is set to 1.2. Notice that I have declared all these variable
names using CamelCase. This is where the
first letter of the first word is lowercase and the first letter of the
subsequent words are without spaces and in uppercase. Next, I can create the
function that will work with these variables
and operate on this data. First, I create a function named convertCurrency that
accepts two parameters, amount and rate. Then in the function’s body, I returned the result of the amount multiplied
by the rate. Basically, I’m coding
it to multiply the two values it receives
and return the result. Next, I need to update
the value of currencyTwo, which was previously
defined on line four, assigned to the value of 0. To do this, I
assign the value of currencyTwo to the result of
the function I just created. Recall that when the
function is invoked, it will return a
value which will be assigned to the
variable currencyTwo. It’s important to remember
that I need to also pass the two arguments required
for my function to work. In this example, I’m sending the variables currencyOne
and exchangeRate. Basically, I’m passing
the values 100 and 1.2 to the function so it can perform its calculation
and return the result. Finally, I console log the value of currencyTwo to test my code. Success, 120 is output
to the console, the result of 100
multiplied by 1.2. In this lesson,
you learned about functional programming
and how it can be used to solve a problem by separating data from functions. Great job.
Reading: Return values from functions
Reading
Many functions, by default, return the value of undefined.
An example is the console.log() function.
If I run:
console.log('Hello');
… here’s the output in the console:
Hello
undefined
Because the console.log() function is built so as to not have the explicitly set return value, it gets the default return value of undefined.
I’ll now code my own implementation of console.log(), which doesn’t return the value of undefined:
function consoleLog(val) {
console.log(val)
return val
}
I’m using the console.log() function inside my custom consoleLog function declaration. And I’m specifying it to return the value of its argument.
Now when I run my custom consoleLog() function:
consoleLog('Hello')
I get the following output:
Hello
'Hello'
So, the value is output in the console, but it’s also returned.
Why is this useful?
It’s useful because I can use return values from one function inside another function.
Here’s an example.
I’ll first code a function that returns a double of a number that it received:
function doubleIt(num) {
return num * 2
}
Now I’ll code another function that builds an object with a specific value:
function objectMaker(val) {
return {
prop: val
}
}
I can call the objectMaker() function with any value I like, such as:
objectMaker(20);
The returned value will be an object with a single prop key set to 20:
{prop:20}
Now consider this code:
doubleIt(10).toString()
The above code returns the number 20 as a string, that is: “20”.
I can even combine my custom function calls as follows:
objectMaker( doubleIt(100) );
This will now return the following value:
{prop: 200}
What does all of this mean?
It means that by JavaScript allowing me to use the return keyword as described above, I can have multiple function calls, returning data and manipulating values, based on whatever coding challenge I have in front of me.
Being able to return custom values is one of the foundations that makes functional programming possible.
Video: Function calling and recursion
– Definition: A recursive function is a function that calls itself within its own body, creating a loop-like behavior. – Potential Issue: If not designed carefully, it can lead to infinite loops, continuously calling itself without stopping. – Treadmill Analogy: Like a treadmill that needs a stopping mechanism, recursive functions require a condition to break the recursion and prevent endless running. – Example:
- A function named
example
was created. - It initially logged three lines of text.
- To demonstrate recursion, the function was modified to call itself, resulting in an infinite loop.
- To prevent this, a counter variable and a conditional statement were added:
- The counter starts at 3 and decrements with each function call.
- When the counter reaches 0, the function returns, ending the recursion. – Key Takeaways:
- Recursive functions offer an alternative way to repeat tasks without traditional loops.
- They’re powerful but require careful design to avoid infinite loops.
- A base case (like the counter reaching 0) is essential to ensure termination.
Welcome to the JavaScript Function Calling and Recursion Playground!
Here’s a guided tour through these fundamental concepts:
1. Function Calling: The Art of Delegation
- Function as a Recipe: Imagine a function as a recipe for performing a specific task. It has a name and a set of instructions (the code within its body).
- Calling a Function: When you call a function, you’re asking the JavaScript interpreter to execute those instructions.
- Syntax: JavaScript
functionName(arguments); // Example: greet("Alice");
- Example: JavaScript
function greet(name) { console.log("Hello, " + name + "!"); } greet("Bob"); // Output: Hello, Bob!
2. Recursion: Functions Calling Themselves
- Definition: A recursive function is a function that calls itself within its own body. It’s like a spiral staircase, where each step leads back to itself.
- Base Case: To avoid infinite loops, every recursive function must have a base case—a condition that stops the recursion.
- Example: Counting Down JavaScript
function countDown(number) { if (number === 0) { // Base case console.log("Blast off!"); } else { console.log(number); countDown(number - 1); // Recursive call } } countDown(3); // Output: 3, 2, 1, Blast off!
3. Visualizing Recursion: The Call Stack
- Think of the Call Stack as a Pile of Plates: Each function call adds a new plate to the stack, and each function return removes a plate.
- Understanding the Stack: When a function calls itself recursively, multiple instances of that function are added to the stack, each with its own local variables and execution context.
4. Common Use Cases for Recursion
- Traversing trees and graphs (e.g., file systems, family trees)
- Solving problems that can be broken down into smaller, self-similar subproblems (e.g., factorial calculation, Fibonacci sequence)
- Implementing algorithms like sorting and searching
5. Cautions and Considerations
- Infinite loops: Ensure a base case to prevent them.
- Performance overhead: Recursion can be slower than loops for large problems.
- Stack overflow: Too many nested calls can exhaust memory.
Get Ready to Experiment!
- Practice writing and calling functions.
- Explore recursive examples and visualize the call stack.
- Understand the benefits and trade-offs of recursion.
- Apply recursion to solve real-world problems.
Unlock the Power of Function Calling and Recursion in JavaScript!
Treadmills are a useful piece of
equipment for doing cardio at the gym, or when running outdoor isn’t an option. They are also easily started
with the push of a button. Imagine however, if there was no way
to control when a treadmill stopped, that wouldn’t be ideal, would it? Fortunately, most treadmills have a
function that tells the treadmill to stop after a specified amount of time. Thank goodness. In JavaScript, functions that
repeat tasks are similarly helpful, unless they run endlessly. In this video, I’ll demonstrate what
recursive functions are, and help you understand how to write them properly to
avoid getting stuck in an infinite loop. To call, invoke, or execute a function
means instructing it to follow the code inside of it one line at a time. To demonstrate,
let’s first build an example. Type function example, parentheses,
then left curly brace. Press enter to advance to the next
line and type console dot log. Inside of the parentheses,
type quote line one, unquote, and then close off with a semi colon. I now have one line of code,
but let’s add a few more. On separate lines, I am put two more
console dot log lines as I did before, but this time containing the strings
line two and line three respectively. I close the function by
inputting a right curly brace. I’ve built a function called
example with three lines. When I run it, each of the lines will
be executed one at a time in sequence producing three strings. To make things interesting, let’s add
one more line to the example function. This time,
type the name of the function itself. So that’s example, parentheses, semicolon. Now, if I run the function again,
it will repeat in an infinite loop. Obviously this wouldn’t be useful. So let’s improve it, and
ensure that it won’t run endlessly. I add a new line before the function and
let counter equal sign three semi colon. Next, I delete my three
console dot log lines, which I’ll replace with
some different code. For the first line,
I type console dot log, and then counter inside of the parentheses. On the second line, I type counter
equal sign, counter minus 1 semi colon. And finally, for the third line,
I start by typing if, and then inside of the parentheses,
I type counter triple equal sign, zero. And then I type return in a semi colon. If I call the function this time, it will
log the numbers 3, 2, 1, and then stop. When a function calls itself,
this is what’s known as recursion. Recursion is an alternative way to run
repetitive code without the use of loops. Next time you see someone
running on a treadmill, imagine a function running
in the background. It might be calling itself to continue
running until its condition is meant to stop. In this video, you learned about the uses
and potential problems of recursive functions, and how to write them so
that they don’t run endlessly.
Do you recall these comparison operators == and === ?
Yes
Great! But just in case, check out the reading, Operators in depth in Module 1 Lesson 2.
Consider the following code:
function myDay() {
console.log('Morning');
console.log('Afternoon');
console.log('Evening');
myDay();
}
Which one of the following best describes what will happen if you run this code?
The function will run in an infinite loop.
Correct! The function will run over and over, as there is no condition to stop it.
Video: Introduction to scope
Here’s a summary of the key points about scope in JavaScript:
Scope Defined:
- It determines which parts of the code (like variables and functions) are accessible from different parts of your program.
- It’s like a two-way mirror in a restaurant: code inside a function can see “out” to the global scope, but code outside can’t see “in” to the local scope.
Types of Scope:
- Global Scope:
- Code outside of any function.
- Variables and functions here are accessible from anywhere in the program.
- Local Scope (Function Scope):
- Code within a function.
- Variables and functions defined here are only accessible within that function.
Scope Chain:
- Each function has a reference to its parent scope, forming a chain.
- When a variable is not found in the local scope, JavaScript searches up the scope chain to find it.
Key Takeaways:
- Understanding scope is essential for writing well-organized and predictable JavaScript code.
- It helps prevent naming conflicts and unintended variable access.
- Knowing the different scope types and how the scope chain works is crucial for effective JavaScript development.
Welcome to the JavaScript Scope Playground!
In this tutorial, we’ll explore the concept of scope, a crucial part of writing well-structured and predictable JavaScript code.
Here’s what we’ll cover:
1. What is Scope?
- Imagine your code as a well-organized house with different rooms. Scope determines which variables and functions live in which rooms and who can access them.
- It prevents naming conflicts and unintended access, keeping your code clean and efficient.
2. Global Scope:
- The outermost room of your code house.
- Variables and functions declared here are like global house rules: everyone can see and use them from anywhere.
- Be mindful of what you put here to avoid clutter and potential conflicts.
3. Local Scope (Function Scope):
- Each function creates its own private room within the house.
- Variables and functions declared inside a function are like personal belongings: only accessible within that room.
- This keeps things organized and prevents unintended interactions.
4. Scope Chain: The Family Tree:
- Functions can also access variables from their parent scopes (the functions that contain them), creating a hierarchy like a family tree.
- JavaScript searches for variables up this chain if it can’t find them in the local scope, ensuring everyone has access to what they need.
5. Let’s Play with Scope!
- We’ll experiment with code examples to see scope in action.
- Observe how variables behave in different scopes and how the scope chain works.
- Write code that demonstrates local and global scope, and try to visualize the scope chain.
6. Best Practices:
- Embrace local scope whenever possible to keep code modular and avoid naming clashes.
- Use global scope sparingly, reserving it for truly shared values.
- Be mindful of scope when designing functions and interacting with variables.
7. Quiz Time!
- Test your understanding with fun and interactive quizzes.
By the end of this tutorial, you’ll be a scope master, ready to write clear, organized, and predictable JavaScript code!
You decide to create a variable within the local scope while scripting a new JavaScript file. Is this variable accessible to code at the global scope level?
No
Correct. Variables created within the local scope cannot be read by code at the global scope level. They are accessible only to functions located within the local scope.
Scope is all about
code accessibility. It determines which
parts of the code are accessible and which
parts are inaccessible. For example, what variables can a function
access within code? Over the next few minutes, you will explore the
concept of scope and learn about how the scope chain
works within JavaScript. You will also explore some of
the different scope types, such as global and local. A nice way to think
about how scope works in JavaScript is a
two-way mirror glass. This is a piece of glass where only one side is transparent. For example, if a restaurant
uses two-way glass, people outside the restaurant
can’t see what’s happening inside but the people inside can see what
is happening outside. The process is similar to how
scope works in JavaScript. For example, the
code that exists outside of a function is
referred to as global scope, and all the code inside
of a function is known as local scope
or function scope. If a variable is defined
within a function, then you can say it’s
scoped to that function. This is also known
as local scope. For example, I could
define a variable named localvar and place
it within a function. I could then say that
this variable is scoped to the function
in which it was created. Each function keeps a
reference to its parent scope. This chain of scope
references is referred to as the scope chain. You’re now familiar
with scope and how the scope chain
works in JavaScript. You can also identify how some of the different
types of scope work, including global and local, also known as function scope.
Reading: The functional programming paradigm
Reading
Learning Objectives
- Be able to explain that there are several programming paradigms
- Be able to explain the basic difference between the two predominant programming paradigms: functional programming and object-oriented programming
- Understand, at a very high level, how the functional programming paradigm works
“There are actually several styles of coding, also known as paradigms. A common style is called functional programming, or FP for short.
In functional programming, we use a lot of functions and variables.
function getTotal(a,b) {
return a + b
}
var num1 = 2;
var num2 = 3;
var total = getTotal(num1, num2);
When writing FP code, we keep data and functionality separate and pass data into functions only when we want something computed.
function getDistance(mph, h) {
return mph * h
}
var mph = 60;
var h = 2;
var distance = getDistance(mph, h);
In functional programming, functions return new values and then use those values somewhere else in the code.
function getDistance(mph, h) {
return mph * h
}
var mph = 60;
var h = 2;
var distance = getDistance(mph, h);
console.log(distance); // <====== THIS HERE!
Another style is object-oriented programming (OOP). In this style, we group data and functionality as properties and methods inside objects.
For example, if I have a virtualPet object, I can give it a sleepy property and a nap() method:
var virtualPet = {
sleepy: true,
nap: function() {}
}
In OOP, methods update properties stored in the object instead of generating new return values.
For example, if I check the sleepy property on the virtualPet object, I can confirm that it’s set to true.
However, once I’ve ran the nap() method on the virtualPet object, will the sleepy property’s value change?
//creating an object
var virtualPet = {
sleepy: true,
nap: function() {
this.sleepy = false
}
}
console.log(virtualPet.sleepy) // true
virtualPet.nap()
console.log(virtualPet.sleepy) // false
OOP helps us model real-life objects. It works best when the grouping of properties and data in an object makes logical sense – meaning, the properties and methods “belong together”.
Note that the goal here is not to discuss OOP in depth; instead, I just want to show you the simplest explanation of what it is and how it works, in order to make the single most important distinction between FP and OOP.
To summarize this point, we can say that the Functional Programming paradigm works by keeping the data and functionality separate. It’s counterpart, OOP, works by keeping the data and functionality grouped in meaningful objects.
There are many more concepts and ideas in functional programming.
Here are some of the most important ones:
- First-class functions
- Higher-order function
- Pure functions and side-effects
There are many other concepts and priciples in functional programming, but for now, let’s stick to these three.
First-class functions
It is often said that functions in JavaScript are “first-class citizens”. What does that mean?
It means that a function in JavaScript is just another value that we can:
- pass to other functions
- save in a variable
- return from other functions
In other words, a function in JavaScript is just a value – from this vantage point, almost no different then a string or a number. For example, in JavaScript, it’s perfectly normal to pass a function invocation to another function. To explain how this works, consider the following program.
function addTwoNums(a, b) {
console.log(a + b)
}
function randomNum() {
return Math.floor((Math.random() * 10) + 1);
}
function specificNum() { return 42 };
var useRandom = true;
var getNumber;
if(useRandom) {
getNumber = randomNum
} else {
getNumber = specificNum
}
addTwoNums(getNumber(), getNumber())
I start the program with the addTwoNums() function whose definition I’ve already used earlier in various variations. The reason why this function is a recurring example is because it’s so simple that it helps explain concepts that otherwise might be a bit harder to grasp. Next, I code a function named randomNum() which returns a random number between 0 and 10. I then code another function named specificNum() which returns a specific number, the number 42. Next, I save a variable named useRandom, and I set it to the boolean value of true. I declare another variable, named getNumber. This is where things get interesting. On the next several lines, I have an if else statement. The if condition is executed when the value of useRandom is set to true. If that’s the case, the entire randomNum() function’s declaration is saved into the getNumber variable. Otherwise, I’m saving the entire specificNum() function’s declaration into the getNumber variable. In other words, based on the useRandom being set to true or false, the getNumber variable will be assigned either the randomNum() function declaration or the specificNum() function declaration. With all this code set, I can then invoke the addTwoNums() function, passing it the invocation of the getNumber() variables as its first and second arguments. This works because functions in JavaScript are truly first-class citizens, which can be assigned to variable names and passed around just like I would pass around a string, a number, an object, etc. Note: most of the code inside the randomNum() function declaration comes from a previous lesson, namely the lesson that discussed the Math object in JavaScript. This brings me to the second foundational concept of functional programming, which is the concept of higher-order functions.
Higher-order functions
A higher-order function is a function that has either one or both of the following characteristics:
- It accepts other functions as arguments
- It returns functions when invoked
There’s no “special way” of defining higher-order functions in JavaScript. It is simply a feature of the language. The language itself allows me to pass a function to another function, or to return a function from another function. Continuing from the previous section, consider the following code, in which I’m re-defining the addTwoNums() function so that it is a higher-order function:
function addTwoNums(getNumber1, getNumber2) {
console.log(getNumber1() + getNumber2());
}
You can think of the above function declaration of addTwoNums as describing how it will deal with the getNumber1 and getNumber2 inputs: once it receives them as arguments, it will then attempt invoking them and concatenating the values returned from those invocations. For example:
addTwoNums(specificNum, specificNum); // returned number is 84
addTwoNums(specificNum, randomNum); // returned number is 42 + some random number
Pure functions and side-effects
Another concept of functional programming are pure functions.
A pure function returns the exact same result as long as it’s given the same values.
An example of a pure function is the addTwoNums() function from the previous section:
function addTwoNums(a, b) {
console.log(a + b)
}
This function will always return the same output, based on the input. For example, as long as we give it a specific value, say, a 5, and a 6:
addTwoNums(5,6); // 11
… the output will always be the same.
Another rule for a function to be considered pure is that it should not have side-effects. A side-effect is any instance where a function makes a change outside of itself.
This includes:
- changing variable values outside of the function itself, or even relying on outside variables
- calling a Browser API (even the console itself!)
- calling Math.random() – since the value cannot be reliably repeated
The topic of pure and impure functions can get somewhat complex.
For now, it’s sufficient to know that this concept exists and that it is related to functional programming.
Programming Assignment: Building a functional program
README.md
Lab Instructions: Building a Functional Program
In this exercise you’ll get hands-on practice with functional programming concepts.
Note: It is best to follow these instructions in the Preview tab on the right side.
Tips: Before you Begin
To view your code and instructions side-by-side, select the following in your VSCode toolbar:
- View -> Editor Layout -> Two Columns
- To view this file in Preview mode, right click on this README.md file and
Open Preview
- Select your code file in the code tree, which will open it up in a new VSCode tab.
- Drag your assessment code files over to the second column.
- Great work! You can now see instructions and code at the same time.
- Questions about using VSCode? Please see our support resources here:
Visual Studio Code on CourseraTo run your JavaScript code
- Select your JavaScript file
- Select the “Run Code” button in the upper right hand toolbar of VSCode. Ex: It looks like a triangular “Play” button.
Task 1: Build a function-based console log message generator
In this exercise, your task is to code a function named consoleStyler
, which accepts four parameters:
color
background
fontSize
txt
Inside the body of the consoleStyler() function declaration, you need to do the following:
- Create a new variable named message, and assign the following to it on the very first line inside the consoleStyler() function body.:
"%c" + txt;
Tip: Do not copy the 3 back ticks. These are used to format this document in the Preview tab. - Create a style variable and assign the following to it on the next line:
`color: ${color};`
Tip: The single backtick before color and after the semi-colon must be included. - Next, update the style variable (using the += operator) with the following code:
`background: ${background};`
Tip: The single backtick before background and after the semi-colon must be included. - Then, update the style variable (again, using the += operator) with the following code:
`font-size: ${fontSize};`
Tip: The single backtick before font-size and after the semi-colon must be included. - Finally, console log the message and style variables inside the
consoleStyler
function declaration.
Hint: Be sure to use backticks (“) when updating your variable styles and not single (”) or double (“”) quotes.
Task 2: Build another console log message generator.
Your task is to code another function, and name it celebrateStyler()
. The function accepts a single parameter, reason, which should be of string data type.
Inside the function declaration’s body, code the following:
- A new variable, named fontStyle, assigning it this code:
"color: tomato; font-size: 50px";
- On the next line, an if statement, verifying that
reason == "birthday"
. - Inside the body of the if block, code the following:
console.log(`%cHappy birthday`, fontStyle);
- On the next line, add an else if, and inside the parentheses, check that
reason == "champions"
- Inside the else if block, add this code:
console.log(`%cCongrats on the title!`, fontStyle);
- Add an else block, with the following code inside of it:
console.log(message, style);
Task 3: Run both the consoleStyler and the celebrateStyler functions
- Invoke the consoleStyler() function, with the following arguments:
'#1d5c63'
'#ede6db'
'40px'
'Congrats!'
- Next, invoke the celebrateStyler() function, with the following argument:
'birthday'
Task 4: Insert a congratulatory and custom message
- Code another function, named
styleAndCelebrate()
.
The function declaration’s body should consist of two function invocations:consoleStyler(color, background, fontSize, txt); celebrateStyler(reason);
- Next, invoke the new function, using the following arguments:
'ef7c8e'
'fae8e0'
'30px'
'You made it!'
'champions'
Final Step: Let’s submit your code!
Nice work! To complete this assessment:
- Save your file through File -> Save
- Select “Submit Assignment” in your Lab toolbar.
Your code will be autograded and return feedback shortly on the “Grades” tab.
You can also see your score in your Programming Assignment “My Submission” tab.
functionalprogramming.js
// Task 1: Build a function-based console log message generator
function consoleStyler(color, background, fontSize, txt) {
var message = "%c" + txt;
var style = `color: ${color};`
style += `background: ${background};`
style += `font-size: ${fontSize};`
console.log(message, style)
}
// Task 2: Build another console log message generator
function celebrateStyler(reason) {
var fontStyle = "color: tomato; font-size: 50px"
if (reason == "birthday") {
console.log(`%cHappy birthday`, fontStyle)
} else if (reason == "champions") {
console.log(`%cCongrats on the title!`, fontStyle)
} else {
console.log(message, style)
}
}
// Task 3: Run both the consoleStyler and the celebrateStyler functions
consoleStyler('#1d5c63', '#ede6db', '40px', 'Congrats!')
celebrateStyler('birthday')
// Task 4: Insert a congratulatory and custom message
function styleAndCelebrate(color, background, fontSize, txt, reason) {
consoleStyler(color, background, fontSize, txt)
celebrateStyler(reason)
}
// Call styleAndCelebrate
styleAndCelebrate('#1d5c63', '#ede6db', '40px', 'Congrats!', 'champions')
Video: Scoping with var, let and const
Here’s a summary of the video on variable scoping in JavaScript:
Key Concepts:
- Scope: Determines which parts of code can access variables.
- Global Scope: Variables declared outside functions, accessible throughout the program.
- Local Scope: Variables declared within functions, accessible only within those functions (ES5).
- Block Scope: Variables declared within blocks of code (using
let
orconst
), accessible only within those blocks (ES6).
Variable Declaration Keywords:
- var (ES5):
- Lenient scoping rules.
- Can be used before declaration.
- Can be redeclared.
- Function-scoped or global-scoped.
- let (ES6):
- Stricter scoping rules.
- Must be declared before use.
- Cannot be redeclared.
- Block-scoped.
- const (ES6):
- Similar to
let
but creates constants. - Value cannot be changed after assignment.
- Similar to
Best Practices:
- Prefer
let
andconst
overvar
for modern JavaScript development. - Use
let
for values that might change. - Use
const
for values that will never change.
Key Differences:
Feature | var | let | const |
---|---|---|---|
Hoisting | Yes | No | No |
Redeclaration | Yes | No | No |
Scope | Function | Block | Block |
Mutability | Mutable | Mutable | Immutable |
Here’s a tutorial on variable scoping in JavaScript, designed to help you master this crucial concept:
Understanding the Playground of Variables:
Imagine a JavaScript program as a sprawling playground, where variables are the kids running around. Scope is like the rules that govern which kids can play in which areas. It determines where variables are accessible and how they interact with each other.
Types of Scopes:
- Global Scope: The entire playground! Variables declared outside of any function can be accessed from anywhere in the program. Think of them as the playground supervisors, always available.
- Local Scope (Function Scope): Individual play zones within the playground. Variables declared inside a function can only be accessed within that function. They’re like kids playing a specific game, only interacting with others in the same game.
- Block Scope: Temporary play areas marked by curly braces
{}
. Variables declared withlet
orconst
within blocks are only accessible within those blocks. They’re like kids joining a quick game of tag, only interacting within that short-lived activity.
Keywords for Declaring Variables:
- var (ES5): The old-school way, with some quirks. Think of it as the relaxed playground where kids can roam freely, sometimes causing confusion.
- Can be used before declaration (hoisted).
- Can be redeclared.
- Function-scoped or global-scoped.
- let (ES6): The modern choice for most variables. It creates well-defined boundaries, keeping things organized.
- Must be declared before use.
- Cannot be redeclared.
- Block-scoped.
- const (ES6): For variables that need to stay constant, like the playground rules that never change.
- Similar to
let
but creates constants. - Value cannot be changed after assignment.
- Similar to
Best Practices:
- Prefer
let
andconst
overvar
in modern JavaScript. They offer better control and prevent unexpected behavior. - Use
let
for values that might change. It’s flexible when you need to update a variable’s value. - Use
const
for values that will never change. It protects variables from accidental modifications and makes your code more predictable.
Remember:
- Scope determines where variables can play and who they can interact with.
- Choose the right keyword (
var
,let
, orconst
) to establish clear boundaries and avoid playground chaos! - By understanding scope, you’ll write more reliable, maintainable, and bug-free JavaScript code.
You are performing an update to some code and you need to create a variable named quantity, which calculates the total number of items. You need this variable to be accessible only inside a for loop. You declare the variable using the let keyword and it is within a for loop that performs the calculation of the total number of items. Does this variable declaration address your needs?
Yes
Correct. When you use let and const to declare a variable, it is scoped to the block – even within if statements and loops, like the for or while loops. Therefore, the quantity variable you create will only exist within the for loop.
You might recall that scope relates to code accessibility. It determines which
part of the code are accessible by different
parts of the program. In this video you will explore
scoping in more detail, and learn about two more
scope types and how they work with the keywords
var, let, and const. You may recall that all
the code outside of functions is referred
to as global scope, and all the code inside of a function is known
as local scope. Local scope states that
a variable is only accessible in the function
where it is declared. In the ES5 version
of JavaScript, only functions can
build local scope. The ES6 version of
JavaScript introduced a new variety of scope
known as the block scope. Block scope states that a
variable declared in a block of code is only accessible
inside that block. All the other code outside of the code block cannot access it. Block scope is built
when you declare variables using let or const. In other words when you build variables with let or const, they become
immediately scoped to the code block they
were created in. The scope of these variables is contained within
curly braces. For example, you can declare two separate variables
with the same name. If one is declared inside curly braces and
the other is not, you can then only access these variables
inside their scope. Before ES6, the
only way to declare a variable in JavaScript
was to use the var keyword. The var keyword is very lenient. Let’s outline some
characteristics of variables that are
declared with var. First, you can use it in your code even before
it is declared. Also, you can redeclare the same variable
when you use VAR. The variables are scoped
to a function R if they are declared outside the function their
scope is global. With ES6, the suggested
way to declare variables is to use the
let or const keywords. Its syntax is very similar
to the var syntax. Only the keyword is replaced. For example, let’s say
you want to declare a variable named user and assign it to a string set to
the value of Miranda. In ES5, you use the keyword var, the variable user,
the equal operator, and then the string value
Miranda inside double quotes. In ES6 with let and const, you use the same syntax, only changing the var keyword
to either let or const. Notice that the syntax
is very similar. You might be wondering what’s
the difference between var, let, and const. The simplest explanation is that the behavior of let and
const is more strict. With a let or a const variable, you cannot use it in your
code before you declare it. You can redeclare it using the variable keyword
like you can with var. Finally, it’s scoped
to the block, even within if
statements and loops, like the far or while loops. If you are new to JavaScript, it may be confusing as to
when to use either var, let, or const. A pro tip is to remember
it’s like this. Use let if the value might
change in the future, and use const if the
value will never change. In this video, you learned
how the scope of variables changes when you use the
keyword var in ES5 JavaScript, and when you use the
keywords let and const in ES6 JavaScript. Great job.
Video: Comparing var, let and const
Here’s a summary of the video on variable declaration keywords in JavaScript:
Key Points:
- var (most lenient):
- Can be accessed before initialization.
- Can be redeclared.
- Function-scoped or global-scoped.
- let (more strict):
- Cannot be accessed before declaration.
- Cannot be redeclared.
- Block-scoped.
- Can be reassigned.
- const (strictest):
- Must be initialized on declaration.
- Cannot be redeclared.
- Cannot be reassigned.
- Block-scoped.
Best Practices:
- Prefer
let
andconst
overvar
in modern JavaScript. - Use
const
by default for variables that won’t change. - Use
let
for variables that need to be reassigned.
Additional Notes:
var
variables can be accessed before their declaration due to a process called “hoisting.”let
andconst
variables are not hoisted.const
variables must be initialized with a value during declaration.
Choosing the Right Keyword:
- Use
const
for values that should remain constant throughout the code. - Use
let
for values that may need to be updated later. - Avoid using
var
in modern JavaScript due to its potential for unexpected behavior.
Here’s a tutorial on variable declaration keywords in JavaScript, designed to help you master how to create and manage variables effectively:
Mastering the Art of Variable Creation:
In JavaScript, variables are like containers for storing data. But before you start filling them, you need to know how to create them properly. That’s where variable declaration keywords come in!
Keywords: Your Tools for Variable Crafting:
JavaScript offers three keywords for declaring variables: var
, let
, and const
. Each has its own rules and best practices:
1. var (The Old-School, Lenient One):
- Accessibility: Can be accessed before declaration (hoisted).
- Scope: Function-scoped or global-scoped.
- Redeclaration: Can be redeclared within the same scope.
- Reassignment: Can be reassigned new values.
- Modern Use: Generally avoided in modern JavaScript due to potential for unexpected behavior.
2. let (The Modern, Controlled One):
- Accessibility: Cannot be accessed before declaration.
- Scope: Block-scoped (accessible only within their enclosing curly braces).
- Redeclaration: Cannot be redeclared within the same scope.
- Reassignment: Can be reassigned new values.
- Best Use: Used for variables that may need to be reassigned later.
3. const (The Constant Guardian):
- Accessibility: Cannot be accessed before declaration.
- Scope: Block-scoped.
- Redeclaration: Cannot be redeclared within the same scope.
- Reassignment: Cannot be reassigned after declaration.
- Best Use: Used for values that should remain constant throughout the code.
Choosing Wisely:
- Prefer
const
by default: It prevents accidental changes and makes code more predictable. - Use
let
for variables that need to be reassigned: This ensures proper scoping and avoids potential issues. - Avoid
var
in modern JavaScript: Its lenient behavior can lead to confusion and bugs.
Remember:
- Choose the right keyword based on whether the variable’s value will change or not.
- Understanding these keywords is crucial for writing clean, maintainable, and error-free JavaScript code!
Which one of the following statements is true when declaring variables using either var, let or const?
Variables declared with const must be assigned during declaration.
In this video, you’ll learn about the var,
let, and const variables and the different rules
that they are bound to. Let’s start with the var keyword. I’ve typed some example code that
is currently commented out but we’ll go through it one point at a time. A variable declared with the var keyword
can be accessed before initialization as long as the variable is eventually
initialized somewhere in our code. To confirm that, let’s try to console log
a variable that hasn’t been declared or initialized. I type console.log(user) and
click the Run button. This returns reference error. User is not defined which
is probably expected. However, suppose I use the var
keyword to declare the variable user as my last line of code and
rerun the code. Notice that undefined is output but
no error. This means that the JavaScript
engine continues to run. Let me clear my window here. And another thing to know about the var
keyword is that we can declare and redeclare the same var
variable without errors. Let me in comment lines 9-13
in my code to demonstrate. Notice that each line uses the var keyword
to repeatedly declare the user variable and assigns it to a different string
value Mary, Joanna, and finally, Mark. I’ll comment out line 15. When I run my code,
it outputs the first value undefined and then the value of the latest reassignment,
in this case the string Mark. Let’s move on to the let keyword. A key difference is that you cannot access
a let variable before declaring it. For example, in lines 4 and 5 suppose I run a console log on
the user variable as our first line. In that case, I get the reference error
cannot access user before initialization. What we can do however, is declare
an unassigned variable with let. Running a console log by uncommenting
lines 8 and 9 works without problems and returns undefined. However, once you declare a variable
threat, you cannot redeclare it. Trying to do so by uncommenting line
12 will produce the syntax error, identifier user has already been declared. While you cannot redeclare a let variable,
you can reassign it. For example, notice lines 8 and 15, initially it is set to undefined and
then to the string value of Anna. Now if I run my code, notice that undefined is output
first followed by the string Anna. Finally, let me switch
tabs again to demonstrate the const keyword which is the strictest. A const variable must be initialized. For example, on lines 4 and 5, you get the syntax error missing
initializer in const declaration. Next, let’s comment out lines 4 and
5 and uncomment lines 8 and 9. As you can see, you can access a const
variable before initialization or else you’ll get a reference here. Next uncommon line 9 as well as line 12. A const variable can’t be re declared as
it throws the type error assignment to constant variable. Okay, and that’s it for this video comparing variable
declaration using var, let and const. It might seem confusing at the beginning
to know which type to choose. Try to remember it like this. The Var keyword is the most lenient,
while the Const keyword is the strictest. The best choice and use,
usually depends on whether or not you will be reassigning values. In modern JavaScript,
I’d advise you to pick either let or const based on whether they
will be reassigned or not. Why not give it a try in
your own practice code?
Practice Quiz: Knowledge check: Introduction to Functional Programming
What will print out when the following code runs?
var globalVar = 77;
function scopeTest() {
var localVar = 88;
}
console.log(localVar);
undefined
That’s correct! localVar is scoped to the function so therefore it is undefined in the global scope.
Variables declared using const can be reassigned.
false
That’s correct! Variables declared using const cannot be redeclared or reassigned.
When a function calls itself, this is known as _____________.
Recursion
That’s correct! Recursion is when a function calls itself.
What will print out when the following code runs?
function meal(animal) {
animal.food = animal.food + 10;
}
var dog = {
food: 10
};
meal(dog);
meal(dog);
console.log(dog.food);
30
That’s correct! The food value starts at 10. The meal function is called twice which adds 10 to the food value each time. Therefore, 30 is printed.
What value will print out when the following code runs?
function two() {
return 2;
}
function one() {
return 1;
}
function calculate(initialValue, incrementValue) {
return initialValue() + incrementValue() + incrementValue();
}
console.log(calculate(two, one));
4
That’s correct! The two function is passed as the first parameter to the calculate function and the one function is passed as the second parameter. Therefore, when the calculate function runs, it will call two() + one() + one() . The result is then 4 .
Reading: Additional resources
Reading
Here is a list of resources that may be helpful as you continue your learning journey.
Introduction to Object-Oriented Programming
Video: Introduction to object-oriented programming
Summary of Object-Oriented Programming (OOP) vs. Functional Programming:
Key Points:
- Paradigms: OOP organizes programs using objects; Functional separates data and functions.
- Example: Calculating shoe cost
- Functional: Define variables, write function, call function with variables.
- OOP: Create objects holding data and functions, access functions with dot notation.
- Benefits of OOP:
- Create multiple objects with similar functionality.
- Reuse code with
this
keyword to avoid duplicate methods. - Use classes for efficient template-based object creation.
Overall Message:
OOP offers an efficient way to structure programs by grouping related data and functions in objects, allowing code reuse and efficient object creation through classes.
Additional Notes:
- The video compares OOP and functional programming using the example of calculating shoe cost.
- It highlights using the
this
keyword to avoid code duplication and introduces the concept of classes for efficient object creation.
I hope this summary is helpful! Let me know if you have any other questions.
Here’s a tutorial on Object-Oriented Programming (OOP) vs. Functional Programming, incorporating visuals:
Introduction:
- Programming Paradigms: Different ways of organizing code to solve problems.
- OOP and Functional Programming: Two popular paradigms with distinct approaches.
OOP (Object-Oriented Programming):
- Key Concepts:
- Objects: Encapsulate data (properties) and behavior (methods) into reusable units.
- Classes: Blueprints for creating objects with similar characteristics.
- Inheritance: Objects can inherit properties and methods from parent classes.
- Polymorphism: Objects of different classes can respond to the same method call in different ways.
- Example:
Functional Programming:
- Key Concepts:
- Functions: First-class citizens, treated like any other data value.
- Pure Functions: Given the same input, always produce the same output (no side effects).
- Immutability: Data cannot be changed after creation, new values are produced instead.
- Recursion: Functions calling themselves to solve problems.
- Example:
Comparison Table:
Feature | OOP | Functional Programming |
---|---|---|
Focus | Objects and their interactions | Functions and their composition |
State | Objects can hold and modify state | Data is immutable, new values are created |
Code Structure | Organized around objects and classes | Organized around functions and data flow |
Reuse | Through inheritance and polymorphism | Through higher-order functions and closures |
Best Suited For | Modeling real-world entities and complex systems | Data processing, parallel programming, algorithms |
When to Choose Which:
- OOP: Well-suited for modeling real-world entities, GUI applications, and systems with complex interactions.
- Functional Programming: Excels in data processing, parallel programming, and algorithms where correctness and predictability are crucial.
Conclusion:
- Both OOP and Functional Programming offer powerful approaches to problem-solving.
- Understanding their strengths and weaknesses is essential for choosing the right paradigm for your project.
- Modern languages often support both paradigms, allowing developers to combine their best features.
You are coding in OOP style. Why would you want to use the "this" keyword?
To refer to the object itself without specifying the object’s name.
Correct. The “this” keyword is an alias for the name of the object.
In programming, there is something
known as the programming paradigms. You can think of this as a classification,
a style or just a general way to write code. You may already be familiar
with one of these paradigms. Functional programming, in this video,
you will learn about another popular one. The object oriented programming paradigm,
often referred to as OOP. OOP revolves around the idea of
organizing our programs using objects to group related data and functionality. This is in contrast to the functional
programming approach, where the data used in the app needs to be kept separate from
functions that operate on that data. Let’s explore this concept further using
some code examples from the two paradigms, suppose we are asked to write some
code that calculates the total cost of buying a pair of shoes. The code needs to calculate the total
price which is the shoes multiplied by the tax amount. To code this solution, you decide that you
need variables to store the values for shoes and tax and total price. You need a function which you
will call total price to perform the calculation of multiplying
the shoes by the tax. Finally, you need to be
able to output the result. Using the functional programming approach, you clearly separate a program’s data
from functions that work on that data. With the OOP approach, you create
an object and store all data related to that object including variables,
functions and output statements. For example,
you create an object named purchase one. You may recall that functions inside
objects are known as methods. Now that the purchase 1 object is created. You access the total price method on the
purchase1 object using the dot notation. Then, you invoke the total price
method which works with data inside the purchase 1 object and
returns the result of 120. In fact, you can access any data
that the purchase 1 object has. For example, using the dot notation, you can access the shoes price data and
the state tax data. An advantage to using the OoP approach
is that you can build as many objects as you need. For example, you can build another
purchase object and name it purchase2. Once created, you can also access
the total price method on the purchase2 object just like you did on
the purchase 1 object previously. You may notice, that the total price
method was almost the same in both the purchase 1 and the purchase 2 objects. This means that you can
improve the objects so that both methods are identical. And you can do that by using this
keyword which you may recall. It essentially means this object. It’s important to note that the code
still works exactly the same as before. Okay, so you may be wondering why did
I go through the trouble of updating the code of purchase 1 dot choose
price to this dot choose price. Well, the advantage here is that
rather than having to think about the name of the object whose shoes
priced property I’m trying to access, I just used the alias of the current
objects name, namely, this keyword. And now I can just copy the total price
method from the purchase 1 object and reuse it in the purchase 2 object. So, using that this keyword allows me
to not really care about the current objects name, which is an improvement
to the previous code I had. However, programmers are always eager to
avoid wasting resources when writing code. And coding a custom method on each
of the objects I built is wasteful. The solution to this is to code my
objects using some sort of a template. You will learn how to create this later
in this lesson using something called a class. For now, let’s explore object
oriented programming principles with the example of calculating the total
cost of buying a pair of shoes. Before starting, let’s first quickly
revisit another programming style. Functional programming, this should help you understand
the differences between the two paradigms. I start with var shoes equals 100 and I also add var state tax equals 1.2. Next, I declare a function, which returns the value of the shoes
multiplied by the value of the tax. This is written as function total price,
with shoes and tax in parenthesis. Inside of curly braces,
I add return shoes, asterix tax. Now, I’m declaring the variable to pay
which invokes the total price function and passes the shoes variable value as
well as the state tax variable value. Finally, I cancel log the to pay variable. When I run the code, the output is 120. So that’s an example of
the functional paradigm. But this time let’s build something
similar with the OOP paradigm. I go to a separate file where I
declare the variable, purchase 1 and store an object literal inside
of it with curly braces. I didn’t add the property shoes and
set it to 100, followed by state tax,
which is set to 1.2. The last property is total price, which is set to a function to
declare a calculation variable. This variable is equal to
the purchase1 dot shoes property multiplied by the purchase
1 dot state tax property. The 2nd part of the function
console logs the string total price along with the value
of the calculation variable. Online 10, I call the function with
purchase 1 dot total price parenthesis. Which I expect to return a value of 120. I run the code and
that’s indeed what I get. On another file, I’ll build another
OOP example, this one starts with the variable purchase 2, which has
the same structure as purchase 1. However, that shoes
value is changed to 50. In the total price function,
the calculation variable is updated to access the shoes and
state tax properties from purchase 2. When I invoked the total price
method on the purchase 2 object and run the code, It returns a value of 60. Between these two OOP examples,
you may have noticed that aside from accessing the shoes and state tax
properties in different objects,. The two methods are completely the same. This means that I can improve my objects
to make both methods identical while getting the same results. I can do this using the this keyword
which essentially means this object. Let’s move to another file,
to examine how that works. In this file,
I had the same purchase 1 and purchased 2 objects from before
with all of the same values. in the total price function of purchase 1, I replaced the references to
purchase 1 with the this keyword. I can then copy the total price
method from purchase1 and paste it into the purchase 2 object,
since they are now identical. I run this code and
it gives me a total price of 120 for purchase 1 and 60 for purchase 2. This is an improvement, over my original code from
the perspective of reducing waste. Instead of writing custom methods for
every object, this approach allows for
the reuse of existing code. However, although I’m
reusing the existing code, I’m now repeating the same method
on each new object that is built. That is wasteful and
programs need to be efficient. This is where making templates for
objects comes in. In JavaScript,
one of the most elegant ways to efficiently build new
objects is by using classes. Congratulations. In this video, you learned about
object orientated programming and how it differs from
functional programming. With the object orientated approach, you can code more efficiently
by reusing existing code.
Video: Classes
Here’s a summary of the video about classes in JavaScript:
Key Points:
- Classes as Blueprints: Classes serve as reusable blueprints for creating objects with defined properties and methods.
- Creating Classes:
- Use the
class
keyword followed by the class name (capitalized). - Enclose the class definition in curly braces.
- Use the
- Constructor Function:
- Used to initialize objects when they’re created.
- Accepts parameters to set object properties.
- Methods:
- Functions defined within the class to perform actions on objects.
- Called using dot notation on objects (e.g.,
objectName.methodName()
). - Can accept parameters like regular functions.
- Creating Objects (Instances):
- Use the
new
keyword followed by the class name and parentheses to create objects.
- Use the
- Accessing Properties and Methods:
- Use dot notation to access properties and methods of objects.
Example:
- Car Class: Blueprint for creating car objects with properties like make, model, and color, and methods like
turboOn()
. - Creating a Car Object:
let car1 = new Car("Toyota", "Camry", "red");
- Calling a Method:
car1.turboOn();
Benefits of Classes:
- Efficient Object Creation: Reusable blueprints for multiple objects with similar characteristics.
- Code Organization: Enhances code structure and maintainability.
Here’s a tutorial on classes in JavaScript, incorporating visual aids:
Understanding Classes:
- Blueprints for Objects: Think of classes as templates or blueprints that define the properties (data) and methods (behavior) of objects.
- Creating Multiple Objects: You can use a single class to create multiple objects, each with its own unique values for the properties.
Creating a Class:
Syntax:
class ClassName {
// Constructor function
constructor(parameters) {
// Initialize properties here
}
// Methods
methodName() {
// Perform actions here
}
}
Example: Car
Class:
class Car {
constructor(make, model, color) {
this.make = make;
this.model = model;
this.color = color;
this.currentSpeed = 0;
}
accelerate(speed) {
this.currentSpeed += speed;
console.log(`Accelerating to ${this.currentSpeed} mph!`);
}
brake() {
this.currentSpeed = 0;
console.log("Stopped!");
}
}
Creating Objects (Instances):
Use the new
keyword:
let car1 = new Car("Toyota", "Camry", "red");
Each object is an instance of the class:
Accessing Properties and Methods:
Dot notation:
console.log(car1.make); // Output: Toyota
car1.accelerate(30);
Benefits of Classes:
- Code Organization: Structures code logically and improves readability.
- Reusability: Creates multiple objects with similar characteristics efficiently.
- Maintainability: Easier to modify and update code within classes.
Additional Concepts:
- Inheritance: Classes can inherit properties and methods from other classes.
- Static Methods: Methods that belong to the class itself, not individual objects.
- Getters and Setters: Control access to properties.
Practice:
- Experiment with creating your own classes and objects to solidify your understanding.
- Explore advanced concepts like inheritance and static methods to expand your knowledge.
You are working with classes in JavaScript. Which of the following instructions should you adhere to? Check all that apply.
Add a constructor function to accept your parameters.
That’s right. The constructor function assigns passed-in parameters to the future object’s properties.
Build your classes using the “class” keyword.
That’s right. Any class is built using the “class” keyword.
Create an instance of the class using the keyword new and that class’ name, followed by opening and closing parentheses, and optional arguments, based on how the class itself is defined.
That’s right. For example, if a class named Car doesn’t take any arguments, you’d instantiate it like this: new Car()
In programming there are situations where
you need to build many objects that have a certain specific set
of properties and methods. For example, you might need to
build hundreds of car objects for a car racing game. To code this efficiently,
you can use something called classes. They are essentially a blueprint that you
can repeatedly use to build new objects of a certain kind, as many times as you like. In this video,
you will learn about classes. In java script any class is built using
the class keyword, followed by the name of the class starting with a capital
letter and a pair of curly braces. Inside of the curly braces you have
the constructor function which accepts as many parameters as needed. The role of the constructor function
is to assign the passed in parameters to the future objects properties. It is the constructor function that is
used when instantiating new objects, instances of a given class. After the constructor is defined,
you add as many methods as you want. It’s important to remember that you
don’t use the function keyword here. Just the name of the method is needed. Once the class definition is ready,
you can start building the car object, now that you have instantiation
the car class and saved the instant of the class as car one. You have access to its methods and
properties. For example,
to access the turbo on method, you type the name of the object
which is car one, then the dot and then the name of the method
that exists on that object. In this example, the turbo on method,
with a pair of parenthesis to invoke it. When invoked, the turbo on method
will work with the available data in the car one object to produce its output. Like with regular functions, you can also
pass parameters to the class methods and then use them the same as
with regular functions. In this video,
you learned about classes and how they can be used to build multiple
object instances with specific properties.
Reading: Object Oriented Programming principles
Reading
In this reading, you’ll learn about the benefits of object-oriented programming (OOP) and the OOP principles.
The Benefits of OOP
There are many benefits to using the object-oriented programming (OOP) paradigm.
OOP helps developers to mimic the relationship between objects in the real world. In a way, it helps you to reason about relationships between things in your software, just like you would in the real world. Thus, OOP is an effective approach to come up with solutions in the code you write. OOP also:
- Allows you to write modular code,
- Makes your code more flexible and
- Makes your code reusable.
The Principles of OOP
The four fundamental OOP principles are inheritance, encapsulation, abstraction and polymorphism. You’ll learn about each of these principles in turn. The thing to remember about Objects is that they exist in a hierarchal structure. Meaning that the original base or super class for everything is the Object class, all objects derive from this class. This allows us to utilize the Object.create() method. to create or instansiate objects of our classes.
class Animal { /* ...class code here... */ }
var myDog = Object.create(Animal)
console.log (Animal)
[class Animal]
A more common method of creating obbjects from classes is to use the new keyword. When using a default or empty constructor method, JavaScript implicitly calls the Object superclass to create the instance.
class Animal { /* ...class code here... */ }
var myDog = new Animal()
console.log (Animal)
[class Animal]
This concept is explored within the next section on inheritance
OOP Principles: Inheritance
Inheritance is one of the foundations of object-oriented programming.
In essence, it’s a very simple concept. It works like this:
- There is a base class of a “thing”.
- There is one or more sub-classes of “things” that inherit the properties of the base class (sometimes also referred to as the “super-class”)
- There might be some other sub-sub-classes of “things” that inherit from those classes in point 2.
Note that each sub-class inherits from its super-class. In turn, a sub-class might also be a super-class, if there are classes inheriting from that sub-class.
All of this might sound a bit “computer-sciency”, so here’s a more practical example:
- There is a base class of “Animal”.
- There is another class, a sub-class inheriting from “Animal”, and the name of this class is “Bird”.
- Next, there is another class, inheriting from “Bird”, and this class is “Eagle”.
Thus, in the above example, I’m modelling objects from the real world by constructing relationships between Animal, Bird, and Eagle. Each of them are separate classes, meaning, each of them are separate blueprints for specific object instances that can be constructed as needed.
To setup the inheritance relation between classes in JavaScript, I can use the extends keyword, as in class B extends A.
Here’s an example of an inheritance hierarchy in JavaScript:
class Animal { /* ...class code here... */ }
class Bird extends Animal { /* ...class code here... */ }
class Eagle extends Bird { /* ...class code here... */ }
OOP Principles: Encapsulation
In the simplest terms, encapsulation has to do with making a code implementation “hidden” from other users, in the sense that they don’t have to know how my code works in order to “consume” the code.
For example, when I run the following code:
"abc".toUpperCase();
I don’t really need to worry or even waste time thinking about how the toUpperCase() method works. All I want is to use it, since I know it’s available to me. Even if the underlying syntax – that is, the implementation of the toUpperCase() method changes – as long as it doesn’t break my code, I don’t have to worry about what it does in the background, or even how it does it.
OOP Principles: Abstraction
Abstraction is all about writing code in a way that will make it more generalized.
The concepts of encapsulation and abstraction are often misunderstood because their differences can feel blurry.
It helps to think of it in the following terms:
- An abstraction is about extracting the concept of what you’re trying to do, rather than dealing with a specific manifestation of that concept.
- Encapsulation is about you not having access to, or not being concerned with, how some implementation works internally.
While both the encapsulation and abstraction are important concepts in OOP, it requires more experience with programming in general to really delve into this topic.
For now, it’s enough to be aware of their existence in OOP.
OOP Principles: Polymorphism
Polymorphism is a word derived from the Greek language meaning “multiple forms”. An alternative translation might be: “something that can take on many shapes”.
So, to understand what polymorphism is about, let’s consider some real-life objects.
- A door has a bell. It could be said that the bell is a property of the door object. This bell can be rung. When would someone ring a bell on the door? Obviously, to get someone to show up at the door.
- Now consider a bell on a bicycle. A bicycle has a bell. It could be said that the bell is a property of the bicycle object. This bell could also be rung. However, the reason, the intention, and the result of somebody ringing the bell on a bicycle is not the same as ringing the bell on a door.
The above concepts can be coded in JavaScript as follows:
const bicycle = {
bell: function() {
return "Ring, ring! Watch out, please!"
}
}
const door = {
bell: function() {
return "Ring, ring! Come here, please!"
}
}
So, I can access the bell() method on the bicycle object, using the following syntax:
bicycle.bell(); // "Get away, please"
I can also access the bell() method on the door object, using this syntax:
door.bell(); // "Come here, please"
At this point, one can conclude that the exact same name of the method can have the exact opposite intent, based on what object it is used for.
Now, to make this code truly polymorphic, I will add another function declaration:
function ringTheBell(thing) {
console.log(thing.bell())
}
Now I have declared a ringTheBell() function. It accepts a thing parameter – which I expect to be an object, namely, either the bicycle object or the door object.
So now, if I call the ringTheBell() function and pass it the bicycle as its single argument, here’s the output:
ringTheBell(bicycle); // Ring, ring! Watch out, please!
However, if I invoke the ringTheBell() function and pass it the door object, I’ll get the following output:
ringTheBell(door); // "Ring, ring! Come here, please!"
You’ve now seen an example of the exact same function producing different results, based on the context in which it is used.
Here’s another example,the concatenation operator, used by calling the built-in concat() method.
If I use the concat() method on two strings, it behaves exactly the same as if I used the + operator.
"abc".concat("def"); // 'abcdef'
I can also use the concat() method on two arrays. Here’s the result:
["abc"].concat(["def"]); // ['abc', 'def']
Consider using the + operator on two arrays with one member each:
["abc"] + ["def"]; // ["abcdef"]
This means that the concat() method is exhibiting polymorphic behavior since it behaves differently based on the context – in this case, based on what data types I give it.
To reiterate, polymorphism is useful because it allows developers to build objects that can have the exact same functionality, namely, functions with the exact same name, which behave exactly the same. However, at the same time, you can override some parts of the shared functionality or even the complete functionality, in some other parts of the OOP structure.
Here’s an example of polymorphism using classes in JavaScript:
class Bird {
useWings() {
console.log("Flying!")
}
}
class Eagle extends Bird {
useWings() {
super.useWings()
console.log("Barely flapping!")
}
}
class Penguin extends Bird {
useWings() {
console.log("Diving!")
}
}
var baldEagle = new Eagle();
var kingPenguin = new Penguin();
baldEagle.useWings(); // "Flying! Barely flapping!"
kingPenguin.useWings(); // "Diving!"
The Penguin and Eagle sub-classes both inherit from the Bird super-class. The Eagle sub-class inherits the useWings() method from the Bird class, but extends it with an additional console log. The Penguin sub-class doesn’t inherit the useWings() class – instead, it has its own implementation, although the Penguin class itself does extend the Bird class.
Do some practice with the above code, trycreating some of your own classes. (hint : think about things you know from everyday life)
Reading: Constructors
Reading
JavaScript has a number of built-in object types, such as:
Math, Date, Object, Function, Boolean, Symbol, Array, Map, Set, Promise, JSON, etc.
These objects are sometimes referred to as “native objects”.
Constructor functions, commonly referred to as just “constructors”, are special functions that allow us to build instances of these built-in native objects. All the constructors are capitalized.
To use a constructor function, I must prepend it with the operator new.
For example, to create a new instance of the Date object, I can run: new Date(). What I get back is the current datetime, such as:
Thu Feb 03 2022 11:24:08 GMT+0100 (Central European Standard Time)
However, not all the built-in objects come with a constructor function. An example of such an object type is the built-in Math object.
Running new Math() throws an Uncaught TypeError, informing us that Math is not a constructor.
Thus, I can conclude that some built-in objects do have constructors, when they serve a particular purpose: to allow us to instantiate a specific instance of a given object’s constructor. The built-in Date object is perfectly suited for having a constructor because each new date object instance I build should have unique data by definition, since it’s going to be a different timestamp – it’s going to be built at a different moment in time.
Other built-in objects that don’t have constructors, such as the Math object, don’t need a constructor. They’re just static objects whose properties and methods can be accessed directly, from the built-in object itself. In other words, there is no point in building an instance of the built-in Math object to be able to use its functionality.
For example, if I want to use the pow method of the Math object to calculate exponential values, there’s no need to build an instance of the Math object to do so. For example, to get the number 2 to the power of 5, I’d run:
Math.pow(2,5); // –> 32
There’s no need to build an instance of the Math object since there would be nothing that needs to be stored in that specific object’s instance.
Besides constructor functions for the built-in objects, I can also define custom constructor functions.
Here’s an example:
function Icecream(flavor) {
this.flavor = flavor;
this.meltIt = function() {
console.log(`The ${this.flavor} icecream has melted`);
}
}
Now I can make as many icecreams as I want:
function Icecream(flavor) {
this.flavor = flavor;
this.meltIt = function() {
console.log(`The ${this.flavor} icecream has melted`);
}
}
let kiwiIcecream = new Icecream("kiwi");
let appleIcecream = new Icecream("apple");
kiwiIcecream; // --> Icecream {flavor: 'kiwi', meltIt: ƒ}
appleIcecream; // --> Icecream {flavor: 'apple', meltIt: ƒ}
I’ve just built two instance objects of Icecream type.
The most common use case of new is to use it with one of the built-in object types.
Note that using constructor functions on all built-in objects is sometimes not the best approach.
This is especially true for object constructors of primitive types, namely: String, Number, and Boolean.
For example, using the built-in String constructor, I can build new strings:
let apple = new String("apple");
apple; // --> String {'apple'}
The apple variable is an object of type String.
Let’s see how the apple object differs from the following pear variable:
let pear = "pear";
pear; // --> "pear"
The pear variable is a string literal, that is, a primitive Javascript value.
The pear variable, being a primitive value, will always be more performant than the apple variable, which is an object.
Besides being more performant, due to the fact that each object in JavaScript is unique, you can’t compare a String object with another String object, even when their values are identical.
In other words, if you compare new String(‘plum’) === new String(‘plum’), you’ll get back false, while “plum” === “plum” returns true. You’re getting the false when comparing objects because it is not the values that you pass to the constructor that are being compared, but rather the memory location where objects are saved.
Besides not using constructors to build object versions of primitives, you are better off not using constructors when constructing plain, regular objects.
Instead of new Object, you should stick to the object literal syntax: {}.
A RegExp object is another built-in object in JavaScript. It’s used to pattern-match strings using what’s known as “Regular Expressions”. Regular Expressions exist in many languages, not just JavaScript.
In JavaScript, you can built an instance of the RegExp constructor using new RegExp.
Alternatively, you can use a pattern literal instead of RegExp. Here’s an example of using /d/ as a pattern literal, passed-in as an argument to the match method on a string.
"abcd".match(/d/); // ['d', index: 3, input: 'abcd', groups: undefined]
"abcd".match(/a/); // ['a', index: 0, input: 'abcd', groups: undefined]
Instead of using Array, Function, and RegExp constructors, you should use their array literal, function literal, and pattern literal varieties: [], () {}, and /()/.
However, when building objects of other built-in types, we can use the constructor.
Here are a few examples:
new Date();
new Error();
new Map();
new Promise();
new Set();
new WeakSet();
new WeakMap();
The above list is inconclusive, but it’s just there to give you an idea of some constructor functions you can surely use.
Note that there are links provided about RegExp and regular expression in the lesson item titled “Additional Reading”.
Video: Inheritance
JavaScript Inheritance: Prototypes and Class Syntax
This video delves into inheritance in JavaScript, focusing on the prototype-based model.
Key Takeaways:
- Prototype: An object holding properties shared by other objects. These “children” inherit the prototype’s properties.
- Inheritance Model: JavaScript uses prototypes for inheritance, not classical “class” inheritance.
- Object.create(): Creates a new object with a specified prototype.
- Property Lookup: JavaScript searches for properties first on the object itself, then on its prototype, and so on.
- Overriding Properties: Children can define their own properties to override those inherited from the prototype. This affects only the child object, not the prototype or other children.
- Class Syntax: A newer addition to JavaScript, offering a more familiar class-based syntax for inheritance, but still working with prototypes behind the scenes.
Examples:
bird
object as prototype with propertieshasWings
,canFly
,hasFeathers
.eagle1
andeagle2
objects created withObject.create(bird)
, inherit bird’s properties.penguin1
created withObject.create(bird)
, butcanFly
set tofalse
on penguin1 itself, overriding the prototype.
Conclusion:
Understanding prototype-based inheritance is crucial for JavaScript developers. While older methods involve Object.create()
, newer class syntax provides a more familiar and streamlined approach, but still relies on the underlying prototype mechanism.
Welcome to the JavaScript Inheritance Workshop! ️
Here’s your guide to unlocking the secrets of JavaScript’s unique approach to object-oriented programming.
Unveiling Prototypes:
- The Prototype Playground: Imagine a shared blueprint for objects, where common properties and behaviors reside. That’s a prototype! ️
- The Inheritance Chain: Objects inherit from prototypes, forming a family tree of sorts.
- Object.create(): The Prototype-Making Factory: Use this method to create new objects with a specific prototype, ensuring they inherit its traits.
Property Lookup: Following the Family Tree:
- From Self to Ancestors: When JavaScript needs a property, it searches the object itself. If it’s not found, it looks up the prototype chain, like exploring a family history book.
Overriding Inherited Properties:
- Redefining Traits: Child objects can have their own unique properties, even if they share a prototype. This is like a child inheriting blue eyes from parents but having a different hair color.
- Local Overrides: These properties take precedence over inherited ones, just as a child’s unique personality might shine through family resemblance. ✨
Classes: The Familiar Face of Inheritance:
- Class Syntax: A Modern Approach: JavaScript offers a class-based syntax that makes inheritance feel more like traditional OOP languages, but prototypes still work behind the scenes.
- Under the Hood: Classes are essentially a syntactic sugar for prototype-based inheritance, making it easier to structure and organize code.
Key Points to Remember:
- Prototypes are the heart of JavaScript’s inheritance model.
- Understanding property lookup is essential for working with prototypes.
- Classes provide a cleaner syntax but still rely on prototypes.
Now it’s time to practice and explore!
True or false? In JavaScript, you can use a prototype object to hold properties that can be shared with various other objects.
True
Correct! The prototype is an object that can have properties to be shared by multiple other objects.
In the real world, inheriting
something means acquiring possession, condition our trade from past generations. In this video you will learn that
inheritance also exists in JavaScript and the inheritance model revolves around
something called the prototype. You may also be familiar with the concept
of a prototype which is often referred to as an original model from
which other forms are developed. In JavaScript, the prototype is
an object that can hold properties to be shared by multiple other objects. And this is the basis of how
inheritance works in JavaScript. This is why it’s sometimes said that
JavaScript implements a prototype of inheritance model. Let’s explore this further now, with some code examples to demonstrate
inheritance and how to build a prototype. Consider the following object. I’m setting the var bird to
an object that has three properties. Each set to the boolean value of true. The properties are has wings can fly and
has feathers. Using the readily available object create,
I can construct new objects. For example, I’ve set the eagle1 variable
to a call that takes the bird object and passes it to the object .create method. I can console log the contents
of the eagle1 object now. Let’s run the code and notice an empty
object logged to the console. However, since I used object to create
to instantiate the eagle1 object. I also have access to all
the properties of the bird object. So I canceled log eagle1 has wings and
pass eagle1.has wings. And I also console log eagle1 can fly and
pass eagle1.can fly. And finally eagle1 has feathers
passing it eagle1.has feathers. Let’s read from the code once again
notice eagle1 has wings true, eagle1 can fly true and
eagle1 has feathers true. Our output to the console with
the object creates syntax. I can build as many objects as I want and they will all have the bird
objects as their prototype. Here, notice that I built
an eagle2 object and I’ve used the bird object as a prototype. Because I ran the object
.create method on it and I save everything to the eagle2 variable. It’s important to understand
that the eagle2 object also has access to the property stored
on the bird object as its prototype. Let’s run this code to confirm and indeed notice that eagle2 has wings
true is output to the console. I can even add different objects
with different behaviors. For example, I can add a penguin1 object. I do this by declaring
a penguin1 variable and assigning the result of
the object .create method to it. Penguins are flightless birds so I want
to set the can fly property to false. Thankfully, this is a relatively
straightforward process because JavaScript starts from the object itself when
looking for properties to work with. Then if it can’t find it on the object,
it looks up to its prototype. It’s important to remember that it doesn’t
look further if it finds the property on the immediate object. This makes for a simple mechanism for
overriding inherited properties. So let’s implement this now. First I set that can fly property
on the penguin1 object to false. And now I can cancel log
that penguin1 object. Notice the output to the console
after running the code is that penguin1 is an object with a can
fly property set to false. Additionally, I can still access all
the properties of the prototype. So accessing that has feathers and
can fly properties of penguin1 will return the values that are stored on
the prototype when I run the code. However, the can fly property is now
set on the penguin1 object itself, so it overrides the can fly
property on the prototype. This override only affects
the penguin1 object, it doesn’t change my prototype or
other eagle objects. In this video, you learned about
inheritance in JavaScript, although it is possible to build inheritance
using the object create method. It’s probably better to use class syntax
for more complex objects and inheritance. Although under the hood,
this syntax still works with prototypes. It makes sense to use classes as
they improve developer experience in more complex scenarios.
Reading: Creating classes
Reading
By the end of this reading, you should be able to explain, with examples, the concept of extending classes using basic inheritance to alter behaviors within child classes.
By now, you should know that inheritance in JavaScript is based around the prototype object.
All objects that are built from the prototype share the same functionality.
When you need to code more complex OOP relationships, you can use the class keyword and its easy-to-understand and easy-to-reason-about syntax.
Imagine that you need to code a Train class.
Once you’ve coded this class, you’ll be able to use the keyword new to instantiate objects of the Train class.
For now though, you first need to define the Train class, using the following syntax:
class Train {}
So, you use the class keyword, then specify the name of your class, with the first letter capitalized, and then you add an opening and a closing curly brace.
In between the curly braces, the first piece of code that you need to define is the constructor:
class Train {
constructor() {
}
}
The constructor will be used to build properties on the future object instance of the Train class.
For now, let’s say that there are only two properties that each object instance of the Train class should have at the time it gets instantiated: color and lightsOn.
class Train {
constructor(color, lightsOn) {
this.color = color;
this.lightsOn = lightsOn;
}
}
Notice the syntax of the constructor. The constructor is a special function in my Train class.
First of all, notice that there is no function keyword. Also, notice that the keyword constructor is used to define this function. You give your constructor function parameters inside an opening and closing parenthesis, just like in regular functions. The names of parameters are color and lightsOn.
Next, inside the constructor function’s body, you assigned the passed-in color parameter’s value to this.color, and the passed-in lightsOn parameter’s value to this.lightsOn.
What does this this keyword here represent?
It’s the future object instance of the Train class.
Essentially, this is all the code that you need to write to achieve two things:
- This code allows me to build new instances of the Train class.
- Each object instance of the Train class that I build will have its own custom properties of color and lightsOn.
Now, to actually build a new instance of the Train class, I need to use the following syntax:
new Train()
Inside the parentheses, you need to pass values such as “red” and false, for example, meaning that the color property is set to “red” and the lightsOn property is set to false.
And, to be able to interact with the new object built this way, you need to assign it to a variable.
Putting it all together, here’s your first train:
var myFirstTrain = new Train('red', false);
Just like any other variable, you can now, for example, console log the myFirstTrain object:
console.log(myFirstTrain); // Train {color: 'red', lightsOn: false}
You can continue building instances of the Train class. Even if you give them exactly the same properties, they are still separate objects.
var mySecondTrain = new Train('blue', false);
var myThirdTrain = new Train('blue', false);
However, this is not all that classes can offer.
You can also add methods to classes, and these methods will then be shared by all future instance objects of my Train class.
For example:
class Train {
constructor(color, lightsOn) {
this.color = color;
this.lightsOn = lightsOn;
}
toggleLights() {
this.lightsOn = !this.lightsOn;
}
lightsStatus() {
console.log('Lights on?', this.lightsOn);
}
getSelf() {
console.log(this);
}
getPrototype() {
var proto = Object.getPrototypeOf(this);
console.log(proto);
}
}
Now, there are four methods on your Train class: toggleLights(), lightsStatus(), getSelf() and getPrototype().
- The toggleLights method uses the logical not operator, !. This operator will change the value stored in the lightsOn property of the future instance object of the Train class; hence the !this.lightsOn. And the = operator to its left means that it will get assigned to this.lightsOn, meaning that it will become the new value of the lightsOn property on that given instance object.
- The lightsStatus() method on the Train class just reports the current status of the lightsOn variable of a given object instance.
- The getSelf() method prints out the properties on the object instance it is called on.
- The getPrototype() console logs the prototype of the object instance of the Train class. The prototype holds all the properties shared by all the object instances of the Train class. To get the prototype, you’ll be using JavaScript’s built-in Object.getPrototypeOf() method, and passing it this object – meaning, the object instance inside of which this method is invoked.
Now you can build a brand new train using this updated Train class:
var train4 = new Train('red', false);
And now, you can run each of its methods, one after the other, to confirm their behavior:
train4.toggleLights(); // undefined
train4.lightsStatus(); // Lights on? true
train4.getSelf(); // Train {color: 'red', lightsOn: true}
train4.getPrototype(); // {constructor: f, toggleLights: f, ligthsStatus: f, getSelf: f, getPrototype: f}
The result of calling toggleLights() is the change of true to false and vice-versa, for the lightsOn property.
The result of calling lightsStatus() is the console logging of the value of the lightsOn property.
The result of calling getSelf() is the console logging the entire object instance in which the getSelf() method is called. In this case, the returned object is the train4 object. Notice that this object gets returned only with the properties (“data”) that was build using the constructor() function of the Train class. That’s because all the methods on the Train class do not “live” on any of the instance objects of the Train class – instead, they live on the prototype, as will be confirmed in the next paragraph.
Finally, the result of calling the getPrototype() method is the console logging of all the properties on the prototype. When the class syntax is used in JavaScript, this results in only shared methods being stored on the prototype, while the constructor() function sets up the mechanism for saving instance-specific values (“data”) at the time of object instantiation.
Thus, in conclusion, the class syntax in JavaScript allows us to clearly separate individual object’s data – which exists on the object instance itself – from the shared object’s functionality (methods), which exist on the prototype and are shared by all object instances.
However, this is not the whole story.
It is possible to implement polymorphism using classes in JavaScript, by inheriting from the base class and then overriding the inherited behavior. To understand how this works, it is best to use an example.
In the code that follows, you will observe another class being coded, which is named HighSpeedTrain and inherits from the Train class.
This makes the Train class a base class, or the super-class of the HighSpeedTrain class. Put differently, the HighSpeedTrain class becomes the sub-class of the Train class, because it inherits from it.
To inherit from one class to a new sub-class, JavaScript provides the extends keyword, which works as follows:
class HighSpeedTrain extends Train {
}
As in the example above, the sub-class syntax is consistent with how the base class is defined in JavaScript. The only addition here is the extends keyword, and the name of the class from which the sub-class inherits.
Now you can describe how the HighSpeedTrain works. Again, you can start by defining its constructor function:
class HighSpeedTrain extends Train {
constructor(passengers, highSpeedOn, color, lightsOn) {
super(color, lightsOn);
this.passengers = passengers;
this.highSpeedOn = highSpeedOn;
}
}
Notice the slight difference in syntax in the constructor of the HighSpeedTrain class, namely the use of the super keyword.
In JavaScript classes, super is used to specify what property gets inherited from the super-class in the sub-class.
In this case, I choose to inherit both the properties from the Train super-class in the HighSpeedTrain sub-class.
These properties are color and lightsOn.
Next, you add the additional properties of the HighSpeedTrain class inside its constructor, namely, the passengers and highSpeedOn properties.
Next, inside the constructor body, you use the super keyword and pass in the inherited color and lightsOn properties that come from the Train class. On subsequent lines you assign passengers to this.passengers, and highSpeedOn to this.highSpeedOn.
Notice that in addition to the inherited properties, you also automatically inherit all the methods that exist on the Train prototype, namely, the toggleLights(), lightsStatus(), getSelf(), and getPrototype() methods.
Now let’s add another method that will be specific to the HighSpeedTrain class: the toggleHighSpeed() method.
class HighSpeedTrain extends Train {
constructor(passengers, highSpeedOn, color, lightsOn) {
super(color, lightsOn);
this.passengers = passengers;
this.highSpeedOn = highSpeedOn;
}
toggleHighSpeed() {
this.highSpeedOn = !this.highSpeedOn;
console.log('High speed status:', this.highSpeedOn);
}
}
Additionally, imagine you realized that you don’t like how the toggleLights() method from the super-class works, and you want to implement it a bit differently in the sub-class. You can add it inside the HighSpeedTrain class.
class HighSpeedTrain extends Train {
constructor(passengers, highSpeedOn, color, lightsOn) {
super(color, lightsOn);
this.passengers = passengers;
this.highSpeedOn = highSpeedOn;
}
toggleHighSpeed() {
this.highSpeedOn = !this.highSpeedOn;
console.log('High speed status:', this.highSpeedOn);
}
toggleLights() {
super.toggleLigths();
super.lightsStatus();
console.log('Lights are 100% operational.');
}
}
So, how did you override the behavior of the original toggleLights() method?
Well in the super-class, the toggleLights() method was defined as follows:
toggleLights() {
this.lightsOn = !this.lightsOn;
}
You realized that the HighSpeedTrain method should reuse the existing behavior of the original toggleLights() method, and so you used the super.toggleLights() syntax to inherit the entire super-class’ method.
Next, you also inherit the behavior of the super-class’ lightsStatus() method – because you realize that you want to have the updated status of the lightsOn property logged to the console, whenever you invoke the toggleLights() method in the sub-class.
Finally, you also add the third line in the re-implemented toggleLights() method, namely:
console.log('Lights are 100% operational.');
You’ve added this third line to show that I can combine the “borrowed” method code from the super-class with your own custom code in the sub-class.
Now you’re ready to build some train objects.
var train5 = new Train('blue', false);
var highSpeed1 = new HighSpeedTrain(200, false, 'green', false);
You’ve built the train5 object of the Train class, and set its color to “blue” and its lightsOn to false.
Next, you’ve built the highSpeed1 object to the HighSpeedTrain class, setting passengers to 200, highSpeedOn to false, color to “green”, and lightsOn to false.
Now you can test the behavior of train5, by calling, for example, the toggleLights() method, then the lightsStatus() method:
train5.toggleLights(); // undefined
train5.lightsStatus(); // Lights on? true
Here’s the entire completed code for this lesson:
class Train {
constructor(color, lightsOn) {
this.color = color;
this.lightsOn = lightsOn;
}
toggleLights() {
this.lightsOn = !this.lightsOn;
}
lightsStatus() {
console.log('Lights on?', this.lightsOn);
}
getSelf() {
console.log(this);
}
getPrototype() {
var proto = Object.getPrototypeOf(this);
console.log(proto);
}
}
class HighSpeedTrain extends Train {
constructor(passengers, highSpeedOn, color, lightsOn) {
super(color, lightsOn);
this.passengers = passengers;
this.highSpeedOn = highSpeedOn;
}
toggleHighSpeed() {
this.highSpeedOn = !this.highSpeedOn;
console.log('High speed status:', this.highSpeedOn);
}
toggleLights() {
super.toggleLights();
super.lightsStatus();
console.log('Lights are 100% operational.');
}
}
var myFirstTrain = new Train('red', false);
console.log(myFirstTrain); // Train {color: 'red', lightsOn: false}
var mySecondTrain = new Train('blue', false);
var myThirdTrain = new Train('blue', false);
var train4 = new Train('red', false);
train4.toggleLights(); // undefined
train4.lightsStatus(); // Lights on? true
train4.getSelf(); // Train {color: 'red', lightsOn: true}
train4.getPrototype(); // {constructor: f, toggleLights: f, ligthsStatus: f, getSelf: f, getPrototype: f}
var train5 = new Train('blue', false);
var highSpeed1 = new HighSpeedTrain(200, false, 'green', false);
train5.toggleLights(); // undefined
train5.lightsStatus(); // Lights on? true
highSpeed1.toggleLights(); // Lights on? true, Lights are 100% operational.
Notice how the toggleLights() method behaves differently on the HighSpeedTrain class than it does on the Train class.
Additionally, it helps to visualize what is happening by getting the prototype of both the train5 and the highSpeed1 trains:
train5.getPrototype(); // {constructor: ƒ, toggleLights: ƒ, lightsStatus: ƒ, getSelf: ƒ, getPrototype: ƒ}
highSpeed1.getPrototype(); // Train {constructor: ƒ, toggleHighSpeed: ƒ, toggleLights: ƒ}
The returned values in this case might initially seem a bit tricky to comprehend, but actually, it is quite simple:
- The prototype object of the train5 object was created when you defined the class Train. You can access the prototype using Train.prototype syntax and get the prototype object back.
- The prototype object of the highSpeed1 object is this object: {constructor: ƒ, toggleHighSpeed: ƒ, toggleLights: ƒ}. In turn this object has its own prototype, which can be found using the following syntax: HighSpeedTrain.prototype.__proto__. Running this code returns: {constructor: ƒ, toggleLights: ƒ, lightsStatus: ƒ, getSelf: ƒ, getPrototype: ƒ}.
Prototypes seem easy to grasp at a certain level, but it’s easy to get lost in the complexity. This is one of the reasons why class syntax in JavaScript improves your developer experience, by making it easier to reason about the relationships between classes. However, as you improve your skills, you should always strive to understand your tools better, and this includes prototypes. After all, JavaScript is just a tool, and you’ve now “peeked behind the curtain”.
In this reading, you’ve learned the very essence of how OOP with classes works in JavaScript. However, this is not all.
In the lesson on designing an object-oriented program, you’ll learn some more useful concepts. These mostly have to do with coding your classes so that it’s even easier to create object instances of those classes in JavaScript.
Using class instance as another class’ constructor’s property
Consider the following example:
class StationaryBike {
constructor(position, gears) {
this.position = position
this.gears = gears
}
}
class Treadmill {
constructor(position, modes) {
this.position = position
this.modes = modes
}
}
class Gym {
constructor(openHrs, stationaryBikePos, treadmillPos) {
this.openHrs = openHrs
this.stationaryBike = new StationaryBike(stationaryBikePos, 8)
this.treadmill = new Treadmill(treadmillPos, 5)
}
}
var boxingGym = new Gym("7-22", "right corner", "left corner")
console.log(boxingGym.openHrs) //
console.log(boxingGym.stationaryBike) //
console.log(boxingGym.treadmill) //
7-22
StationaryBike { position: 'right corner', gears: 8 }
Treadmill { position: 'left corner', modes: 5 }
In this example, there are three classes defined: StationaryBike, Treadmill, and Gym.
The StationaryBike class is coded so that its future object instance will have the position and gears properties. The position property describes where the stationary bike will be placed inside the gym, and the gears propery gives the number of gears that that stationary bike should have.
The Treadmill class also has a position, and another property, named modes (as in “exercise modes”).
The Gym class has three parameters in its constructor function: openHrs, stationaryBikePos, treadmillPos.
This code allows me to instantiate a new instance object of the Gym class, and then when I inspect it, I get the following information:
- the openHrs property is equal to “7-22” (that is, 7am to 10pm)
- the stationaryBike property is an object of the StationaryBike type, containing two properties: position and gears
- the treadmill property is an object of the Treadmill type, containing two properties: position and modes
Reading: Default Parameters
Reading
A useful a ES6 feature allows me to set a default parameter inside a function definition First, .
What that means is, I’ll use an ES6 feature which allows me to set a default parameter inside a function definition, which goes hand in hand with the defensive coding approach, while requiring almost no effort to implement.
For example, consider a function declaration without default parameters set:
function noDefaultParams(number) {
console.log('Result:', number * number)
}
Obviously, the noDefaultParams function should return whatever number it receives, squared.
However, what if I call it like this:
noDefaultParams(); // Result: NaN
JavaScript, due to its dynamic nature, doesn’t throw an error, but it does return a non-sensical output.
Consider now, the following improvement, using default parameters:
function withDefaultParams(number = 10) {
console.log('Result:', number * number)
}
Default params allow me to build a function that will run with default argument values even if I don’t pass it any arguments, while still being flexible enough to allow me to pass custom argument values and deal with them accordingly.
This now allows me to code my classes in a way that will promote easier object instantiation.
Consider the following class definition:
class NoDefaultParams {
constructor(num1, num2, num3, string1, bool1) {
this.num1 = num1;
this.num2 = num2;
this.num3 = num3;
this.string1 = string1;
this.bool1 = bool1;
}
calculate() {
if(this.bool1) {
console.log(this.string1, this.num1 + this.num2 + this.num3);
return;
}
return "The value of bool1 is incorrect"
}
}
Now I’ll instantiate an object of the NoDefaultParams class, and run the calculate() method on it. Obviously, the bool1 should be set to true on invocation to make this work, but I’ll set it to false on purpose, to highlight the point I’m making.
var fail = new NoDefaultParams(1,2,3,false);
fail.calculate(); // 'The value of bool1 is incorrect'
This example might highlight the reason sometimes weird error messages appear when some software is used – perhaps the developers just didn’t have enough time to build it better.
However, now that you know about default parameters, this example can be improved as follows:
class WithDefaultParams {
constructor(num1 = 1, num2 = 2, num3 = 3, string1 = "Result:", bool1 = true) {
this.num1 = num1;
this.num2 = num2;
this.num3 = num3;
this.string1 = string1;
this.bool1 = bool1;
}
calculate() {
if(this.bool1) {
console.log(this.string1, this.num1 + this.num2 + this.num3);
return;
}
return "The value of bool1 is incorrect"
}
}
var better = new WithDefaultParams();
better.calculate(); // Result: 6
This approach improves the developer experience of my code, because I no longer have to worry about feeding the WithDefaultParameters class with all the arguments. For quick tests, this is great, because I no longer need to worry about passing the proper arguments.
Additionally, this approach really shines when building inheritance hierarchies using classes, as it makes it possible to provide only the custom properties in the sub-class, while still accepting all the default parameters from the super-class constructor.
In conclusion, in this reading I’ve covered the following:
- How to approach designing an object-oriented program in JavaScript
- The role of the extends and super keywords
- The importance of using default parameters.
Reading: Designing an OO Program
Reading
In this reading, I will show you how to create classes in JavaScript, using all the concepts you’ve learned so far.
Specifically, I’m preparing to build the following inheritance hierarchy:
Animal
/ \
Cat Bird
/ \ \
HouseCat Tiger Parrot
There are two keywords that are essential for OOP with classes in JavaScript.
These keywords are extends and super.
The extends keyword allows me to inherit from an existing class.
Based on the above hierarchy, I can code the Animal class like this:
class Animal {
// ... class code here ...
}
Then I can code, for example, the Cat sub-class, like this:
class Cat extends Animal {
// ... class code here ...
}
This is how the extends keyword is used to setup inheritance relationships.
The super keyword allows me to “borrow” functionality from a super-class, in a sub-class. The exact dynamics of how this works will be covered later on in this lesson.
Now I can start thinking about how to implement my OOP class hierarchy.
Before I even begin, I need to think about things like: * What should go into the base class of Animal? In other words, what will all the sub-classes inherit from the base class? * What are the specific properties and methods that separate each class from others? * Generally, how will my classes relate to one another?
Once I’ve thought it through, I can build my classes.
So, my plan is as follows:
1. The Animal class’ constructor will have two properties: color and energy
2. The Animal class’ prototype will have three methods: isActive(), sleep(), and getColor().
3. The isActive() method, whenever ran, will lower the value of energy until it hits 0. The isActive() method will also report the updated value of energy. If energy is at zero, the animal object will immediately go to sleep, by invoking the sleep() method based on the said condition.
4. The getColor() method will just console log the value in the color property.
5. The Cat class will inherit from Animal, with the additional sound, canJumpHigh, and canClimbTrees properties specific to the Cat class. It will also have its own makeSound() method.
6. The Bird class will also inherit from Animal, but is own specific properties will be quite different from Cat. Namely, the Bird class will have the sound and the canFly properties, and the makeSound method too.
7. The HouseCat class will extend the Cat class, and it will have its own houseCatSound as its special property. Additionally, it will override the makeSound() method from the Cat class, but it will do so in an interesting way. If the makeSound() method, on invocation, receives a single option argument – set to true, then it will run super.makeSound() – in other words, run the code from the parent class (Cat) with the addition of running the console.log(this.houseCatSound). Effectively, this means that the makeSound() method on the HouseCat class’ instance object will have two separate behaviors, based on whether we pass it true or false.
8. The Tiger class will also inherit from Cat, and it will come with its own tigerSound property, while the rest of the behavior will be pretty much the same as in the HouseCat class.
9. Finally, the Parrot class will extend the Bird class, with its own canTalk property, and its own makeSound() method, working with two conditionals: one that checks if the value of true was passed to makeSound during invocation, and another that checks the value stored inside this.canTalk property.
Now that I have fully explained how all the code in my class hierarchy should work I might start implementing it by adding all the requirements as comments inside the code structure.
At this stage, with all the requirements written down as comments, my code should be as follows:
class Animal {
// constructor: color, energy
// isActive()
// if energy > 0, energy -=20, console log energy
// else if energy <= 0, sleep()
// sleep()
// energy += 20
// console.log energy
}
class Cat extends Animal {
// constructor: sound, canJumpHigh, canClimbTrees, color, energy
// makeSound()
// console.log sound
}
class Bird extends Animal {
// constructor: sound, canFly, color, energy
// makeSound()
// console.log sound
}
class HouseCat extends Cat {
// constructor: houseCatSound, sound, canJumpHigh, canClimbTrees, color, energy
// makeSound(option)
// if (option)
// super.makeSound()
// console.log(houseCatSound)
}
class Tiger extends Cat {
// constructor: tigerSound, sound, canJumpHigh, canClimbTrees, color, energy
// makeSound(option)
// if (option)
// super.makeSound()
// console.log(tigerSound)
}
class Parrot extends Bird {
// constructor: canTalk, sound, canJumpHigh, canClimbTrees, color, energy
// makeSound(option)
// if (option)
// super.makeSound()
// if (canTalk)
// console.log("talking!")
}
Now that I’ve coded my requirements inside comments of otherwise empty classes, I can start coding each class as per my specifications.
Coding the Animal class
First, I’ll code the base Animal class.
class Animal {
constructor(color = 'yellow', energy = 100) {
this.color = color;
this.energy = energy;
}
isActive() {
if(this.energy > 0) {
this.energy -= 20;
console.log('Energy is decreasing, currently at:', this.energy)
} else if(this.energy == 0){
this.sleep();
}
}
sleep() {
this.energy += 20;
console.log('Energy is increasing, currently at:', this.energy)
}
getColor() {
console.log(this.color)
}
}
Each animal object, no matter which one it is, will share the properties of color and energy.
Now I can code the Cat and Bird classes:
class Cat extends Animal {
constructor(sound = 'purr', canJumpHigh = true, canClimbTrees = true, color, energy) {
super(color, energy);
this.sound = sound;
this.canClimbTrees = canClimbTrees;
this.canJumpHigh = canJumpHigh;
}
makeSound() {
console.log(this.sound);
}
}
class Bird extends Animal {
constructor(sound = 'chirp', canFly = true, color, energy) {
super(color, energy);
this.sound = sound;
this.canFly = canFly;
}
makeSound() {
console.log(this.sound);
}
}
Note: If I didn’t use the super keyword in our sub-classes, once I’d run the above code, I’d get the following error: Uncaught ReferenceError: Must call super constructor in derived class before accessing ‘this’ or returning from derived constructor.
And now I can code the three remaining classes: HouseCat, Tiger, and Parrot.
class HouseCat extends Cat {
constructor(houseCatSound = "meow", sound,canJumpHigh,canClimbTrees, color,energy) {
super(sound,canJumpHigh,canClimbTrees, color,energy);
this.houseCatSound = houseCatSound;
}
makeSound(option) {
if (option) {
super.makeSound();
}
console.log(this.houseCatSound);
}
}
class Tiger extends Cat {
constructor(tigerSound = "Roar!", sound,canJumpHigh,canClimbTrees, color,energy) {
super(sound,canJumpHigh,canClimbTrees, color,energy);
this.tigerSound = tigerSound;
}
makeSound(option) {
if (option) {
super.makeSound();
}
console.log(this.tigerSound);
}
}
class Parrot extends Bird {
constructor(canTalk = false, sound,canFly, color,energy) {
super(sound,canFly, color,energy);
this.canTalk = canTalk;
}
makeSound(option) {
if (option) {
super.makeSound();
}
if (this.canTalk) {
console.log("I'm a talking parrot!");
}
}
}
Now that we’ve set up this entire inheritance structure, we can build various animal objects.
For example, I can build two parrots: one that can talk, and the other that can’t.
var polly = new Parrot(true); // we're passing `true` to the constructor so that polly can talk
var fiji = new Parrot(false); // we're passing `false` to the constructor so that fiji can't talk
polly.makeSound(); // 'chirp', 'I'm a talking parrot!'
fiji.makeSound(); // 'chirp'
polly.color; // yellow
polly.energy; // 100
polly.isActive(); // Energy is decreasing, currently at: 80
var penguin = new Bird("shriek", false, "black and white", 200); // setting all the custom properties
penguin; // Bird {color: 'black and white', energy: 200, sound: 'shriek', canFly: false }
penguin.sound; // 'shriek'
penguin.canFly; // false
penguin.color; // 'black and white'
penguin.energy; // 200
penguin.isActive(); // Energy is decreasing, currently at: 180
Also, I can build a pet cat:
var leo = new HouseCat();
Now I can have leo purr:
// leo, no purring please:
leo.makeSound(false); // meow
// leo, both purr and meow now:
leo.makeSound(true); // purr, meow
Additionally, I can build a tiger:
var cuddles = new Tiger();
My cuddles tiger can purr and roar, or just roar:
cuddles.makeSound(false); // Roar!
cuddels.makeSound(true); // purr, Roar!
Here’s the complete code from this lesson, for easier copy-pasting:
class Animal {
constructor(color = 'yellow', energy = 100) {
this.color = color;
this.energy = energy;
}
isActive() {
if(this.energy > 0) {
this.energy -= 20;
console.log('Energy is decreasing, currently at:', this.energy)
} else if(this.energy == 0){
this.sleep();
}
}
sleep() {
this.energy += 20;
console.log('Energy is increasing, currently at:', this.energy)
}
getColor() {
console.log(this.color)
}
}
class Cat extends Animal {
constructor(sound = 'purr', canJumpHigh = true, canClimbTrees = true, color, energy) {
super(color, energy);
this.sound = sound;
this.canClimbTrees = canClimbTrees;
this.canJumpHigh = canJumpHigh;
}
makeSound() {
console.log(this.sound);
}
}
class Bird extends Animal {
constructor(sound = 'chirp', canFly = true, color, energy) {
super(color, energy);
this.sound = sound;
this.canFly = canFly;
}
makeSound() {
console.log(this.sound);
}
}
class HouseCat extends Cat {
constructor(houseCatSound = "meow", sound,canJumpHigh,canClimbTrees, color,energy) {
super(sound,canJumpHigh,canClimbTrees, color,energy);
this.houseCatSound = houseCatSound;
}
makeSound(option) {
if (option) {
super.makeSound();
}
console.log(this.houseCatSound);
}
}
class Tiger extends Cat {
constructor(tigerSound = "Roar!", sound,canJumpHigh,canClimbTrees, color,energy) {
super(sound,canJumpHigh,canClimbTrees, color,energy);
this.tigerSound = tigerSound;
}
makeSound(option) {
if (option) {
super.makeSound();
}
console.log(this.tigerSound);
}
}
class Parrot extends Bird {
constructor(canTalk = false, sound,canFly, color,energy) {
super(sound,canFly, color,energy);
this.canTalk = canTalk;
}
makeSound(option) {
if (option) {
super.makeSound();
}
if (this.canTalk) {
console.log("I'm a talking parrot!");
}
}
}
var fiji = new Parrot(false); // we're passing `false` to the constructor so that fiji can't talk
var polly = new Parrot(true); // we're passing `true` to the constructor so that polly can talk
fiji.makeSound(); // undefined
fiji.makeSound(true); // chirp
polly.makeSound(); // I'm a talking parrot!
polly.makeSound(true); // chirp, I'm a talking parrot!
polly.color; // yellow
polly.energy; // 100
polly.isActive(); // Energy is decreasing, currently at: 80
var penguin = new Bird("shriek", false, "black and white", 200); // setting all the custom properties
penguin; // Bird {color: 'black and white', energy: 200, sound: 'shriek', canFly: false }
penguin.sound; // 'shriek'
penguin.canFly; // false
penguin.color; // 'black and white'
penguin.energy; // 200
penguin.isActive(); // Energy is decreasing, currently at: 180
var leo = new HouseCat();
// leo, no purring please:
leo.makeSound(false); // meow
// leo, both purr and meow now:
leo.makeSound(true); // purr, meow
var cuddles = new Tiger();
cuddles.makeSound(false); // Roar!
cuddles.makeSound(true); // purr, Roar!
Programming Assignment: Building an object-oriented program
README.md
Lab Instructions: Object Oriented Programming
Tips: Before you Begin
To view your code and instructions side-by-side, select the following in your VSCode toolbar:
- View -> Editor Layout -> Two Columns
- To view this file in Preview mode, right click on this README.md file and
Open Preview
- Select your code file in the code tree, which will open it up in a new VSCode tab.
- Drag your assessment code files over to the second column.
- Great work! You can now see instructions and code at the same time.
- Questions about using VSCode? Please see our support resources here:
Visual Studio Code on CourseraTo run your JavaScript code
- Select your JavaScript file
- Select the “Run Code” button in the upper right hand toolbar of VSCode.
Ex: It looks like a triangular “Play” button.
Task 1: Code a Person class
Code a Person class, with three parameters in the constructor: name, age, and energy.
Set the default parameters in the Person class as follows:
name = "Tom"
age = 20
energy = 100
Code two methods in the Person
class. Name those methods sleep()
and doSomethingFun()
.
The sleep()
method should take the existing energy level and increase it by 10.
The doSomethingFun() method should take the existing energy level and decrease it by 10.
Task 2: Code a Worker class
Code a sub-class, inheriting from the Person
class, and name it Worker
.
The Worker
class has two additional parameters in the constructor:
- xp (for “experience points”)
- hourlyWage.
These properties are set to the following default values:
xp = 0
hourlyWage = 10
The Worker
class has all the paramerters and methods of its super-class.
Additionally, it has the goToWork()
method, which, whenever it’s run, increases the value of the xp
property by 10.
Task 3: Code a intern object
Inside the intern function instantiate the Worker
class to code a new intern object.
The intern should have the following characteristics:
name: Bob
age: 21
energy: 110
xp: 0
hourlyWage: 10
Run the goToWork()
method on the intern object. Then return
the intern object.
Task 4: Code a manager object
Inside the manager function instantiate the Worker
class to code a new manager
object.
The manager object should have the following characteristics:
name: Alice
age: 30
energy: 120
xp: 100
hourlyWage: 30
Run the doSomethingFun()
method on the manager object. Then return
the manager object.
Nice work!
ooprogramming.js
// Task 1: Code a Person class
class Person {
constructor(name = "Tom", age = 20, energy = 100) {
this.name = name;
this.age = age;
this.energy = energy;
}
sleep() {
this.energy += 10;
}
doSomethingFun() {
this.energy -= 10;
}
}
// Task 2: Code a Worker class
class Worker extends Person {
constructor(name = "Tom", age = 20, energy = 100,xp = 0, hourlyWage = 10) {
super(name, age, energy)
this.xp = xp;
this.hourlyWage = hourlyWage;
}
doSomethingFun() {
super.doSomethingFun
}
sleep() {
super.sleep;
}
goToWork() {
this.xp += 10;
}
}
// Task 3: Code an intern object, run methods
function intern() {
let intern = new Worker();
intern.name = "Bob";
intern.age = 21
intern.energy = 110
intern.xp = 0
intern.hourlyWage = 10
intern.goToWork()
return(intern)
}
// Task 4: Code a manager object, methods
function manager() {
let manager = new Worker("Alice", 30, 120, 100, 30);
manager.doSomethingFun()
return manager;
}
console.log(intern())
console.log(manager())
Practice Quiz: Knowledge check: Introduction to Object-Oriented Programming
What will print out when the following code runs?
class Cake {
constructor(lyr) {
this.layers = lyr + 1;
}
}
var result = new Cake(1);
console.log(result.layers);
2
That’s correct! The Cake object stores its layers property as the value of the constructor parameter lyr plus one. Therefore, the value of the layers property is 2.
When a class extends another class, this is called ____________.
Inheritance
That’s correct! A class inherits from another class using the extends keyword. This is called Inheritance.
What will print out when the following code runs?
class Animal {
constructor(lg) {
this.legs = lg;
}
}
class Dog extends Animal {
constructor() {
super(4);
}
}
var result = new Dog();
console.log(result.legs);
4
That’s correct! The Dog constructor passes the value of 4 to the super constructor of Animal. Therefore, the value of the legs property is 4 .
What will print out when the following code runs?
class Animal {
}
class Cat extends Animal {
constructor() {
super();
this.noise = "meow";
}
}
var result = new Animal();
console.log(result.noise);
undefined
That’s correct! The noise property does not exist within the scope of the Animal class. Therefore, undefined will print.
What will print out when the following code runs?
class Person {
sayHello() {
console.log("Hello");
}
}
class Friend extends Person {
sayHello() {
console.log("Hey");
}
}
var result = new Friend();
result.sayHello();
Hey
That’s correct! The Friend class overrides the sayHello method. Therefore, Hey is printed out instead of Hello when sayHello is called.
Reading: Additional resources
Reading
Here is a list of resources that may be helpful as you continue your learning journey.
Advanced Javascript Features
Video: De-structuring arrays and objects
Here’s a summary of the key points about destructuring in JavaScript:
Understanding Destructuring:
- It’s a way to extract specific values from objects or arrays and create new variables from them.
- Imagine a project folder: Destructuring is like copying a file from that folder to a separate location.
- The original item remains in the folder, but the copy is independent.
How It Works:
- Use the
let
keyword and curly braces to target desired properties. - Example:
let { PI } = Math;
extracts thePI
property from theMath
object into a new variable namedPI
. - Case-sensitivity matters:
let { pi } = Math;
would returnundefined
becausepi
doesn’t exist onMath
.
Key Characteristics:
- Independence: Destructuring creates a separate copy, not a reference.
- No Connection: Modifying the dstructured variable doesn’t affect the original property.
- Array Destructuring: Works similarly to extract elements into individual variables.
Example:
let { PI } = Math;
creates a copy ofMath.PI
inPI
.PI === Math.PI
initially returnstrue
.- Changing
PI
to1
doesn’t affectMath.PI
. PI === Math.PI
now returnsfalse
, proving their independence.
Remember:
- Destructuring is a powerful tool for working concisely with objects and arrays in JavaScript.
- It can simplify code and make it more readable.
✨ Welcome to the De-structuring Arrays and Objects in JavaScript Tutorial! ✨
Here, you’ll unlock a powerful technique to extract specific values from arrays and objects, creating new variables in a clean and concise way.
Let’s dive in!
What is Destructuring?
- It’s like carefully unpacking items from a box and placing them on individual shelves.
- You select specific values from a collection (array or object) and assign them to new variables.
- It’s often used to simplify code, make it more readable, and avoid repetitive property/element access.
De-structuring Objects:
Syntax:
let { property1, property2, ... } = objectToDestructure;
Example:
let person = { name: "Alice", age: 30, city: "New York" };
let { name, age } = person; // Extract name and age into separate variables
console.log(name); // Output: "Alice"
console.log(age); // Output: 30
De-structuring Arrays:
Syntax:
let [element1, element2, ... ] = arrayToDestructure;
Example:
let numbers = [10, 20, 30];
let [first, second] = numbers; // Extract first two elements
console.log(first); // Output: 10
console.log(second); // Output: 20
✨ Advanced Features:
Default Values:
let { city = "Unknown" } = person; // If "city" is missing, assign "Unknown"
Ignoring Values:
let { name, _ } = person; // Extract name, ignore other properties
Destructuring in Functions:
function greet({ name, age }) {
console.log("Hello, " + name + ", age " + age + "!");
}
greet(person); // Pass the object directly
Benefits of Destructuring:
- Cleaner, more concise code
- Enhanced readability
- Improved variable naming
- Efficient value extraction
- Flexible data manipulation
Practice and Explore:
- Experiment with different examples.
- Combine destructuring with other JavaScript features.
- Discover creative ways to leverage its power in your projects!
Have you ever needed to apply
the formatting of text in a word processor from one portion of text to another. In essence you are copying the properties
from some text that is already formatted and applying them to another
piece of text that you want to format. In a similar way as with text, JavaScript objects can have properties
that define their characteristics. In this video, you will learn
how to D structure, objects and arrays and
also how to use the D structuring syntax, to extract new variables from objects and
arrays. To illustrate D structuring,
imagine that an object or an array is like a project folder that you have on
your computer with several files in it. D structuring something out of an object
or array, in this case your project folder is like copying that item from your
folder on to another location. The original item still exists
in your project folder. I just made a copy of
the original item but this copy is completely
independent of the original item. Now let’s explore an example with
an existing built in math object to D Structure the value of phi from it. Let’s start by using the LET keyword and surround the uppercase Pie in curly
brackets equals math because I already know that the pie property
exists on the math object. I make a copy of it and I save
the new object in a separate variable. I name Pie. Note that I can only destruction
something that already exists on an object using faulty spelling,
including lower case won’t work and will return an undefined value If I
type let open curly bracket small case pi close curly bracket equals
math pi returns as undefined. This is because there isn’t a lowercase
pi property on the math object. So when I try to destroy culture it,
I get the value of undefined for the lower case pi variable. The next step is to confirm that all caps
pi variable has the identical value and data type as math dot pi by using the
triple equal strict comparison operator. This will return a value of true to
prove that the D structured property and the original property
are in no way connected. I update the value of
the pie variable to be one. By Typing Pi equals one. I can now compare all caps pie and
math dot pi again by typing pie, triple equal sign, math dot pi, thus
getting back the boolean value of false. It’s clear that these two
are no longer the same. The only reason why this worked is because
the original property on the object and the D structured value
are not connected in any way. In other words, there’s no connection
between the d structured variable and the source property on the given object. In this video, you covered how to de
structure objects and erase and also how to use the D structuring syntax to extract
new variables from objects and arrays
True or False. In JavaScript, it's possible to extract the properties from objects into distinct variables using destructuring.
True
Correct. In JavaScript, it’s possible to extract the properties from objects into distinct variables using destructuring.
Reading: For of loops and objects
Reading
In this reading, you’ll learn how the for of loop works conceptually.
To begin, it’s important to know that a for of loop cannot work on an object directly, since an object is not iterable. For example:
const car = {
speed: 100,
color: "blue"
}
for(prop of car) {
console.log(prop)
}
Running the above code snippet will throw the following error:
Uncaught TypeError: car is not iterable
Contrary to objects, arrays are iterable. For example:
const colors = ['red','orange','yellow']
for (var color of colors) {
console.log(color);
}
This time, the output is as follows:
red
orange
yellow
Luckily, you can use the fact that a for of loop can be run on arrays to loop over objects.
But how?
Before you can properly answer this question, you first need to review three built-in methods: Object.keys(), Object.values(), and Object.entries().
Built-in methods
The Object.keys() method
The Object.keys() method receives an object as its parameter. Remember, this object is the object you want to loop over. It’s still too early to explain how you’ll loop over the object itself; for now, focus on the returned array of properties when you call the Object.keys() method.
Here’s an example of running the Object.keys() method on a brand new car2 object:
const car2 = {
speed: 200,
color: "red"
}
console.log(Object.keys(car2)); // ['speed','color']
[ 'speed', 'color' ]
So, when I run Object.keys() and pass it my car2 object, the returned value is an array of strings, where each string is a property key of the properties contained in my car2 object.
The Object.values() method
Another useful method is Object.values():
const car3 = {
speed: 300,
color: "yellow"
}
console.log(Object.values(car3)); // [300, 'yellow']
The Object.entries() method
Finally, there’s another useful method, Object.entries(), which returns an array listing both the keys and the values.
const car4 = {
speed: 400,
color: 'magenta'
}
console.log(Object.entries(car4));
What gets returned from the invocation of the Object.entries() method is the following:
[ ['speed', 400], ['color', 'magenta'] ]
This time, the values that get returned are 2-member arrays nested inside an array. In other words, you get an array of arrays, where each array item has two members, the first being a property’s key, and the second being a property’s value.
Effectively, it’s as if you was listing all of a given object’s properties, a bit like this:
[
[propertyKey, propertyVal],
[propertyKey, propertyVal],
...etc
]
To summarise, you learned that you can loop over arrays using the for of loop. You also learned that you can extract object’s keys, values, or both, using the Object.keys(), Object.values() and Object.entries() syntax.
Examples
You now have all the ingredients that you need to loop over any object’s own property keys and values.
Here’s a very simple example of doing just that:
var clothingItem = {
price: 50,
color: 'beige',
material: 'cotton',
season: 'autumn'
}
for( const key of Object.keys(clothingItem) ) {
console.log(key, ":", clothingItem[key])
}
The trickiest part to understand in this syntax is probably the clothingItem[key].
Luckily, this is not too hard to comprehend, especially since you’ve already covered the concept previously when you were learning how to access an object’s member using the brackets notation.
Recall that you also learned how you can dynamically access a property name.
To revisit this concept and show a practical demo of how that works, let’s code a function declaration that randomly assigns either the string speed or the string color to a variable name, and then build an object that has only two keys: a speed key and a color key.
After this setup, you will be able to dynamically access either one of those properties on a brand new drone object, using the brackets notation.
Here’s the example’s code:
function testBracketsDynamicAccess() {
var dynamicKey;
if(Math.random() > 0.5) {
dynamicKey = "speed";
}else{
dynamicKey = "color";
}
var drone = {
speed: 15,
color: "orange"
}
console.log(drone[dynamicKey]);
}
testBracketsDynamicAccess();
15
This example might feel a bit convoluted, but its purpose is to demo the fact that you’re getting either one or the other value from an object’s key, based on the string that got assigned to the dynamicKey variable, and accessed without issues, using the brackets notation.
Feel free to run the testBracketsDynamicAccess() function a few times, and you’ll notice that sometimes the value that gets output is 15, and sometimes it’s orange, although I’m always accessing the drone[dynamicKey] key. Since the value of the dynamicKey is populated on the Math.random() invocation, sometimes that expression evaluates to drone[“speed”], and other times that expression evaluates to drone[“color”].
You have now learned about the building blocks that make the for of loop useful to iterate over objects – although objects are not iterables.
Next, you’ll have a go at a practical example of working with both the for of and the for in loop. Each loops have their place and can be considered useful in different situations.
Video: For- of loops and objects
Here’s a summary of the video:
Key points:
- for…in loops: Iterate over an object’s own properties and its prototype’s properties, making them potentially unreliable for targeting only object-specific properties.
- for…of loops: Iterate exclusively over an object’s own properties, disregarding its prototype.
Demonstration:
- An object named
car
with propertiesengine
,steering
, andspeed
is created. - A
sportsCar
object inherits fromcar
usingObject.create
. - A
for...in
loop onsportsCar
logs both its ownspeed
property and the inheritedengine
andsteering
properties, highlighting its inclusion of prototype properties. - A
for...of
loop onsportsCar
logs only its ownspeed
property, demonstrating its focus on object-specific properties.
Simplified example:
- A simplified version reinforces the key concepts using a
car
object with only anengine
property and asportsCar
object inheriting from it. - The
for...in
loop again logs bothspeed
(fromsportsCar
) andengine
(from the prototype), while thefor...of
loop logs onlyspeed
.
Conclusion:
- When iterating over objects in JavaScript, use
for...of
loops to reliably target only the object’s own properties. - Use
for...in
loops cautiously, being mindful of their inclusion of prototype properties.
Navigating Objects with Precision: A Guide to For…of Loops in JavaScript
In the realm of JavaScript, where objects reign supreme, understanding how to effectively loop through their properties is essential. While for…in loops have their place, for…of loops offer a more focused and reliable approach when working with objects directly.
In this tutorial, we’ll explore the distinctions between these loops and how to confidently use them to navigate object properties.
1. Understanding the Key Differences
- for…in: Iterates over all enumerable properties of an object, including those inherited from its prototype chain. This can be useful for exploring an object’s full structure, but it’s important to be aware of the potential inclusion of prototype properties.
- for…of: Iterates exclusively over the object’s own enumerable properties, disregarding any inherited ones. This provides a more precise and predictable way to focus on the object’s specific attributes.
2. Syntax and Usage
for…in:
for (const property in object) {
console.log(property, object[property]);
}
for…of:
for (const value of object) {
console.log(value);
}
3. Examples in Action
JavaScript
const car = { engine: true, steering: true, speed: "slow" };
const sportsCar = Object.create(car);
sportsCar.speed = "fast";
// for...in loop (includes prototype properties)
for (const prop in sportsCar) {
console.log(prop); // Output: "speed", "engine", "steering"
}
// for...of loop (only object's own properties)
for (const prop of sportsCar) {
console.log(prop); // Output: "speed"
}
4. When to Use Each Loop
- Use for…of:
- When you want to iterate over an object’s own properties directly.
- When you need to avoid prototype pollution and ensure predictable results.
- When working with arrays or iterables in general.
- Use for…in:
- When you need to explore the full hierarchy of an object, including inherited properties.
- When working with objects for key-value mapping or property enumeration.
5. Key Points to Remember
- for…of loops are generally preferred for iterating over object properties due to their accuracy and predictability.
- for…in loops can be useful for specific scenarios, but be mindful of their inclusion of prototype properties.
- Choose the appropriate loop based on your intended use case and desired level of property inclusion.
By mastering for…of loops and understanding their distinction from for…in loops, you’ll gain greater control and precision when navigating objects in JavaScript, ensuring you work with the exact properties you need.
When working with objects, the for-of loop and for-in loop can be used to iterate over the object's properties. Which of the following statements are correct? Choose all that apply.
- The for-of loop will iterate over the object’s own properties only when using the Object.keys() method to return an array to loop over.
- The for-of loop will not iterate over the object and its prototype properties.
In this video, I’ll help you
understand the difference between for and loops
and for of loops, when applied to
objects in JavaScript. At first, this code
may appear complex, but you’ll find that
it only involves concepts that you’ve
dealt with before. Let’s begin by breaking
down what I have. I have a concept to an object and assign to a
variable named car. This object has three
properties, engine, steering and speed, which
are given the values true, true, and slow respectively. I also have a cost assigned
to the variable sports car, and I’ve used Object.create, so that inherits the properties
of the car variable. Then I set the speed
property of the sports car to fast and save it to
the sports car variable. I’ve also added a console
log to display the string, the sports car object, followed by the properties
of the sports car object. Next, I have two for loops. The first one is a
for-in loop written to log the properties of
the sports car object. This is typed as for, followed by properties and
sports car in parentheses. Inside of curly braces is
a console log for prop, so it displays the properties
of the sports car. Before and after the
foreign loop code, I’ve written console
logs to print some comments which will be addressed after I run my code. My second for loop uses the object keys method
on my sports car object, which should iterate
over that object. This is typed as for, followed by prop of objects, dot keys, sports car
inside of parentheses. Inside of the curly braces is a console log for
prop plus a colon in double-quotes and sports car with prop enclosed
in square brackets. I’ve also console logged
another comma after this code. When I run this code, I get the output. The sports car object
is speed fast. It also displays a
comment I had in the code for in is unreliable. Let’s explore why. From the for-in loop, the console log values
might surprise us. It loops over the property
in the sports car object, but the output includes
the properties on the sports car’s prototype too. Instead of just a
speed property, I also looped over the
engine and steering properties which exist on the prototype of the
sports car object, not on the sports
car object itself. In fact, as the common state, for in loops are unreliable
in this scenario because they iterate over not only
the specified object, but also its prototype. That’s why I used a thinking
emoji in my comment with a string iterating over
objects and its prototype. Now, let’s examine what came
from the second for loop, which is a for of loop. Note that our output,
the comment I had in the code for of is reliable. I’ve gotten back speed
fast, or in other words, the property and value that I’ve assigned to the
sports car object. Just as I have stated in
the comment in my code. This is because a for of
loop only iterates over the object’s own properties and does not count the
prototype at all. Hopefully, you are able
to differentiate between the for in and the for
of types of loops. Let’s run a
simplified version of the same code without
the comments. Also show my other file. This time around my
car object only has an undrawn property
then I’m declaring the sports car variable
and I’m setting the car object as the
sports car prototype. I’m also setting the speed
of the sports car as fast. Finally, I’m console logging the sports car
object and looping over prop and sports car and props of object keys
and sports car. In summary, the two
loops are simplified. I’m only console logging a
thinking emoji and the props value for the first
loop, the foreign loop. I’m only console logging
a bull’s eye emoji and the provenance value
in the for of loop. That is the second
loop in my code. When I run the code again, the result is much simpler. First, I confirm that the
sports car object only has one single property
speed, which is fast. Then the for in loop
displays speed and engine, because engine belongs
to the prototype of the sports car object and not the sports car object itself. Finally, the for of loop outputs looping over only the sports
car object properties, which in this case is
only the property fast. The emojis from my
code up here alongside these properties and help us to understand what they mean. Just to sum it up, the speed and engine properties are
from the foreign loop because it draws from
the prototype of the sports car object as
well as the object itself. The speed fast
property, however, comes from the for of loop, since that iterates over the sports car objects
property only. In this video, you learn
that when you run on objects in JavaScript
for in loops, iterate over the properties of the object and its prototype. While for of loops do this only for the
objects’ properties.
Reading: Template literals examples
Reading
The aim of this reading is to help you understand how template literals work.
What are template literals?
Template literals are an alternative way of working with strings, which was introduced in the ES6 addition to the JavaScript language.
Up until ES6, the only way to build strings in JavaScript was to delimit them in either single quotes or double quotes:
'Hello, World!'
"Hello, World!"
Alongside the previous ways to build strings, ES6 introduced the use of backtick characters as delimiters:
`Hello, World!`
The above code snippet is an example of a template string, which is also known as a template literal.
Note: On most keyboards, the backtick character can be located above the TAB key, to the left of the number 1 key.
With template literals, an expression can be embedded in a placeholder. A placeholder is represented by ${}, with anything within the curly brackets treated as JavaScript and anything outside the brackets treated as a string:
Differences between a template and regular string
There are several ways in which a template string is different from a regular string.
- First, it allows for variable interpolation:
let greet = "Hello";
let place = "World";
console.log(`${greet} ${place} !`) //display both variables using template literals
The above console log will output:
Hello World !
Essentially, using template literals allows programmers to embed variables directly in between the backticks, without the need to use the + operator and the single or double quotes to delimit string literals from variables. In other words, in ES5, the above example would have to be written as follows:
var greet = "Hello";
var place = "World";
console.log(greet + " " + place + "!"); //display both variables without using template literals
- Besides variable interpolation, template strings can span multiple lines.
For example, this is perfectly good syntax:
`Hello,
World
!
`
Notice that this can’t be done using string literals (that is, strings delimited in single or double quotes):
"Hello,
World"
The above code, when run, will throw a syntax error.
Put simply, template literals allow for multi-line strings – something that simply isn’t possible with string literals.
- Additionally, the reason why it’s possible to interpolate variables in template literals is because this syntax actually allows for expression evaluation.
In other words, this:
//it's possible to perform arithmetic operation inside a template literal expression
console.log(`${1 + 1 + 1 + 1 + 1} stars!`)
The above example will console log the following string: 5 stars!.
This opens up a host of possibilities. For example, it’s possible to evaluate a ternary expression inside a template literal.
Some additional use cases of template literals are nested template literals and tagged templates. However, they are a bit more involved and are beyond the scope of this reading.
If you’re curious about how they work, please refer to the additional reading provided at the end of this lesson.
Video: Working with template literals
Here’s a summary of the video on template literals in JavaScript ES6:
Key Points:
- Template Literals: A new way to create strings in ES6, using backticks (`) instead of single or double quotes.
- Multiline Strings: Template literals allow strings to span multiple lines without errors, unlike ES5 methods.
- Variable Interpolation: Embed variables directly into strings using
${variableName}
syntax, eliminating concatenation with ‘+’. - Quote Flexibility: Quotes within template literals are treated as regular characters, not string delimiters.
Benefits:
- Enhanced Readability: Multiline strings improve code readability and maintainability, especially for longer text blocks.
- Easier Concatenation: Variable interpolation streamlines string building, making code more concise and expressive.
- No Escaping Quotes: Eliminates the need to escape quotes within strings, simplifying syntax and reducing errors.
Example:
JavaScript
let first = `I'm a string with "quotes"`;
let second = `And I'm another one`;
let combined = `Here's a message with ${first} and ${second}.`;
console.log(combined);
Output:
Here's a message with I'm a string with "quotes" and And I'm another one.
Conclusion:
Template literals offer a powerful and flexible approach to string creation in JavaScript, enhancing code readability, maintainability, and expressiveness. Embrace them for a better coding experience!
Tutorial: Mastering Template Literals in JavaScript ES6
Unleash the Power of Strings with Backticks!
Introduction
Greetings, fellow coders! Ready to explore a more elegant and flexible way to create strings in JavaScript? ES6 introduces template literals, a game-changer that’ll make your code more readable, maintainable, and expressive. Let’s dive in!
What Are Template Literals?
- Backticks Enclose Them: Instead of single or double quotes, template literals are enclosed within backticks (`), usually located above the Tab key.
- Multiline Magic: Write strings across multiple lines without errors or concatenation hassles!
- Embed Variables Seamlessly: Use
${variableName}
within the template literal to inject variables directly into the string. - Quote Freedom: Quotes within template literals are treated as regular characters, not string delimiters. No more escaping needed!
Key Advantages:
- Enhanced Readability: Multiline strings make code more readable and easier to maintain, especially for longer text blocks.
- Concise Concatenation: Variable interpolation streamlines string building, eliminating the need for ‘+’ operators.
- Simpler Syntax: No escaping quotes means cleaner and less error-prone code.
Example Time:
JavaScript
let greeting = "Hello";
let name = "Bard";
let message = `${greeting}, ${name}! Welcome to the world of template literals.`;
console.log(message);
Output:
Hello, Bard! Welcome to the world of template literals.
Common Use Cases:
- Multiline Strings: Formatting texts for better readability.
- Building Dynamic HTML: Creating flexible HTML elements with variables.
- Constructing URLs: Assembling dynamic URLs with ease.
- Generating Code: Crafting code blocks or templates dynamically.
Tips and Tricks:
- Whitespace Preservation: Template literals maintain original whitespace, including indentation and spacing.
- Tagged Templates: Advanced feature for custom string processing (explore this later).
Conclusion
Template literals offer a powerful and versatile approach to string creation in JavaScript. Embrace them to write cleaner, more expressive, and maintainable code!
Image: [Illustration of code blocks with template literals, highlighting backticks, multiline strings, and variable interpolation]
In what ways can template literals be used to write JavaScript code more efficiently? Check all that apply:
You can create multi-line strings. You can interpolate variables. You can combine strings with less code.
Correct! Template literals can be used to create multi-line strings, interpolate variables, and to combine strings with simpler code.
In this video, I’ll guide you
through creating and using template literals
in JavaScript ES6 to understand their benefits. First, let’s revisit
strings in JavaScript ES5, which are built using single
quotes or double quotes. I have an example in my code, I’ve declared a variable, no multi-line with
the let keyword, which holds the string value, no multi-line strings in ES5. On the following line, I’m using the
console.log method to output the string did you know, followed by the
plus operator and then finally the no
multi-line variable. Recall that you can use the plus operator
for concatenation. When I run the code, I get the expected output
of did you know, no multi-line strings in ES5. This time, let’s change the value of the no
multi-line variable. To do this, I place my
cursor after the word no and press the Enter key to move part of the string
to a second line. This now spans the string
over multiple lines. If we were to run this code now, we would get the error. Also, notice that VS Code is trying to warn
us about this error by highlighting the end
of lines 3 and 4 with red text and displaying the message unterminated
string literal. This is basically JavaScript telling us that our
single line string is not coded correctly with the expected closing
double quotation symbol. Using ES5 methods, you can only create
strings using single or double
quotations and using this method does not support the use of multi-line strings. Next, let me clear the output and switch tabs in my code. Here we have some syntax that
may be unfamiliar to you. We have a variable multi-line declared with the let keyword
and it contains a string. Like the previous example, this string is distributed
across several lines. However, instead of quotes, it’s encased within
a pair of backticks. This turns it into
an ES6 expression known as a template literal. The backtick symbol is
usually located above the tab key to the left of
the one key on your keyboard. Still, it’s a good idea
to check your devices documentation as you may be using a different
keyboard layout. Using template
literals, you can add as many lines as you want
without causing errors. I can confirm this
by running my code. Notice that the output
is a multi-line string. But wait, it gets better. We can combine
template literals with variable interpolation for
even more flexibility. Once again, let me clear the output and continue
to the next tab. Here, notice I have two variables called
first and second, each containing a
single line string encased in backticks. But there’s a twist here. Each string also has a segment that sits
inside of quotes. Wouldn’t this cause
conflict you might wonder? Fortunately, that’s
not the case. By using template literals, JavaScript does not
consider quotes, a string delimiters, meaning they are just
regular characters here. Now I can use template
literals again to interpolate the variables first and
second on a different line. Instead of using the plus
operator for concatenation, I can simply enclose the full desired string
within backticks. I can then place the variable
name by enclosing it within a set of curly braces
preceded by a dollar symbol. If I run this code, JavaScript combines
everything and outputs the full string. With template literals you
don’t need to worry about the limitations of using
single and double quotes. This can make for a much
better coding experience as you just need to use backticks and variable
interpolation. That’s all for this video. Well done, you learned how to build then apply
template literals to create multiline strings and interpolate variables
in JavaScript.
Programming Assignment: Array and object iteration
README.md
Lab Instructions: Advanced JS Features
Tips: Before you Begin
To view your code and instructions side-by-side, select the following in your VSCode toolbar:
- View -> Editor Layout -> Two Columns
- To view this file in Preview mode, right click on this README.md file and
Open Preview
- Select your code file in the code tree, which will open it up in a new VSCode tab.
- Drag your assessment code files over to the second column.
- Great work! You can now see instructions and code at the same time.
- Questions about using VSCode? Please see our support resources here:
Visual Studio Code on CourseraTo run your JavaScript code
- Select your JavaScript file
- Select the “Run Code” button in the upper right hand toolbar of VSCode.
Ex: It looks like a triangular “Play” button.
Task: Iterate Over an Array
In this exercise, you’ll use the for….of loop to iterate over an array and to iterate over an object’s own properties.
Step 1. You are given an array of dairy products:
var dairy = ['cheese', 'sour cream', 'milk', 'yogurt', 'ice cream', 'milkshake']
Create a function called logDairy
. Within it, console log each of the items in the dairy array, using the for…of loop.
After you create this function, call it as logDairy()
to see the output on the console.
The expected output should be:
cheese
sour cream
milk
yogurt
ice cream
milkshake
Step 2. You are given the following starter code:
const animal = {
canJump: true
};
const bird = Object.create(animal);
bird.canFly = true;
bird.hasFeathers = true;
Create a function called birdCan
, within it, loop over the bird object’s properties and console log each one, using the for…of loop. Finally call the function as birdCan()
to see the output on the console. Remember, you need to console log both the key and the value of each of the bird object’s properties.
Expected output should be:
canFly: true
hasFeathers: true
Step 3. Using the same starter code as in task 2, create a function called `animalCan` and within it, loop over all the properties in both the bird object and its prototype – the animal object – using the for…in loop. Finally call the function as `animalCan()` to see the output on the console.
Expected outout should be:
canFly: true
hasFeathers: true
canJump: true
Final Step: Let’s submit your code!
Nice work! To complete this assessment:
- Save your file through File -> Save
- Select “Submit Assignment” in your Lab toolbar.
Your code will be autograded and return feedback shortly on the “Grades” tab.
You can also see your score in your Programming Assignment “My Submission” tab.
solution.js
// Task 1
var dairy = ['cheese', 'sour cream', 'milk', 'yogurt', 'ice cream', 'milkshake']
function logDairy() {
for (var food of dairy) {
console.log(food)
}
}
logDairy()
// Task 2
const animal = {
canJump: true
};
const bird = Object.create(animal);
bird.canFly = true;
bird.hasFeathers = true;
function birdCan() {
for (var prop of Object.keys(bird))
console.log(prop + ": " + bird[prop])
}
birdCan()
// Task 3
function animalCan() {
for (var prop of Object.keys(bird))
console.log(prop + ": " + bird[prop])
for (var prop of Object.keys(animal))
console.log(prop + ": " + animal[prop]);
}
animalCan()
Video: Data Structures
Summary of JavaScript Data Structures for Beginners:
Problem: How to write a program to calculate average grade from test results?
Key Points:
- Data structure choice: Before coding, consider how to represent data efficiently.
- JavaScript data structures: Arrays, objects, maps, and sets.
- Objects: Unordered key-value pairs, useful for storing and accessing data under specific keys (e.g., object-oriented programming).
- Arrays: Ordered collections of values, accessed by index, ideal for iterating and modifying data.
- Maps: Ordered key-value pairs, similar to arrays but any value can be a key (unlike objects limited to strings or symbols).
- Sets: Collections of unique items, adding duplicates has no effect, useful for checking for unique values.
Takeaway:
- The data structure you choose should fit the task and improve code efficiency.
- Consider different structures like arrays, objects, maps, and sets when solving any coding problem.
Next Up:
Applying these data structures to solve specific coding tasks.
JavaScript Data Structures 101: Organize Your Code Like a Pro
Welcome to the world of JavaScript data structures! In this tutorial, we’ll explore how to organize your code efficiently and strategically using JavaScript’s fundamental building blocks: objects, arrays, maps, and sets.
Why Data Structures Matter
Imagine your JavaScript code as a bustling city – data structures are like the buildings that house and manage its residents (data). Choosing the right structure is essential for:
- Efficiency: Finding the data you need quickly and easily, just like navigating to the right building in a well-planned city.
- Maintainability: Keeping your code organized and understandable, making it easier to update and expand in the future, like a city with clear road maps.
Meet the JavaScript Data Structure Squad
Here are the key players you’ll encounter:
- Objects:
- Unordered collections of key-value pairs, like a phonebook where names are keys and numbers are values.
- Ideal for storing related information and accessing it by specific keys.
- Example: Creating a
student
object with properties likename
,age
, andgrades
.
- Arrays:
- Ordered lists of values, like a numbered row of houses on a street.
- Perfect for storing sequences of items and accessing them by their position in the list (index).
- Example: Keeping a list of
studentNames
in an array to iterate through them.
- Maps:
- Similar to objects, but with more flexible keys – any value can be a key, not just strings or symbols.
- Useful for quick lookups when you need to associate unique keys with values.
- Example: Storing a map of student names and their favorite colors.
- Sets:
- Collections of unique values, like a unique set of keys to unlock different houses.
- Ensure each item is present only once, helpful for checking for duplicates or removing duplicates.
- Example: Keeping a set of unique student email addresses.
Choosing the Right Structure for the Job
Here’s a quick decision guide:
- Need to store key-value pairs with string or symbol keys? Use an object.
- Need to store a sequence of items in order? Use an array.
- Need more flexible key-value pairs with any value as a key? Use a map.
- Need to ensure unique values in a collection? Use a set.
Practice Makes Perfect
Ready to put these structures to work? Here are some exercises to get you started:
- Create an object to represent a pet with properties like name, species, and age.
- Create an array to store a shopping list and practice adding, removing, and sorting items.
- Use a map to store a collection of words and their definitions, allowing for non-string keys.
- Use a set to keep track of unique visitors to a website.
Remember, data structures are the foundation of efficient and organized code. By mastering these essential JavaScript structures, you’ll unlock a whole new level of coding prowess!
Which one of these data structures consists of iterable key-value pairs?
Maps
That’s right! Maps are made up of iterable key value pairs.
Suppose you receive some data on students
test results and your task is to write a program that outputs an average grade
from all the tests based on the raw data. Before you can code this task,
you need to consider two separate issues. First, how do you represent
the given data in your app and second, how do you called the solution? Before you even start coding a solution, you need to think about how
you will represent the data. In this video, you will learn about
some of the JavaScript’s most common data structures such as objects,
arrays, maps and sets. A data structure is
a way to organize data. For example,
you could represent it as a string. However, it would be somewhat
of a strange representation. You’d need to somehow extract the numbers
from the string before performing calculations on them. Alternatively, you could
represent it as several numbers, each number saved in a variable. Doing it this way you don’t have to
extract and convert strings to numbers. But is this the most efficient
way of storing your apps data? Perhaps another approach would be to
store all the grades in an array. This way of organizing your
data is even more efficient. It involves less typing and we’re grouping related data
together under a single label. You may recall the many
benefits of using a arrays. But what is important here is
that you understand how you code a solution to a given task depends
on how you structure your data. In other words, a solution to a coding task depends
on the data structure you use. JavaScript is somewhat limited in
the types of data structures available compared to other programming languages,
such as, Java or Python. However, some of the most common that
you will encounter are objects arrays, maps and sets. You may be familiar with
some of these already. Let’s explore each briefly. Now you may recall that
an object is unaltered, noniterable collection
of key value pairs and you use objects when you need to store and
later access a value under a key. An example of using this data
structure is when you need to write object orientated, R00P code. Similarly, you may also recall
an array which is an ordered iterable collection of values. Likewise, you use arrays
when you need to store and later access a value under an index. And remember, we do not specify the index,
JavaScript does this automatically. You only use the index to access
the specific value stored in the array. When working with arrays,
it’s common to use a loop, such as a for loop to access and edit the data. For example, to find the average grade for
the task earlier, you could loop over the array and
calculate the total sum. Then after the for loop, calculate the average by dividing
the sum by the length of the array. The next data structure is map which
is like an array because it’s iterable. However, it consists of key value pairs. It’s important not to
confuse a map with an object. With maps any value can be used as a key. With objects,
keys can only be strings or symbols. Finally, the last data structure I
want you to know about is a set. This is another collection where each
item in the collection must be unique. For example, if you try to add
a non unique item to a set, this operation will simply not be run. In other words, no errors will be thrown
and no updates will be made to a set. In this video, you learned about some of
JavaScript’s most common data structures, such as, objects, arrays, maps and sets, which one you need to use
depends on the task at hand. Next time you have a coding task, try to think of the data
structures you might use.
Reading: Data Structures examples
Reading
In this reading, you’ll learn about some of the most common examples of data structures.
The focus will be on working with the Object, Array, Map and Set data structures in JavaScript, through a series of examples.
Note that this reading will not include a discussion of some data structures that exist in some other languages, such as Queues or Linked Lists. Although these data structures (and other data structures too!) can be custom-coded in JavaScript, the advanced nature of these topics and the difficulty with implementing related exercises means they are beyond the scope of this reading.
Working with arrays in JavaScript
Previously, you’ve covered a lot of concepts related to how to work with JavaScript arrays.
However, there are still a few important topics that can be covered, and one of those is, for example, working with some built-in methods.
In this reading, the focus is on three specific methods that exist on arrays:
- forEach
- filter
- map
Let’s explore these methods.
The forEach() method
Arrays in JavaScript come with a handy method that allows you to loop over each of their members.
Here’s the basic syntax:
const fruits = ['kiwi','mango','apple','pear'];
function appendIndex(fruit, index) {
console.log(`${index}. ${fruit}`)
}
fruits.forEach(appendIndex);
The result of running the above code is this:
0. kiwi
1. mango
2. apple
3. pear
To explain the syntax, the forEach() method accepts a function that will work on each array item. That function’s first parameter is the current array item itself, and the second (optional) parameter is the index.
Very often, the function that the forEach() method needs to use is passed in directly into the method call, like this:
const veggies = ['onion', 'garlic', 'potato'];
veggies.forEach( function(veggie, index) {
console.log(`${index}. ${veggie}`);
});
This makes for more compact code, but perhaps somewhat harder to read. To increase readability, sometimes arrow functions are used. You can find out more about arrow functions in the additional reading.
The filter() method
Another very useful method on the array is the filter() method. It filters your arrays based on a specific test. Those array items that pass the test are returned.
Here’s an example:
const nums = [0,10,20,30,40,50];
nums.filter( function(num) {
return num > 20;
})
Here’s the returned array value:
[30,40,50]
Similar to the forEach() method, the filter() method also accepts a function and that function performs some work on each of the items in the array.
The map method
Finally, there’s a very useful map method.
This method is used to map each array item over to another array’s item, based on whatever work is performed inside the function that is passed-in to the map as a parameter.
For example:
[0,10,20,30,40,50].map( function(num) {
return num / 10
})
The return value from the above code is:
[0,1,2,3,4,5]
As already discussed, choosing a proper data structure affects the very code that you can write. This is because the data structure itself comes with some built-in functionality that makes it easier to perform certain tasks or makes it harder or even impossible without converting your code to a proper data structure.
Now that you’ve covered the methods, let’s explore how to work with different built-in data structures in JavaScript.
Working with Objects in JavaScript
A lot of the information on how to work with objects in JavaScript has already been covered in this course.
The example below demonstrates how to use the object data structure to complete a specific task. This task is to convert an object to an array:
const result = [];
const drone = {
speed: 100,
color: 'yellow'
}
const droneKeys = Object.keys(drone);
droneKeys.forEach( function(key) {
result.push(key, drone[key])
})
console.log(result)
This is the result of executing the above code:
['speed',100,'color','yellow']
Although this is possible and works, having to do something like this might mean that you haven’t chosen the correct data structure to work with in your code.
On the flip side, sometimes you don’t get to pick the data structure you’re working with. Perhaps that data comes in from a third-party data provider and all you can do is code your program so that it consumes it. You’ll learn more about the interchange of data on the web when you learn about JSON (JavaScript Object Notation).
Working with Maps in JavaScript
To make a new Map, you can use the Map constructor:
new Map();
A map can feel very similar to an object in JS.
However, it doesn’t have inheritance. No prototypes! This makes it useful as a data storage.
For example:
let bestBoxers = new Map();
bestBoxers.set(1, "The Champion");
bestBoxers.set(2, "The Runner-up");
bestBoxers.set(3, "The third place");
console.log(bestBoxers);
Here’s the console output:
Map(3) {1 => 'The Champion', 2 => 'The Runner-up', 3 => 'The third place'}
To get a specific value, you need to use the get() method. For example:
bestBoxers.get(1); // 'The Champion'
Working with Sets in JavaScript
A set is a collection of unique values.
To build a new set, you can use the Set constructor:
new Set();
The Set constructor can, for example, accept an array.
This means that we can use it to quickly filter an array for unique members.
const repetitiveFruits = ['apple','pear','apple','pear','plum', 'apple'];
const uniqueFruits = new Set(repetitiveFruits);
console.log(uniqueFruits);
The above code outputs the following in the console:
{'apple', 'pear', 'plum'}
Other data structures in JavaScript
Besides the built-in data structures in JavaScript, it’s possible to build non-native, custom data structures.
These data structures come built-in natively in some other programming languages or even those other programming languages don’t support them natively.
Some more advanced data structures that have not been covered include:
- Queues
- Linked lists (singly-linked and doubly-linked)
- Trees
- Graphs
For resources on building these data structures, please refer to the additional reading.
Video: Spread operator
Summary of the Spread Operator in JavaScript:
What it is:
- Introduced in ES6.
- A “magical tool” for spreading array items and joining objects.
- Represented by three dots (…).
Benefits:
- Simply copies object properties to create new objects.
- Concisely passes all array elements to functions.
- Avoids manual listing of individual array elements.
Example:
- Function takes three arguments for places to visit (place1, place2, place3).
- Calling the function with individual array elements is tedious.
- Using the spread operator before an array name (…arrayName) simplifies the call.
Conclusion:
- Spread operator makes code cleaner and more efficient.
- Applicable to both arrays and objects.
- A valuable tool for modern JavaScript development.
Mastering the Spread Operator in JavaScript: A Practical Guide
Welcome to the Spread Operator Playground! ✨ Get ready to unlock the power of this versatile tool, which can transform your JavaScript code into a masterpiece of efficiency and elegance.
Here’s the itinerary for our journey:
1. Unveiling the Spread Operator:
- Introduction: Meet the spread operator (…), a versatile tool introduced in ES6 that streamlines array and object manipulation.
- Syntax: Master its simple yet powerful syntax: three dots placed before an array or object.
2. Spreading Out Arrays:
- Expanding Arrays: Effortlessly combine multiple arrays into a single array, as if by magic!
- Passing Elements to Functions: Conquer the challenge of passing all array elements as individual arguments to functions—the spread operator handles it gracefully.
- Creating New Arrays: Craft new arrays with ease, featuring elements from existing arrays and additional items.
3. Merging Objects:
- Combining Properties: Seamlessly merge properties from multiple objects into a new object, preserving data integrity.
- Copying Objects: Safely create copies of objects without altering the originals, ensuring data consistency.
4. Advanced Adventures:
- Rest Parameter: Harness the power of the spread operator to gather remaining function arguments into an array, embracing flexibility.
- Destructuring Assignment: Extract specific elements from arrays or objects with precision, using the spread operator in destructuring patterns.
5. Hands-On Practice:
- Interactive Exercises: Reinforce your understanding through engaging coding challenges, designed to solidify your skills.
- Real-World Examples: Discover how the spread operator enhances code readability and maintainability in practical scenarios.
6. Mastering the Spread:
- Key Takeaways: Revisit the essential concepts and benefits of using the spread operator.
- Creative Applications: Explore diverse use cases and unleash your imagination to apply this powerful tool in innovative ways.
Ready to embark on this exciting adventure? Let’s spread the knowledge and transform your JavaScript skills!
The spread operator allows you to pass all array elements into a function without having to type them all individually. Is this true or false?
True
Correct! The spread operator will include all of the array elements with much less code.
The spread operator
is another of the many great new
editions that came to the JavaScript language
in its ES6 update. It is the shortest and
simplest method to copy the properties of an object
onto a newly created object. Think of the spread operator as a magical multi-purpose
tool that can spread out array items and
join objects together. In this video, you
will explore what the spread operator
is and how to use it. Note that the spread operator is characterized by three dots. To illustrate where the spread
operator becomes useful, let’s first build an array and then call the items
with a basic function. Using the variable keyword let, I create an array of the top
three places to visit on a holiday to Rome
and I call it top3. Then I include the
Colosseum, Trevi Fountain, and the Vatican City as the elements of
my top three array. Now I write a function that lists these three attractions. To keep it simple, I just
log it into the console, I create a function
and I name it, showItinerary with
three arguments, place1, place2, place3. Now I console log the
three places to visit by typing console.log and
then the string Visit, and the first argument, place1. Next, I console log the other two arguments by
first using the strings, then visit, and the
argument place2. Then the string finish
with a visit to, and the third argument place3. Then when I run the function showItinerary it should run
through all three places. Now, let’s try to run the showItinerary function with the elements in the top3 array. I write the function
name, showItinerary, and each array element
starting with top3, open square bracket zero, which is the first
element in the array, and close square bracket. Then I do the same for the other array
elements one and two. But what if I
extended my function to have seven places
that I want to visit? Let’s disregard what the showItinerary function
definition may show and imagine that I have made the necessary updates so that the function will
handle seven arguments. I have now built an
entirely new array of the top seven destinations, and I’ve saved it in a
variable named top7. Now I call the
showItinerary function and passing this function, the seven arguments
again start with zero as in top7 and zero within
square brackets. Then the array again, top7 and number one within
square brackets, and so on until we get to the last top seven
array element, which is top7 and number
6 within square brackets. While this code will work, it seems a bit impractical the spread operator simplifies
things. Let’s try it now. I type the showItinerary
function, then open parenthesis, three dots, top7, close parenthesis,
semicolon, that’s it. I use the spread operator
by placing it in front of an array which is passed to the showItinerary function. The advantage of
this approach is that you don’t have to list each individual member of the array that you want
to pass to your function. The syntax is clear, concise, and easy to type. Now, if I go back
to the top3 array, I can use it with the spread operator just like I used it for the top7 array. I type the showItinerary
function and the three dots and
the array name, top3 within parenthesis and
I end with a semicolon. The function returns
the combination of the strings and the
variables I used earlier, visit the Colosseum, then visit Trevi Fountain and finish with a visit to
the Vatican City. In this video, you explored what the spread operator is
and how you can use it.
Video: Rest operator
Summary of the Rest Operator in JavaScript:
What it is:
- Used to collect remaining function arguments into a single array.
- Opposed to the spread operator, which expands existing arrays or objects.
- Represented by three dots (…).
Benefits:
- Simplifies handling a variable number of arguments in functions.
- Enables concise construction of sub-arrays from existing ones.
- Useful for destructuring assignment to extract specific elements.
Example:
- Extracting top 3 attractions from a “top 7” vacation list:
JavaScript
const top7 = [
"Colosseum", "Roman Forum", "Vatican", "Trevi Fountain", "Pantheon",
"Piazza Venezia", "Palatine Hill"
];
const [first, second, third, ...secondVisit] = top7;
console.log(`Top 3: ${first}, ${second}, ${third}`);
console.log(`Next visit: ${secondVisit.join(", ")}`);
Other Applications:
- Multiplying values with variable tax rates.
- Building dynamic lists for various purposes.
Key Takeaways:
- Rest parameter should be the last parameter in a function.
- Use destructuring with rest operator for selective element extraction.
- The rest operator enhances code flexibility and reduces boilerplate.
Ready to Unpack the Rest Operator in JavaScript? ✨
Here’s a visual guide to mastering this versatile tool:
1. What It Is:
- Definition: Think of it as a box that collects the remaining items in an array or function arguments.
- Syntax: Represented by three dots (…) before a variable name.
2. Gathering Leftovers in Arrays:
- Extracting Sub-Arrays: Imagine a suitcase full of clothes. Use the rest operator to neatly pack specific items into a smaller bag, leaving the rest behind.
- Example:
JavaScript
const colors = ["red", "green", "blue", "yellow", "purple"];
const [firstColor, ...otherColors] = colors;
console.log(firstColor); // Output: "red"
console.log(otherColors); // Output: ["green", "blue", "yellow", "purple"]
3. Capturing Variable Arguments in Functions:
- Handling Uncertain Numbers: Picture a party where you don’t know exactly how many guests will attend. The rest operator ensures no one is left out!
- Example:
JavaScript
function greetGuests(greeting, ...names) {
names.forEach(name => console.log(`${greeting}, ${name}!`));
}
greetGuests("Welcome", "Alice", "Bob", "Charlie");
// Output: "Welcome, Alice!", "Welcome, Bob!", "Welcome, Charlie!"
4. Key Points to Remember:
- Last in Line: The rest parameter must always be the final parameter in a function’s definition.
- Destructuring Duo: Often combined with destructuring assignment for selective element extraction.
That’s it! Now you’re equipped to handle arrays and functions with ease using the rest operator. Enjoy its flexibility and code more efficiently!
The rest operator allows you to take items from an array and use them to create a separate sub-array. True or false?
True
Correct! The rest operator can be used to destructure existing array items, rather than typing them out again.
You might already know,
that a spread operator in JavaScript, is used to unpack a box, for
example, to unpack an array. The rest operator, on the other hand,
is used to build a smaller box, and pack items into it. In this video, you will explore what
a rest operator is, and how to use it. To illustrate how a rest operator can
be useful, consider a travel itinerary, I’ve realized, that there are many
things I’d love to see, while in Rome, during my vacation. Unfortunately, I’m pressed for time, and there’s no way to really
enjoy all of the attractions, even if I rush to see them all, let’s
explore how to solve this itinerary issue. In this case I can create an array of
seven places that I would like to visit, on my holiday to Rome. So I type const top7 to create the array,
and I list the seven places I would
like to go, within square brackets, with each item in double quotes,
and separated by a comma. The Colosseum, the Roman Forum,
the Vatican, Trevi Fountain, the Pantheon, Piazza Venezia,
and the Palatine Hill. To solve the problem, I decided to
organize my list in such a way, that I have my top three attractions, and
prepare another list, for a second visit. To do this, I use the rest operator, and
a technique known as de structuring, in this de structure in syntax,
I simply specify, what I want to get out of the top seven
array, in this case the first three items. So, I start by typing const, open and
closed square bracket, equal sign, top7. Then, I create three variables first,
second and third, plus another variable, to hold the rest
of the list, named secondVisit. To do this, I type const first,
second, third, and then three dots, and
a new variable, secondVisit, within Square brackets,
then equals top7, semi colon. With this syntax, I extracted
the contents of the top7 array, into four variables, the variable first,
with the value of the Colosseum. The variable second, with the value of
the Roman Forum, the variable third, with the value of the Vatican. And then I include the variable
secondVisit, that is a sub array, of the rest of the items,
in the original top7 array. If I inspect secondVisit, an array
of the four remaining attractions, Trevi Fountain, the Pantheon,
Piazza Venezia, and the Palatine Hill, are all saved as string primitives. The rest operator, therefore, gives us what is left over of the source
array, as a separate sub array. The rest operator is also useful
in functions too, in fact, I can use a rest parameter,
to quickly multiply values. I create a function,
to add the tax rate to prices, I name it, addTaxToPrices, and
give it two parameters, the tax rate and the rest operator,
with the items bought. The function returns each item with
the tax rate, in the addToTaxPrices, parameters, the rest parameter
gives me an array, so I can use array methods,
on items bought, using the map method. It’s important to know,
that the rest parameter, must be the last parameter
in the function definition. This means, that adding any other
parameter, to my addTaxToPrices function, after the rest operator, and
the items bought would result in an error. In this video,
you learned how to use the rest operator, which groups the remaining parameters in a
list, within a standard JavaScript array, well done with completing this video,
on the rest operator.
Reading: Using Spread and Rest
Reading
In this reading, you’ll learn how to join arrays, objects using the rest operator. You will also discover how to use the spread operator to:
- Add new members to arrays without using the push() method,
- Convert a string to an array and
- Copy either an object or an array into a separate object
Recall that the push() and pop() methods are used to add and remove items from the end of an array.
Join arrays, objects using the rest operator
Using the spread operator, it’s easy to concatenate arrays:
const fruits = ['apple', 'pear', 'plum']
const berries = ['blueberry', 'strawberry']
const fruitsAndBerries = [...fruits, ...berries] // concatenate
console.log(fruitsAndBerries); // outputs a single array
Here’s the result:
['apple', 'pear', 'plum', 'blueberry', 'strawberry']
It’s also easy to join objects:
const flying = { wings: 2 }
const car = { wheels: 4 }
const flyingCar = {...flying, ...car}
console.log(flyingCar) // {wings: 2, wheels: 4}
Add new members to arrays without using the push() method
Here’s how to use the spread operator to easily add one or more members to an existing array:
let veggies = ['onion', 'parsley'];
veggies = [...veggies, 'carrot', 'beetroot'];
console.log(veggies);
Here’s the output:
['onion', 'parsley', 'carrot', 'beetroot']
Convert a string to an array using the spread operator
Given a string, it’s easy to spread it out into separate array items:
const greeting = "Hello";
const arrayOfChars = [...greeting];
console.log(arrayOfChars); // ['H', 'e', 'l', 'l', 'o']
Copy either an object or an array into a separate one
Here’s how to copy an object into a completely separate object, using the spread operator.
const car1 = {
speed: 200,
color: 'yellow'
}
const car 2 = {...car1}
car1.speed = 201
console.log(car1.speed, car2.speed)
The output is 201, 200.
You can copy an array into a completely separate array, also using the spread operator, like this:
const fruits1 = ['apples', 'pears']
const fruits2 = [...fruits1]
fruits1.pop()
console.log(fruits1, "not", fruits2)
This time, the output is:
['apples'] 'not' ['apples','pears']
Note that the spread operator only performs a shallow copy of the source array or object. For more information on this, please refer to the additional reading.
There are many more tricks that you can perform with the spread operator. Some of them are really handy when you start working with a library such as React.
Practice Quiz: Knowledge check: Advanced JavaScript Features
What will print out when the following code runs?
const meal = ["soup", "steak", "ice cream"]
let [starter] = meal;
console.log(starter);
soup
That’s correct! The first item in the meal array is de-structured to the starter variable. Therefore, the code will print out soup .
The for-of loop works for Object data types.
false
That’s correct! The for-of loop must use an iterable such as arrays.
What will print out when the following code runs?
let food = "Chocolate";
console.log(`My favourite food is ${food}`);
My favourite food is Chocolate
That’s correct! The template literal will replace ${food} with Chocolate .
What values will be stored in the set collection after the following code runs?
let set = new Set();
set.add(1);
set.add(2);
set.add(3);
set.add(2);
set.add(1);
1, 2, 3
That’s correct! A Set only stores unique items.
What value will be printed out when the following code runs?
let obj = {
key: 1,
value: 4
};
let output = { ...obj };
output.value -= obj.key;
console.log(output.value);
3
That’s correct! The spread operator … will copy the properties from obj . Therefore, when output is created, it’s value property will be equal to 4. Then 1 is substracted from the value property and result is stored back in the value property. Therefore, 3 will be printed out.
What value will be printed out when the following code runs?
function count(...basket) {
console.log(basket.length)
}
count(10, 9, 8, 7, 6);
5
That’s correct! The rest operator … allows a function to accept an indefinite amount of parameters. The length property of the basket variable will return 5 because there were 5 parameters passed to the method call. Therefore, 5 will be printed out.
Reading: Additional resources
Reading
Here is a list of resources that may be helpful as you continue your learning journey.
Javascript in the Browser
Video: JavaScript modules
Summary of “JavaScript Modules: ES6 and Beyond”
Key points:
- Modules in JavaScript:
- Standalone units of code that can be reused.
- Added in ES6 to avoid issues with global functions in complex programs.
- Work by importing and exporting code between files.
- Before modules:
- All functions were global, leading to conflicts and namespace issues.
- Third-party libraries and multiple developers created challenges.
- CommonJS was an early module system, but not supported natively in browsers.
- ES6 modules in action:
- Requires a
type="module"
attribute on the<script>
tag. - Uses
import
andexport
keywords to manage code between files. - Can be run locally with a server to avoid CORS security issues.
- Requires a
- Outcomes:
- Understand the benefits and limitations of modules in JavaScript.
- Learn how to use basic ES6 modules in a browser.
Additional points:
- The video covers other module systems like CommonJS, but the focus is on ES6 modules.
- Resources for setting up a local server are provided in the additional reading.
- The tutorial emphasizes the practical application of ES6 modules in a browser environment.
# JavaScript Modules: Breaking Down Code Barriers
Welcome to this hands-on exploration of JavaScript modules!
In this tutorial, you’ll discover how to organize and reuse code effectively using ES6 modules. Get ready to:
- Understand the motivation behind modules and their benefits.
- Learn how to create, import, and export modules in practice.
- Overcome common challenges and leverage modules in browser environments.
- Explore advanced module concepts for future learning.
Let’s dive in!
Understanding the Need for Modules:
- The problem with global functions: Explore the limitations of global namespaces and how they can lead to conflicts and maintainability issues.
- Encapsulation and reusability: Discover how modules promote code organization, maintainability, and code sharing.
Creating and Using Modules:
- The
type="module"
attribute: Learn how to signal a module script in your HTML files using this attribute. - Exporting code: Use the
export
keyword to make functions, variables, and other values available to other modules. - Importing code: Bring in exported elements from other modules using the
import
keyword.
Running Modules in Browsers:
- Setting up a local server: Address CORS issues and practice running modules locally using a simple server setup.
- Troubleshooting common errors: Learn to identify and resolve common module-related errors in the browser console.
Advanced Topics (Optional):
- Dynamic imports: Explore techniques to load modules on demand at runtime.
- Circular dependencies: Understand and address potential circular dependency issues between modules.
- Module bundlers: Discover tools like Webpack and Rollup that optimize and package modules for production environments.
Throughout this tutorial, you’ll have opportunities to:
- Create your own modules and practice importing/exporting code.
- Experiment with different module setups and scenarios.
- Reinforce your understanding through interactive exercises.
Ready to take your JavaScript code organization to the next level? Let’s get started!
Which of the following statements about modules in JavaScript are true? Choose all that apply.
Modules allow for code to be reused and more easily replaced.
Correct. Modules were added to JavaScript in version ES6 and allow for code to be imported, reused and more easily replaced.
To use an ES6 module in a browser, you need to set the script type attribute to “module”
Correct. To use an ES6 module in a browser, the script’s type attribute must be set to “module”.
Modules were added to ECMAScript ES6 specification
Correct. Modules were added to JavaScript in version ES6.
Hello and welcome. Photographers often need different camera
lenses for different shooting situations. It wouldn’t be very economical
to have a separate camera for every need that arises,
fortunately most systems are modular meaning the lens can be removed and
replaced with a different one as needed. In JavaScript, complex programs can be
useful for multiple applications and it wouldn’t make sense to rewrite
them over and over thankfully. Since version ES6, they can be saved and
used elsewhere as modules in this video. You will cover what modules are in
JavaScript which includes how they work as well as their current limitations. You’ll also explore how to use
simple ES6 modules in a browser. JavaScript modules are standalone units of
code that you can reuse again and again. Being standalone means that you can add
them to your program, remove them and replace them with other modules and
everything will still work. But before we continue, let’s explore what things were like
before modules entered the picture. In all versions of JS, all functions that are defined
on the window object are global. While useful for simple projects,
this created some issues when third party libraries or
multiple developers became involved. For example,
a global function from one script could override a function from another
one using the same variable name, techniques were developed to bypass these
issues but they were not without flaws. And so for a long time, JavaScript lacked built in natively
supported module functionality. An engineer at Mozilla named
Kevin Bangor tried to fix this through a project called Server JS which
was later renamed to Common JS. CommonJS is designed
to specify how modules should work outside of
the browser environment. It is mostly used on server
side JavaScript namely node.js a downside of CommonJS is that
browsers don’t understand its syntax. That is certain keywords that CommonJS
relies on, such as require and module.exports don’t work
as expected in browsers. You can learn more about other module
systems in the additional reading but now that you know a bit of the history, let me demonstrate ES6 modules in action
to understand how ES6 modules work. We need to go back to
the humble html script tag. The script tag comes with a type
attribute which identifies the type of content that it contains. For JavaScript, it is written as script
type equals followed by text slash JavaScript in double quotes to display
text in a browser on the next line. I’ve typed console.log, followed by
the string hello from script tag in parenthesis and
then a script closing tag. I can even omit the type attribute and
use a basic script tag and the attribute will be set to
text/JavaScript by default. To make that happen I’ve input
an open script tag followed by console.log on the next line and
same sample text. I’ve been added a few more console logs
before closing off the script tag. To verify that these script tags work. I’ll open a local html file in my
browser that is linked to this code when I opened the elements
tab in the developer tools, it displays the script tags while the
console tab shows the console log output. Next let’s explore how we can use
ES6 modules in a browser before starting I will open
a separate code document. Now I’ve changed the value of the type
attribute by typing the script tag, script type equals module. I then imported a module
called greeting.js. But how do you make it work to
demonstrate I’ll open the associated html file in another browser tab. Since I’m running this file locally,
access to my script is blocked by a built in browser security feature
called cross origin resource sharing and I receive an error message
under the console tab. To eliminate this error,
I need to run the html file over a server. I can use a local server for that. For information on how to set up a local
server referred to the additional reading, now my greeting.js module
is being read in and consumed by this html document script tag. In other words, the file script tags
have successfully imported the module. In this video you have learned
about modules in JavaScript ES6. You should now have a better idea of both
their uses and their limitations and you should know how to use
basic ES6 modules in a browser.
Video: JavaScript DOM manipulation
Summary of DOM Manipulation:
- DOM is like a superpower remote for websites: It allows developers to dynamically change content, style, and structure of webpages.
- The DOM is a tree-like structure: It represents the HTML document as nested objects, mirroring the page’s elements and attributes.
- Interacting with the DOM: Developers can manipulate the DOM using:
- DevTools Elements tab: A graphical interface for inspecting and modifying elements.
- JavaScript Console: Writing code to access and update the DOM object.
- Manipulating the DOM in action:
- Create an HTML element (e.g., h2) using
document.createElement
. - Add text and attributes to the element using methods like
innerText
andsetAttribute
. - Attach the element to the DOM using
document.body.appendChild
.
- Create an HTML element (e.g., h2) using
- Benefits of DOM manipulation:
- Create interactive and dynamic webpages.
- Update content without reloading the page.
- Add custom functionality and features.
Here’s a tutorial on DOM Manipulation:
What is the DOM?
- The DOM (Document Object Model) is a tree-like representation of a webpage’s HTML structure.
- It allows developers to interact with and modify the elements of a webpage using JavaScript.
- Think of it as a blueprint or roadmap of the page, where each element (headings, paragraphs, images, etc.) is a node in the tree.
Why is DOM Manipulation Important?
- It’s the foundation for creating dynamic and interactive web experiences.
- Without DOM manipulation, webpages would be static and unchanging.
- It allows you to:
- Update content without reloading the entire page
- Add or remove elements
- Change styles
- Create animations and effects
- Respond to user interactions
How to Manipulate the DOM:
- Accessing the DOM:
- The
document
object in JavaScript is the gateway to the DOM. - It represents the entire HTML document.
- The
- Selecting Elements:
- You can target specific elements using various methods:
getElementById(id)
: Selects an element by its unique ID.getElementsByClassName(className)
: Selects elements by their class name.querySelector(selector)
: Selects the first element matching a CSS selector.querySelectorAll(selector)
: Selects all elements matching a CSS selector.
- You can target specific elements using various methods:
- Modifying Elements:
- Once you have a reference to an element, you can:
- Change its content:
element.textContent = "New text"
- Change its attributes:
element.setAttribute("attribute", "value")
- Change its styles:
element.style.property = "value"
- Add or remove classes:
element.classList.add("class")
,element.classList.remove("class")
- Show or hide elements:
element.style.display = "none"
orelement.style.display = "block"
- Change its content:
- Once you have a reference to an element, you can:
- Creating and Appending Elements:
- Create new elements using
document.createElement("elementName")
. - Add them to the DOM using methods like:
appendChild(element)
: Adds an element as the last child of another element.insertBefore(newElement, existingElement)
: Inserts an element before another element.
- Create new elements using
Common DOM Manipulation Methods:
getElementById()
getElementsByClassName()
querySelector()
querySelectorAll()
createElement()
appendChild()
insertBefore()
textContent
setAttribute()
style
classList
Example:
JavaScript
// Create a new paragraph element
const newParagraph = document.createElement("p");
newParagraph.textContent = "This is a new paragraph added with JavaScript!";
// Add it to the body of the document
document.body.appendChild(newParagraph);
Practice and Further Learning:
- Experiment with DOM manipulation in your browser’s console.
- Explore online tutorials and resources for more in-depth examples and techniques.
- Build small projects to apply your knowledge and practice common DOM manipulation tasks.
True or false? Editing the local DOM of a webpage does not affect the document stored on the webserver.
True
You are correct! The DOM is an in-memory representation of the active HTML document. Any changes made are local and do not affect the document stored on the webserver.
Did you ever think of the functions your TV
remote does for you? It allows you to make
changes to your TV. You can think of the DOM
like a TV remote that lets you change the webpage
content on the screen. It even allows you to replace only certain parts of the page, such as an image or
the heading or both. A remote however, has
certain limitations. You can only change the channel, contrast, brightness,
and volume. The DOM gives you much finer-grained control
than a TV remote ever could. For example, imagine you can
change what characters in a TV movie look like with a few simple commands while
the movie is playing. The DOM allows you to change properties of objects
on a webpage. You can think of the DOM as a superpower remote
for websites. It gives developers
power in how they can manipulate and
update webpages. The DOM is in the form of a JavaScript object with nested objects for different
parts of the page. These objects have nested
objects of their own until the entire HTML file is mapped out in what looks
like a tree structure. The DOM is the model
of the HTML file saved as a JavaScript object
in your browser’s memory. The browser automatically builds the DOM for every webpage
that it downloads. For example, if you type a URL into your
browser’s address bar, the browser would fetch the webpage that
exists on this domain. If the browser connects
to the server and it allows the browser
to download the page, it will receive
all the HTML code and save it in its memory. The browser will then
show the downloaded page. It would also build that
webpage’s DOM a model of the HTML document your
browser has just downloaded. As a developer, you
can interact with the page’s DOM to make
changes to the webpage. To interact with the DOM, you can use the Elements tab inside the browser’s DevTools. You get to the DevTools by
right-clicking anywhere in a browser window and
then by clicking “Inspect”. The Elements tab allows you
to interact with the DOM of the currently active webpage using a graphical
user interface, also known as a GUI. The browser also allows you to interact with the DOM
using JavaScript. To do this, you should click the Console tab in the
browser’s DevTools. You can focus on the
Console panel by pressing the Escape
key on your keyboard. Once done, you can start typing JavaScript commands to view
and manipulate the DOM. This is similar to how you interact with the DOM
using the Elements panel, only this time you’re
using code to do it. The entire DOM object
is saved inside the document variable and
accessible via the console. Now let me demonstrate how
DOM manipulation works. Using the document object model allows us to manipulate
live websites. For example, I’ve opened
my browser and loaded the example.com webpage
from the Internet. I want to add a
heading 2 HTML element to this webpage using the DOM. Once again, I have the
Developer Tools open in the window to the right on
the Console tab is active. It’s important to remember
that any changes I make to the DOM are relative to my browser’s local
copy of the webpage. I’m not updating the content of the live website so don’t worry, you’re not going to break it. If I reload the webpage, all changes I make to the
DOM will be lost as it will reset to the page that was downloaded
from the server. In order to create my heading 2 I need to update the
document object. To do this, I type document dot and then the
method createElement. Then inside the open
and close parenthesis, I type the name of the HTML element that
I want to create, which is wrapped
around single quotes. What I am doing here is passing the tag names as a
JavaScript string. Finally, I’m going to assign this statement to
a const variable. I type constant h2, and then the assignment
operator, I press “Enter.” Now I have successfully
built my h2 element. You may notice that
the webpage on the left has not been
updated with the heading 2. This is because although, I now have a h2 element saved
in JavaScript’s memory, I still need to attach
it to the DOM structure. Currently, it’s not a part
of the document object. Additionally, my h2 element
also needs some text. Without it, even after adding the h2 element to the document, there would not be
a visible change on the page because the
added h2 element, although, being a
part of the DOM, would have no text inside. In other words, it
would be blank. Let’s fix these two issues now. First, I’ll make some
updates to my h2 element. I’ll add some attributes and some text using the
inner text method. I can run this on
my h2 variable. I type h2.innerText
and then assign a string with a value of
this is an h2 heading. Next, I want my heading
2 element to have an ID and a class
HTML attribute. To do this, I need to use
the set attribute method. I type h2.setAttribute, which takes two parameters. The first one is the
attribute’s name, which is ID, and then the value
of the attribute. For this example, I’ll name as sub-heading and press “Enter.” Notice that inside
the parenthesis, the name and the
value are wrapped in single quotes and
separated by a comma. Next, I need to use the set
attribute method again. This time for the
class attribute. I’ve pasted the
same line of code, and now I just need to
change the word ID to class. For the value, I change this to secondary and press “Enter.” Finally, I’m ready to append
my h2 object to the DOM. First, I can test that
my code is correct by typing h2 and noticing the
HTML structure’s output. This looks good to me so
let’s add it to the DOM. I need to run the
append child method on the document body to do this. Now, I type
document.body.appendChild. Inside the parenthesis, I place my HTML structure
stored in the variable h2. Success. My object is
appended to the body of this webpage and the heading 2 text
displays in the browser. You should now be able
to explain the basics of DOM manipulation and use some of the most common DOM
manipulation methods.
Reading: JavaScript interactivity
Reading
The purpose of this reading is to introduce you to a simple explanation of web page manipulation and some examples of it.
Did you know that JavaScript’s initial purpose was to provide interactivity in the browser?
In other words, it was the “set of controls” that would allow web developers to control the behavior of the webpages and even the browsers that these webpages worked on.
This is still the case today.
As the web ecosystem developed and the world became ever more digitized, so did the myriad of ways that one can use JavaScript as a web developer to manipulate websites.
Initially, in the late 1990s, there was plain JavaScript that had to be tweaked to suit individual browsers.
Then, by the mid-2000s, the jQuery library came out, with the idea of writing less code, but doing more with it. It “leveled the playing field” as it allowed developers to use a single code-base for various browsers.
This trend continued and many other frameworks such as React, Vue, Angular, D3, and more came along.
Together with npm and Node.js, the JavaScript ecosystem is not slowing down.
Even though it has gone a long way, sometimes it’s good to go back to basics. JavaScript is still the king when it comes to making our websites interactive.
Although CSS has developed significantly over the years, it is still JavaScript that allows users to:
- Get their geolocation,
- Interact with maps,
- Play games in the browser,
- Handle all kinds of user-triggered events, regardless of the device,
- Verify form input before sending it to the backend of a webapp,
- and more!
There are many, many ways in which JavaScript allows you to build rich, interactive experiences on the web.
Video: Event handling
Key concepts:
- Events: User interactions like clicks or taps on a webpage.
- Event handlers: JavaScript functions that execute in response to events.
- addEventListener method: A way to attach event handlers to HTML elements.
- HTML event attributes: An alternative method to specify event handlers directly in HTML.
Steps to create event listeners:
- Using addEventListener:
- Select the target element using
document.querySelector
. - Create an event handler function.
- Call
target.addEventListener(event, handler)
.
- Select the target element using
- Using HTML event attributes:
- Add the event attribute (e.g.,
onclick
) to the HTML element. - Set the attribute’s value to the name of the event handler function.
- Add the event attribute (e.g.,
Example:
- Clicking the heading triggers both
handleClick
(body listener) andhandleClick2
(heading listener). - Clicking outside the heading triggers only
handleClick
.
Additional points:
- Event listeners can be attached to various elements and events (e.g., button clicks, form submissions).
- Choose the appropriate method (addEventListener or HTML attribute) based on your needs and preferences.
You are using JavaScript code on your website to listen out for events. Which of the following are examples of events that your code can listen out for? Check all that apply.
Button click. Icon tap
Let’s say you are
using a webpage on your computer and
you click a button, or you tap the like icon on a friend’s picture
on your phone. In JavaScript, the
button click and the like icon tap are examples
of user triggered events. Events are happening
all the time. You can use JavaScript code
to listen for these events. You can even choose the parts of the page on which you are
listening for events. Let me describe an example. You might want to listen for a click event on an
Add to Cart button. Once you capture such an event, you might want to run
some JavaScript code. For example, I can add a circle with the number
one on it next to the shopping cart
icon to indicate that there is now one item
in the shopping cart. If the same event gets
triggered or fired again, our event handling code
then handles the event by updating the count in the circle next to the
shopping cart icon. The circle then displays
the number two to indicate that there are
two items in the cart. In JavaScript, the
function that handles captured events is known
as the event handler. Let me demonstrate how to listen foreign event by using the
add event listener method. Okay, so I’m back in the console here and
let me demonstrate two ways to set up
an event listener for HTML elements on a webpage. One of the easiest
ways to listen for an event is to use the add
event listener method. You can do that on a
given HTML element. For example, suppose
I want to listen to the click event on the body
of this example website. First, I need to
get a reference to the body element where we
want to listen to this event. In the console of the
browser developer tools, I type document.queryselector, and then the name of the element inside of the parenthesis. For this example, its body, and I enclose
it with single quotes. Next, I want to assign the
body object to a variable. I type const target equals to assign the body
object to the target variable. I’ve named this variable target because it’s the target
of our click event. Now I can create a function that would be run when this
target is clicked. I type function handle click, and then in the function body, I console log the string,
clicked the body. The next step is to run the addEventListener method
on the target element. I type target.add EventListener. Then inside the parenthesis, I pass it two arguments. The first is the event type
click as a string value, and the second is my
handle click function. Okay, so my code is now ready. Let me test it by
clicking the webpage. Success. Notice that the text
is output to the console. In addition to the
addEventListener method, an alternative way to
listen for events is by using HTML event attributes. Before doing that,
let me first write a second click handler
function named handleClick2. Once again, I console log a string inside
the function body. This time it will output the
phrase clicked the heading. Next, I need to open
the elements panel of the developer tools and expand the view for the div element, then the heading element
should be visible. I right-click the H1 element
and click edit as HTML. Then after the H1, I create the attribute by typing onclick equals followed by my function name handleClick2 with a pair of
parenthesis at the end. Finally, I click
outside the element to save the change and return
to the Console tab. Notice that when I now click on the heading
in the webpage, the phrase clicked
the heading and clicked the body is
output to the console. Basically, this single click has triggered two different
event listeners. But notice that if I click
outside of the heading, it only triggers the
event listener that listens for clicks on
the entire body element. In this video, you learned how to write an
event listener using the addEventListener method
as well as by writing a function directly as a HTML event
attribute. Great work.
Reading: Exercise: Web page content update
Reading
In this reading, you will learn how to capture user input and process it. You’ll be introduced to a simple example that demonstrates how to manipulate information displayed based on user input.
To capture user input, you can use the built-in prompt() method, like this:
let answer = prompt('What is your name?');
Once you have the user-provided input inside the answer variable, you can manipulate it any way you need to.
For example, you can output the typed-in information on the screen, as an <h1> HTML element.
Here’s how you’d do that:
let answer = prompt('What is your name?');
if (typeof(answer) === 'string') {
var h1 = document.createElement('h1')
h1.innerText = answer;
document.body.innerText = '';
document.body.appendChild(h1);
}
This is probably the quickest and easiest way to capture user input on a website, but doing it this way is not the most efficient approach, especially in more complex scenarios.
This is where HTML forms come in.
You can code a script which will take an input from an HTML form and display the text that a user types in on the screen.
Here’s how this is done.
You’ll begin by coding out a “test solution” to the task at hand:
var h1 = document.createElement('h1')
h1.innerText = "Type into the input to make this text change"
var input = document.createElement('input')
input.setAttribute('type', 'text')
document.body.innerText = '';
document.body.appendChild(h1);
document.body.appendChild(input);
So, you’re essentially doing the same thing that you did before, only this time you’re also dynamically adding the input element, and you’re setting its HTML type attribute to text. That way, when you start typing into it, the letters will be showing in the h1 element above.
However, you’re not there quite yet. At this point, the code above, when run on a live website, will add the h1 element with the text “Type into the input to make this text change”, and an empty input form field under it.
You can try this code out yourself, for example, by pointing your browser to the example.com website, and running the above code in the console.
Remember you can access the console from the developer tools in your browser.
Another opinionated thing that you did in the code above is: setting my variables using the var keyword.
Although it’s better to use either let or const, you’re just running a quick experiment on a live website, and you want to use the most lenient variable keyword, the one which will not complain about you having already set the h1 or the input variables.
If you had a complete project with a modern JavaScript tooling setup, you’d be using let or const, but this is just a quick demo, so using var in this case is ok.
The next thing that you need to do is: set up an event listener. The event you’re listening for is the change event. In this case, the change event will fire after you’ve typed into the input and pressed the ENTER key.
Here’s your updated code:
var h1 = document.createElement('h1')
h1.innerText = "Type into the input to make this text change"
var input = document.createElement('input')
input.setAttribute('type', 'text')
document.body.innerText = '';
document.body.appendChild(h1);
document.body.appendChild(input);
input.addEventListener('change', function() {
console.log(input.value)
})
This time, when you run the above code on the said example.com website, subsequently typing some text into the input field and pressing the enter key, you’ll get the value of the typed-in text logged to the console.
Now, the only thing that you still need to do to complete my code is to update the text content of the h1 element with the value you got from the input field.
Here’s the complete, updated code:
var h1 = document.createElement('h1')
h1.innerText = "Type into the input to make this text change"
var input = document.createElement('input')
input.setAttribute('type', 'text')
document.body.innerText = '';
document.body.appendChild(h1);
document.body.appendChild(input);
input.addEventListener('change', function() {
h1.innerText = input.value
})
After this update, whatever you type into the input, after pressing the ENTER key, will be shown as the text inside the h1 element.
Although this completes this lesson item, it’s important to note that combining DOM manipulation and event handling allows for some truly remarkable interactive websites.
Reading: Exercise: Capture Data
Reading
Description
The aim of this exercise is to access the content of an element, specifically to use a button click to replace text.
Task 1: The example.com website
Open the example.com website in your browser. Open the developer tools and focus on the Console tab.
Example.com is a domain that can be used as an example in documents, papers and websites.
If you navigate in your browser to http://www.example.com you will see a webpage with a simple message:
Example Domain
This domain is established to be used for illustrative examples in documents. You may use this domain in examples without prior coordination or asking for permission.
Task 2: Get h1 into a variable
Use the document.querySelector() method to query the h1 element on the page and assign it to the variable named h1.
Task 3: Code an array
Declare a new variable, name it arr, and save the following array into it:
[
'Example Domain',
'First Click',
'Second Click',
'Third Click'
]
Task 4: Write a click-handling function
Write a new function declaration, named handleClicks. It should not accept any parameters.
Inside of it, code a switch statement, and pass a single parameter to it, h1.innerText.
The body of the switch statement should have a total of 4 cases (the fourth being the default case).
The first case should start with case arr[0]:. It should set the h1.innerText to arr[1]. In other words, it should assign the value of arr[1] to the h1.innerText property. The next line should have only the break keyword.
The second case should start with case arr[1]:. It should set the h1.innerText to arr[2]. In other words, it should assign the value of arr[2] to the h1.innerText property. The next line should have only the break keyword.
The third case should start with case arr[2]:. It should set the h1.innerText to arr[3]. In other words, it should assign the value of arr[3] to the h1.innerText property. The next line should have only the break keyword.
The default case should set the value of the h1.innerText property to arr[0].
Task 5: Add an event listener
You’ve created an h1 variable in Task 2. Now, use that variable to run the addEventListener() method on it. Pass two arguments to the addEventListener() method: ‘click’ and handleClicks.
Reading: Solution: Capture Data
Reading
Task 1 solution: The example.com website
- Open your favorite browser and navigate to https://example.com/.
- Next open its developer tools using either the F12 key, or right-clicking onto the page and selecting the contextual menu’s Inspect command, or by pressing CTRL SHIFT I or COMMAND SHIFT I.
- Next, click on the Console tab to open it in a dedicated tab, or press the ESC key to have the console open while any tab is in focus.
Task 2 solution: Get h1 into a variable
var h1 = document.querySelector('h1')
Task 3 solution: Code an array
var arr = [
'Example Domain',
'First Click',
'Second Click',
'Third Click'
]
Task 4 solution: Write a click-handling function
function handleClicks() {
switch(h1.innerText) {
case arr[0]:
h1.innerText = arr[1]
break
case arr[1]:
h1.innerText = arr[2]
break
case arr[2]:
h1.innerText = arr[3]
break
default:
h1.innerText = arr[0]
}
}
Task 5 solution: Add an event listener
h1.addEventListener('click', handleClicks);
Reading: Moving data around on the web
Reading
The modern web consists of millions and millions of web pages, connected services and databases.
There are websites communicating with other websites, getting data from data feeds and data providers, both paid and free.
All of these data flows must be facilitated with some kind of data format.
Around 2001, Douglas Crockford came up with a data interchange format based on JavaScript objects. The name given to this format was JSON, which is JavaScript Object Notation.
Before JSON, the most common data interchange file format was XML (Extensible Markup Language). However, due to XML’s syntax, it required more characters to describe the data that was sent. Also, since it was a specific stand-alone language, it wasn’t as easily inter-operable with JavaScript.
Thus, the two major reasons for the JSON format becoming the dominant data interchange format that it is today is two-fold:
- First, it’s very lightweight, with syntax very similar to “a stringified JavaScript object”. You’ll learn more about the specifics of this later.
- Second, it’s easier to handle in JavaScript code, since, JSON, after all, is just JavaScript.
It is often said that JSON is a subset of JavaScript, meaning it adheres to syntax rules of the JavaScript language, but it’s even more strict in how proper JSON code should be formatted. In other words, all JSON code is JavaScript, but not all JavaScript code is JSON.
Besides being a data interchange format, JSON is also a file format. It’s not uncommon to access some third-party data from a third-party website into our own code in the form of a json file.
For example, if you had a website with the data on stock price movements, you might want to get the data of the current stock prices from a data vendor. They might offer their data service by giving you access to the file named, say stockPrices.json, that you could access from their servers.
Once you’d downloaded that stringified JSON data into your own code, you could then convert that data to a plain JavaScript object.
That would mean that you could use your web application’s code to “dig into” the third-party data-converted-to-a-JavaScript-object, so as to obtain specific information based on a given set of criteria.
For example, if the stringified JSON data was converted to an object that had the following structure:
const currencyInfo = {
[
USD: {
// ...
},
GBP: {
// ...
},
EUR: {
// ...
}
]
}
You could then access only the data on the USD property, if that’s what was needed by you app at a given point in time.
Hopefully, with this explanation, you understand, at a high level, how and why you might want to use JSON in your own code.
It’s all about getting stringified JSON data from a server, converting (“parsing”) that data into JS objects in your own code, working with the converted data in your own code, and perhaps even stringifying the result into JSON, so that this data is then ready to, for example, be sent back to a server after your code has processed it locally.
JSON is just a string – but there are rules that it must follow
JSON is a string, but it must be a properly-formatted string. In other words, it must adhere to some rules.
If a JSON string is not properly formatted, JavaScript would not be able to parse it into a JavaScript object.
JSON can work with some primitives and some complex data types, as described below.
Only a subset of values in JavaScript can be properly stringified to JSON and parsed from a JavaScript object into a JSON string.
These values include:
- primitive values: strings, numbers, bolleans, null
- complex values: objects and arrays (no functions!)
- Objects have double-quoted strings for all keys
- Properties are comma-delimited both in JSON objects and in JSON arrays, just like in regular JavaScript code
- String properties must be surrounded in double quotes. For example: “fruits”, “vegetables”
- Number properties are represented using the regular JavaScript number syntax; e.g 5, 10, 1.2
- Boolean properties are represented using the regular JavaScript boolean syntax, that is: true and false
- Null as a property is the same as in regular JavaScript; it’s just a null
You can use object literals and array literals, as long as you follow the above rules
What happens if you try to stringify a data type which is not accepted in JSON syntax?
For example, what if you try to stringify a function? The operation will silently fail.
If you try to stringify some other data types, such as a BigInt number, say 123n, you’d get the following error: Uncaught TypeError: Do not know how to serialize a BigInt.
Some examples of JSON strings
Finally, here is an example of a stringified JSON object, with a single key-value pair:
‘{“color”:“red”}‘
Here’s a bit more complex JSON object:
‘{“color”:“red”, “nestedObject”: { “color”: “blue” } }‘
The above JSON object encodes two properties:
- “color”:”red”
- “nestedObject”: { “color”: “blue” }
It’s also possible to have a JSON string encoding just an array:
‘[“one”, “two”, “three”]’
The above JSON string encodes an array holding three items, three values of the string data type. Obviously, just like objects, arrays can nest other simple or complex data structures.
For example:
‘[{ “color”: “blue” }, {“color: “red”}]’
In the above example, the JSON string encodes an array which holds two objects, where each object consists of a single key-value pair, where both values are strings.Go to next item
Video: JavaScript Object Notation – JSON
Converting JSON Strings to JavaScript Objects:
- Use
JSON.parse(jsonString)
to convert a JSON string into a JavaScript object. - This allows you to access and manipulate the object’s properties and methods.
Converting JavaScript Objects to JSON Strings:
- Use
JSON.stringify(object)
to convert a JavaScript object into a JSON string. - This is useful for sending data to APIs or storing it in a format that can be easily parsed.
Key Points:
- JSON strings are essentially objects represented as strings with specific formatting.
- JavaScript objects can hold functions, while JSON strings cannot.
- Valid JSON does not allow JavaScript comments.
- Methods are excluded when stringifying a JavaScript object.
Common Use Cases:
- Retrieving data from APIs often involves converting JSON strings to JavaScript objects for easier manipulation.
- Sending data to APIs or storing it in a structured format often requires converting JavaScript objects to JSON strings.
You can convert a JSON file to a JavaScript object so that you can work with that object's properties.
True
Correct. When working with JSON it is common to convert it back to a JavaScript object to work with its properties. To do this you need to use the global built-in JSON object and its parse method.
In this video will help you learn to
convert a JSON string to a regular JavaScript object and vice versa. If you type a piece of JSON code
into your browser’s console, it should not produce any errors. For example, a JSON string with one
property named greeting that contains the value of the string hello. If I run this code,
I get back the same result. It’s worth remembering that JSON is
basically just an object represented in the form of a string. It has some specific formatting but
it’s a string nonetheless. So to work with JSON, it is common to
convert it back to a JavaScript object to work with its properties and methods. To do this you need to use
the global built in JSON object and its parse method,
let me demonstrate this now. First I will sign the JSON
string to a variable named JSONstr using the const keyword. Next I’ll run the JSON parse
method on this variable by typing JSON.parse and
then JSONstr inside the parentheses. I press enter and notice that a regular
JavaScript object is returned. I want to save this object as a variable. So I assigned the JSON parse method
to a variable named aPlainObj using the const keyword. Okay, so now that my JSON string is
stored in a regular JavaScript object. I can manipulate it just like
any other JavaScript object. Let me demonstrate this now by reassigning
the value of the greeting property, I type the object name followed by a dot
and then the object property equals hi. Press enter and
notice that the word hi is output. I can confirm this by
inspecting the object and notice that its structure
has been updated. Okay, that’s how you convert a JSON
string to a JavaScript object. You can also go the other way and
convert a regular object to a JSON string. Using the string of my
method of the JSON object. Let me demonstrate this now. For example, let’s start by
declaring an object named data and assign it some properties and values. To run the JSON string of
my method on this object, I’ll type JSON.stringfy and place
the objects name inside the parentheses. The result is a JSON string. Notice that both the objects keys and its values are double quoted
strings in the JSON syntax. It’s important to remember that while
plain JavaScript objects can hold functions, JSON strings cannot. Another limitation is that valid JSON
doesn’t allow the use of JavaScript comments. Also when you stringfy a JavaScript
object containing a method, that method will be excluded
from the stringfy operation. In this video you have learned how to
convert a JSON string to a JavaScript object with the parse method. And how to convert a JavaScript object to
a JSON string using the stringfy method. If you work with retrieving data from APIs
converting the JSON strings to JavaScript objects will be a standard workflow. You can then easily access the objects
properties programmatically this is a vital tool in your tool belt, and
I encourage you to practice this.
Practice Quiz: Knowledge Check – JavaScript in the browser
In the following code, the type attribute can be omitted.
<script type="text/javascript">
//Comment
</script>
true
That’s correct! type=”text/javascript” is the implicit value of the script tag when it is omitted.
What does the document variable return in JavaScript?
console.log(document);
The entire webpage in the browser’s memory, as a JavaScript object.
That’s correct! The document object holds the entire structure of the active webpage in the browser’s memory.
What does the following function return?
getElementById('main-heading')
The first element that has the id attribute with a value main-heading
After the following code is run, what will happen when the user clicks on a p element in the browser?
document.querySelector('h1').addEventListener('click',
function() {
console.log('clicked');
});
Nothing.
That’s correct! The click event listener is registered on h1 elements.
What will be printed when the following code runs?
var result = {
value: 7
};
console.log(JSON.stringify(result));
{“value”: 7}
That’s correct! JSON.stringify will turn the object into a string representation. The property name is wrapped in double quotes in the representation.
Video: Module summary: Programming Paradigms
Key Topics:
- Functional Programming: Separating data and functions to solve problems.
- Object-Oriented Programming (OOP): Using objects and classes to organize code.
- Scope: Visibility of variables within different code blocks.
- Object Construction: Building objects using classes and constructors.
- Inheritance: Extending functionalities from parent to child objects.
- Modern JavaScript Features: Spread, rest, template strings, and modules.
- DOM Manipulation and Event Handling: Building interactive web pages.
- JSON: Data format for transferring and storing information.
Key Takeaways:
- Understanding different programming paradigms allows for more efficient and maintainable code.
- Functional programming emphasizes functions and immutability, while OOP focuses on objects and encapsulation.
- Scope control is crucial for preventing variable conflicts and unexpected behavior.
- Objects and classes provide structured code organization and reusability.
- Inheritance facilitates sharing functionalities across related objects.
- Modern JavaScript features offer enhanced coding capabilities.
- DOM manipulation and event handling create responsive web interfaces.
- JSON is a widely used format for data exchange.
Overall:
This module covered a comprehensive range of topics related to programming paradigms in JavaScript, equipping you with essential knowledge for effective development.
You’ve reached the
end of this module on programming paradigms.
Great work. During this module, you
explored the core features of functional programming and
object-oriented programming. Let’s review the module by summarizing the major
items you encountered. The various styles of computer languages are known
as programming paradigms. Having studied programming
paradigms in this module, you should be able to describe functional programming
and how it can be used to
solve a problem by separating data from functions. Having explored
functional programming, you moved on to another
popular paradigm. Object-oriented programming,
often referred to as OOP. You discovered how OOP differs from functional
programming. You studied object-oriented
programming principles. In programming, scope
determines which parts of the code are accessible and
which parts are inaccessible. You learned how the scope
of variables changes when you use the keyword
Var in ES5 JavaScript, and when you use the keywords, Let and Const in ES6 JavaScript. You should now be
familiar with how the scope chain
works in JavaScript. You should also now be able to identify how some of the
different types of scope work, including global and local. Much of the development work in JavaScript involves
building objects. Classes are essentially
a blueprint that you can repeatedly use to
build new objects. You can also pass parameters to the class methods and then use them the same as with
regular functions. Constructors tell JavaScript how you want your
objects to be built. You should now be
able to utilize constructors on built-in
JavaScript objects. You learned that inheritance
exists in JavaScript, and the inheritance model
revolves around the prototype. Additionally, you explored how JavaScript code uses modern
features like spread, rest, template
strings, and modules. You build code that manipulates the DOM and handles events. Finally, you used
JSON in JavaScript. That was a lot to cover, but you should now be
more familiar with programming paradigms in
JavaScript. Great work.
Quiz: Module quiz: Programming Paradigms
Variables declared using ‘let’ can be reassigned.
true
That’s correct! Variables declared using let cannot be redeclared but can be reassigned.
What will print out when the following code runs?
function scopeTest() {
var y = 44;
console.log(x);
}
var x = 33;
scopeTest();
33
That’s correct! x is defined in the global scope before the console.log is called.
What will print out when the following code runs?
class Cake {
constructor(lyr) {
this.layers = lyr;
}
getLayers() {
return this.layers;
}
}
class WeddingCake extends Cake {
constructor() {
super(2);
}
getLayers() {
return super.getLayers() * 5;
}
}
var result = new WeddingCake();
console.log(result.getLayers());
10
That’s correct! The WeddingCake constructor stores the amount of layers as 2. However, WeddingCake overrides the getLayers() function to multiple the result by 5. Therefore, 10 is outcome.
What will print out when the following code runs?
class Animal {
}
class Dog extends Animal {
constructor() {
this.noise = "bark";
}
makeNoise() {
return this.noise;
}
}
class Wolf extends Dog {
constructor() {
super();
this.noise = "growl";
}
}
var result = new Wolf();
console.log(result.makeNoise());
growl
That’s correct! The noise property is overridden when the Wolf constructor is called.
Consider this code snippet: ‘const [a, b] = [1,2,3,4] ‘. What is the value of b?
2
That’s correct! The value b is assigned the second item value of the array through de-structuring.
What value will be printed out when the following code runs?
function count(...food) {
console.log(food.length)
}
count("Burgers", "Fries", null);
3
That’s correct! The rest operator … allows a function to accept an indefinite amount of parameters. The length property of the food variable will return 3 because there were 3 parameters passed to the method call. The value null counts as a parameter. Therefore, 3 will be printed out.
Which of the following are JavaScript methods for querying the Document Object Model? Select all that apply.
getElementsByClassName
That’s correct! getElementsByClassName will return all elements with the specified class.
getElementById
That’s correct! getElementById will return the first matching element with the specified ID.
querySelector
That’s correct! querySelector will return all elements matching the specified CSS selector.
Which of the following methods convert a JavaScript object to and from a JSON string?
JSON.parse
That’s correct! JSON.parse will convert a JSON string to a JavaScript object.
JSON.stringify
That’s correct! JSON.stringify will convert a JavaScript object to a JSON string.
What will be the result of running this code?
const letter = "a"
letter = "b"
Uncaught TypeError: Assignment to constant variable
That’s correct. You cannot reassign a variable assigned using the const keyword.
What is a constructor?
A function that is called to create an instance of an object.
Correct. A constructor function details how an object will be built using the keyword new.
Reading: Additional resources
Reading
Here is a list of resources that may be helpful as you continue your learning journey.
Nodejs.org official docs on CommonJS