sábado, 22 de abril de 2023

C2 - PROGRAMMING WITH JAVASCRIPT - COURSE 2/9

  META FRONT END DEVELOPER PROFESSIONAL CERTIFICATE

PROGRAMMING WITH JAVASCRIPT



ossibilities with modern JavaScript technologies. Finally, you will learn about the practice of testing code and how to write a unit test using Jest.

Meta

Meta builds technologies that help people connect with friends and family, find communities, and grow businesses. The Meta Professional Certificates create opportunities so that anyone regardless of education, background or experience can learn high-quality skills to land a high-growth career—no degree or experience required to get started. Meta also offers training courses on the metaverse to educate people, brands, businesses and professionals on the opportunities it presents and what it means for our world today and into the future.

WEEK 1 - Introduction to Javascript

In this module, you are introduced to JavaScript. You'll learn why JavaScript is so integral to software development. And you'll get an overview of how to write JavaScript code inside the browser. Furthermore, you will learn about the most common operators as well as conditional statements and loops. After completing this module, you will have completed the following learning objectives:

Course syllabus

This course is the second of a series that aims to help you learn more about web development. 

In this course, you will explore the following:

Module 1: Introduction to JavaScript
In this module, you are introduced to JavaScript. You'll learn why JavaScript is so integral to software development. And you'll get an overview of how to write JavaScript code inside the browser. Furthermore, you will learn about the most common operators as well as conditional statements and loops.

After completing this module, you will be able to:
  • Explain the importance of JavaScript in software development
  • Demonstrate how to write JavaScript code inside the browser
  • Demonstrate how to write basic JavaScript code
  • List common operators, conditional statements and loops
  • Demonstrate how to use variables and output their value in the console
Module 2: The building blocks of a program
Here you'll learn how to use objects, arrays and functions. In addition, you will learn about the most common built-in methods, and the difference between undefined, null and empty strings. And you'll explore both error handling and defensive programming.

After completing this module, you will be able to:
  • Build and use objects, arrays, and functions
  • List some common built-in methods on built-in objects
  • Describe handling bugs and errors using try, catch, throw, and defensive programming
  • Explain the difference between undefined, null, and empty strings  
  • Demonstrate how to write basic code using arrays, objects and functions   
Module 3: Programming paradigms
This module is about functional programming and the object 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:
  • 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
  • Write JavaScript code using more modern features like spread, rest, template strings and modules
  • Build code that manipulates the DOM and handles events
  • Use JSON in JavaScript
Module 4: Testing and compatibility
Here you will learn about Node.js and npm. And you will explore how to install npm packages and how to work with package.json. Furthermore, you will learn about testing in JavaScript and you'll code a simple unit test in Jest.

After completing this module, you will be able to:
  • Describe Node.js and npm
  • Explain how to install npm packages
  • Describe how to work with package.json
  • Explain the process of testing in JavaScript
  • List the three most prevalent kinds of testing
  • Demonstrate how to code a simple unit test in Jest
Module 5: Graded assessment
In the final module, you'll learn about the graded assessment. After you complete the individual units in this module, you'll synthesize the skills you gained from the course to create code for the "Little lemon receipt maker ". 

You'll also have to opportunity to reflect on the course content and the learning path that lies ahead.    


How to Position Yourself for a New Career

You are well on your way to becoming a software developer.

You took the most important first step: you started.

While this specialization on Coursera will make you into a well-rounded junior developer, you are basically just getting started.

Here are some proven tips to make the transition to your new career as smooth as possible.

Be persistent
Succeeding in your career efforts is not easy. Luckily, it's not too hard either. Consider this new endeavor of learning to code a part of your everyday life.

Make it as much of a routine as possible. Hopefully, it will work like this: 
  • You wake up, 
  • You brush your teeth, 
  • You run some errands, 
  • And then you write and learn to code.
Obviously, there are things like your school obligations, or your day job, or other places you need to be and things you need to do.

However, if you don't code regularly - preferably on a daily basis - your progress will be slower. Try to set aside some time to consistently code and learn every day. Persistence is key.

Start building simple apps today
Don't wait until you "learn enough". There's always more to learn, and it's best to get started with any kind of a simple project right now.

Even just taking the code from this specialization and tinkering with it will do wonders for your confidence and the speed at which you acquire new knowledge.

Also, the more you practice, the better you'll retain what you've learned.

Having your own projects that you can showcase to others - no matter how small or straightforward shows a track record and dedication. This is something that your future employer might be impressed with, so start today.

Set up a GitHub account
Since we're on the topic of personal projects, head on over to GitHub and set up your developer profile right away. It's essential to have an account there since you can keep all your projects in a single location that you can access from any computer.

You can almost think of your GitHub account as an additional brain power. No matter how long ago, whatever you've worked on will remain there, waiting for you to peek into and re-familiarise yourself with.

Pair program
Try to find someone at your level or perhaps slightly more knowledgeable than you and ask them to set up a recurring pair programming session.

This works nicely because having a pair programming partner can speed up your learning. You also have someone to be accountable to.

Start a coding blog
Technical communication is important for developers, and just like anything else, you get better with practice.

Starting a coding blog will work the same as having a GitHub account, with some the additional benefits: 
  • It shows even more dedication - and this increases your chances of getting hired 
  • It helps you experiment with different technologies 
  • Setting up your own website is practical learning in its own right and one more project to add to your CV
Collaborate on open source projects
Even if you are just starting out and are really struggling to get into this field, you can still be a valuable contributor to open-source projects. 

There are so many open-source projects that are in demand for all kinds of contributors. 

Even contributing to a project by fixing some typos in documentation files is a nice start to getting more involved and putting yourself out there.

Get a certificate
Getting certified is always a good thing. The fact that you're reading this lesson right now confirms that you're on your way to receiving a certificate of completion from Coursera!

Keep a positive attitude
As with anything worth doing, you might sometimes get tired, not understanding how something works, and perhaps even feel like giving up.

Remember to stay consistent.

There are always ups and downs in life, but sometimes it's worth it to think of all the things you've achieved so far and use that as motivation to keep at it.

Never stop learning
There's always more to learn in IT, and that's probably the best thing about it. It's the very thing that makes it fun and provides an opportunity for each developer to get ahead in their career.

How to uncover job opportunities

Learning how to program in JavaScript helps you prepare for a wide range of job opportunities. This is in part because it expands the possibilities of what you can build as a developer. 

JavaScript is one of the most in-demand programming languages, as it is used in nearly all active websites. Its versatility enables developers to use popular libraries, plugins, and frameworks such as React, which improves efficiency and productivity.

With all flexibility that programming in JavaScript brings, it is no surprise that there are different careers that you might want to follow. However, no matter what career path you choose, you will always want to learn other technologies like HTML, CSS, React, Node.js, or Python, so you are more marketable. 

Let’s cover a few of the most common roles you can get if you know how to program in JavaScript. 

Mobile Developer
There has been a constant increase in the demand for mobile developers as mobile devices’ use for accessing the internet has been on the rise. Mobile developers specialize in building apps for platforms like Google’s Android and Apple’s iOS. Many developers choose to use React Native, which allows them to build one application using JavaScript that works on both Android and iOS devices. Mobile developers work with UX and UI designers and use React’s UI capabilities to implement functionalities that customers will use. Mobile developers also make sure that the front-end and the back-end of the applications work seamlessly. Other skills that mobile developers may have include HTML, CSS, Java, Kotlin, Objective-C, C++, C#, among others. 

Front-End Developer 
As the name implies, front-end developers build the user-facing parts of websites and apps. They work closely with designers to implement visual and interactive elements through coding, using HTML, CSS, and of course, JavaScript. They also use libraries and frameworks like React to save time and make their work more efficient. Front-end developers may also be responsible for making sure the final user has a good user experience and that websites and apps behave as expected and are free of errors and bugs. 

Back-End Developer 
Back-end developers work on the back-end of websites and applications. They can use JavaScript with Node.js to develop back-end functionalities. Among these functionalities are streaming and chat-based applications, as well as JSON APIs and serverless functions. Back-end developers possess additional skills, including professional working knowledge of Python, APIs, cloud infrastructure, and database. 

Full-Stack Developer 
As you might guess, a full-stack developer works with both the front- and back-end of building websites and apps. So, these professionals combine the skills in these two areas. They can use frameworks like React to work on the front-end and Node.js to work on the back-end. They also apply skills in addition to JavaScript to build websites and apps.

Your professional journey ahead
As you embark on the exciting career as a professional developer, you will realize that you will progressively expand your skills to include a wide range of technologies and programming languages besides JavaScript.

If you want to have an idea of the opportunities available in these areas, you might want to check your favorite job search website or app and look for jobs related to JavaScript. You will learn that there is no shortage of opportunities. And as you start reading more about these roles, you will find that JavaScript is often only one of the competencies that employers are looking for. 

But don’t worry, as you advance in your studies and in your career, you will further develop your skills to focus on the professional path you want to follow. 

Good luck on your professional journey!

Writing your first Javascript code

In this reading, you'll learn about comments in JavaScript. Additionally, you'll learn about the semi-colon in JavaScript: what it does and why it is used. You will then download a browser if you don't have one installed and run your first piece of JavaScript using the Console.

Comments in JavaScript
I've chosen comments as the starting point for two reasons: 
  1. Their syntax - the way comments are written is easy to understand. 
  2. Writing comments can empower you as a developer.
First, I'll explain the syntax, and after that, I'll discuss why being able to write comments is so empowering.

Comments in JavaScript: the syntax
There are two varieties of comments in JavaScript: 
  1. Single-line comments 
  2. Multi-line comments
A single-line comment is created when you add two forward-slash characters one after the other, without spaces. 

// this is a comment!

Anything that follows a single-line comment in JavaScript is ignored by the browser.

This means that, essentially, you can write any kind of text, code, characters, emojis, whatever - and the browser will ignore it.

A multi-line comment, as its name says, spans for several lines of code and is created with a forward slash and a star. For example: 

/*
this
is
a
multi-line
comment
*/

You can also use the multi-line comment syntax on a single line of code, as follows: 

/* this is a multi-line comment on a single line */

Why writing comments is empowering
In this course, it is assumed that you've never written a single line of JavaScript code.

With this assumption in mind, consider the effects of what you've just learned, that is, the effects of learning how to write comments in JavaScript: 
  1. You can now freely express your ideas about any code that you write. 
  2. You can add comments to any code that already exists.
  3. Those comments can be intended for your future self, or for colleagues on your development team.
So, comments are empowering because they facilitate communication with your future self or with your team members, allowing you to ask questions about the code, mark the code as "to do", or as "to improve", or just simply explain what a given piece of code does. 

Additionally, you can even comment out some working code in a JavaScript file - to prevent it from running.

Effectively, comments allow you to "switch off" pieces of JavaScript code.

There can be many reasons for that: 
  1. Trying to understand how a given piece of code works.
  2. Testing different solutions to a coding problem - while not having to delete existing code.
  3. Debugging - trying to pin-point why your code is broken or behaving unprediticably.
The semi-colon in JavaScript
In the English language, the fullstop or period - the . character - is used to separate thoughts into sentences.

By clearly separating thoughts with the fullstop, you avoid being misunderstood.

In JavaScript, the semi-colon - the ; character - has a similar purpose: it is used to clearly delimit parts of the code from some other parts of the code.

Automatic Semi-Colon Insertion (ASI)
Interestingly, the browser has a feature known as "Automatic Semi-colon Insertion" - meaning, it does a pretty good job of "filling in the blanks" in case there is a missing semi-colon where there should be one.

Effectively, what that means for developers is that most of the time, it makes no difference if a semi-colon is added or not, since the browser is likely to figure it out anyway.

That's why some developers say that you shouldn't bother with adding semi-colons at all.

However, other developers argue that it's better to use it wherever it's needed - for the sake of clarity.

The truth is that most of the time, you can think of adding semi-colons in JavaScript as optional - and somewhat of a stylistic preference.

A note on using the console in the developer tools in your browser
As already mentioned earlier on in this course, one of the reasons why JavaScript is so popular is because it's so approachable.

To get started with JavaScript, all you need is a browser. In this course I'll be using Google Chrome.

Once you've installed the browser and run it, right-click on the currently active web page and click the Inspect command on the right-click contextual menu.

This will open the Developer Tools and then you can click on the Console tab to open the console, or alternatively, pressing the ESC key will toggle on and off the console regardless of the currently active Developer Tools panel.

You can type any JavaScript command you like into the DevTools console.

If you need to type multiple lines of code before you run them, make sure to press the SHIFT + ENTER shortcut key to get onto the next line.

Notice the distinction between pressing the ENTER key to run the JavaScript code you've typed, versus pressing the SHIFT + ENTER shortcut to move onto the next line of code (rather than running the code you've already typed up).

This is all that you need to get started writing JavaScript code!

In the upcoming lessons, feel free to follow along in either of two ways: 
  1. Using the VS Code editor and the Code Runner extension as previously described 
  2. Using the Chrome browser itself, and running the code inside the DevTools console as described in this reading
Output a greeting into the console
Now that you know how to get to the Developer Tools' Console tab, let's now use it to run your first piece of real JavaScript code.

In Chrome, with the Developer Tools open, click into the empty space in the console tab, just to the right of the blue > character. You should see a blinking vertical line (also referred to as "the cursor"). The cursor indicates that you can type into the console.

If you type valid JavaScript code, it will be executed, meaning: it will be processed and it might result in some kind of output.

You'll now use the console.log function to output the words "Hello, World".

To do so, type the following command into the console: 

console.log("Hello, World");


If you've done everything as instructed, the words "Hello, World" should be output in the console.

Here's another, more complex command, to show you that the console.log command comes with a number of tricks.

For example, did you know that you can style the output in the console?

In this code snippet, there are a few additions: the font size is different and the color is blue: 

console.log("%cHello, World""color: blue; font-size: 40px");

If you copy-paste this piece of code, or perhaps, simply type it into the console, once you press the ENTER key to run it, you'll get the words "Hello, World" output to the console. This time, however, the color of the letters will be blue, and the font size will be 40px. So, you've just learned a nice trick with the console. 

If you add the %c right after the " character, you can then style the console output by adding the , character after the second ", and then, inside another pair of " and " characters, use valid CSS code to style the words you want to output in the console.

The reason for showing you this little trick was to hopefully get you motivated to practice writing various words into the console.log command, and to use your CSS skills to change the styling of these words in the console output. That way, you might find it fun to practice this newly acquired skill - and learning and fun always go nicely together.

Output multiple words into the console
To output multiple words into the console, you can join them using the + character, formally known as the "concatenation operator" when we're joining pieces of text, or the "addition operator", for performing the mathematical operation of adding two numbers. 

Here is an example of joining three separate pieces of text: console.log("Hello " + "there, " + "World").
The output of this command will be: Hello there, World.

Here is an example of outputting three separate pieces of text using the , character instead:

console.log("Hello ", "there, ", "World")

The output of this command will still be: Hello there, World.

Exercise: Declaring variables

In this exercise, you will practice declaring variables.

To check the output of your code, please enter it into the text box provided and click the "Run" button. This will execute the code and display the resulting output.

Tasks
  1. Declare a new variable named petDog and give it the name Rex.
  2. Declare a new variable named petCat and give it the name Pepper.
  3. Console.log the petDog variable.
  4. Console.log the petCat variable.
  5. Console.log the text "My pet dog's name is: " and the petDog variable.
  6. Console.log the text "My pet cat's name is: " and the petCat variable.
  7. Declare another variable and name it catSound. Assign the string of "purr" to it.
  8. Declare another variable and name it dogSound. Assign the string of "woof" to it.
  9. Console.log the variable petDog, then the string "says", then the variable dogSound.
  10. Console.log the variable petCat, then the string "says", then the variable catSound.
  11. Reassign the value stored in catSound to the string "meow".
  12. Console.log the variable petCat, then the string "now says", then the variable catSound.
Make sure to output all your variables. Feel free to play.

Declaring variables (solutions)

Here are the solutions to the previous exercise, which was to practice declaring variables.

Please note: The solutions presented here use single quotes and double quotes interchangeably to delimit pieces of text. This is done on purpose to illustrate that both ways of representing text are possible and acceptable so that you are aware of it. 

Task 1 solution to: Declare a new variable named petDog and give it the name Rex.

var petDog = 'Rex';

Task 2 solution to: Declare a new variable named petCat and give it the name Pepper.

var petCat = 'Pepper';

Task 3 solution to: Console log the petDog variable.

var petDog = 'Rex'// Task 1 solution
console.log(petDog);

Task 4 solution to: Console log the petCat variable.

var petCat = 'Pepper'// Task 2 solution
console.log(petCat);

Task 5 solution to: Console.log the string "My pet dog's name is: " and the petDog variable.

var petDog = 'Rex'// Task 1 solution
console.log("My pet dog's name is: " + petDog);

Please note that in this specific example, because the text in line 2 contains a single quote within it, you should use double quotes to surround the whole piece of text. Otherwise, JavaScript will return an error. We will cover this issue in more detail later. 

Task 6 solution to: Console.log the string "My pet cat's name is: " and the petCat variable.

var petCat = 'Pepper'// Task 2 solution
console.log("My pet cat's name is: " + petCat);

Please note that in this specific example, because the text in line 2 contains a single quote within it, you should use double quotes to surround the whole piece of text. Otherwise, JavaScript will return an error. We will cover this issue in more detail later. 

Task 7 solution to: Declare another variable and name it catSound. Assign the string of "purr" to it.

var catSound = "purr";

Task 8 solution to: Declare another variable and name it dogSound. Assign the string of "woof" to it.

var dogSound = "woof";

Task 9 solution to: Console.log the variable petDog, then the string "says", then the variable dogSound.

var petDog = 'Rex'// Task 1 solution
var dogSound = "woof"// Task 8 solution
console.log(petDog, "says", dogSound);

Task 10 solution to: Console.log the variable petCat, then the string "says", then the variable catSound.

var petCat = 'Pepper'// Task 2 solution
var catSound = "purr"// Task 7 solution
console.log(petCat, "says", catSound);

Task 11 solution to: Reassign the value stored in catSound to the string "meow".

var catSound = "purr"// Task 7 solution
catSound = "meow";

Task 12 solution to: Console.log the variable petCat, then the string "now says", then the variable catSound.

var petCat = 'Pepper'// Task 2 solution
var catSound = "meow"// Task 11 solution
console.log(petCat, "now says", catSound);

Operators in depth

In this reading, you will learn about additional operators, operator precedence and operator associativity. I'll also provide you with some examples of logical operators.

1. Additional operators
  • Logical AND operator: && 
  • Logical OR operator: || 
  • Logical NOT operator: ! 
  • The modulus operator: % 
  • The equality operator: ==
  • The strict equality operator: ===
  • The inequality operator: !=
  • The strict inequality operator: !==
  • The addition assignment operator: += 
  • The concatenation assignment operator: += (it's the same as the previous one - more on that later)
The logical AND operator in JavaScript: &&
The logical AND operator is, for example, used to confirm if multiple comparisons will return true.

In JavaScript, this operator consists of two ampersand symbols together: &&.

Let's say you're tasked with coming up with some code that will check if the currentTime variable is between 9 a.m. and 5 p.m. The code needs to console.log true if currentTime > 9 and if currentTime < 17.

Here's a solution: 

var currentTime = 10;
console.log(currentTime > 9 && currentTime < 17);

How does this code work?

First, on line one, I set the currentTime variable, and assign the value of 10 to it.

Next, on line two I console log two comparisons: 

currentTime > 9 

currentTime < 17

I also use the && logical operator to join the two comparisons.

Effectively, my code is interpretted as the following:

console.log(10 > 9 && 10 < 17);

The comparison of 10 > 9 will return true.

Also, the comparison of 10 < 17 will return true.

This means I can further re-write the line two of my solution as follows: 

console.log(true && true);

In essence, this is how my code works.

Now, the question is, what will be the result of console.log(true && true)?

To understand the answer, you need to know the behavior of the && logical operator.

The && logical operator returns a single value: the boolean true or false, based on the following rules: 
  • It returns true if both the values on its right and on its left are evaluated to true 
  • It returns false in all the other instances
In other words: 

console.log(true && true) will output: true 

console.log(true && false) will output: false 

console.log(false && true) will output: false 

console.log(false && false) will output: false

The logical OR operator in JavaScript: ||
The logical OR operator in JavaScript consists of two pipe symbols together: ||.

It is used when you want to check if at least one of the given comparisons evaluates to true.

Consider the following task: You need to write a program in JavaScript which will return true if the value of the currentTime variable is not between 9 and 17. Put differently, your code needs to console.log true if the value of the variable currentTime is either less than 9 or greater than 17.

Here's a solution: 

var currentTime = 7;
console.log(currentTime < 9 || currentTime > 17);

In line one of the code I assign the number 7 to the variable currentTime.

On line two, I console log the result of checking if either currentTime < 9 or currentTime > 17 will evaluate to true.

It's the same as this: 

var currentTime = 7;
console.log(true || false);

Here are the rules of how the || operator evaluates given values: 

console.log(true || true) will output: true 

console.log(true || false) will output: true  

console.log(false || true) will output: true  

console.log(false || false) will output: false

The logical OR operator will always return true, except when both sides evaluate to false. In other words, for the logical OR operator to return false, the results of both comparisons must return false.

Going back to the example of checking if either currentTime < 9 or currentTime > 17, this makes sense: the only time you will get false is when the value stored in the currentTime variable is greater than 9 and less then 17.

The logical NOT operator: !
In JavaScript, the logical NOT operator's symbol is the exclamation mark: !.

You can think of the ! operator as a switch, which flips the evaluated boolean value from true to false and from false to true.

For example if I assign the boolean value of true to the petHungry variable: 

var petHungry = true;

...then I can console log the fact that the pet is no longer hungry by using the ! operator to flip the boolean value stored inside of the petHungry variable, like so:

console.log('Feeding the pet'); console.log("Pet is hungry: ", !petHungry); console.log(petHungry);

This is the output of the above code:   

Pet is hungry: true
Feeding the pet
Pet is hungry: false
true

The reason for the changed output in the console is because you have flipped the value stored inside the petHungry variable, from true to false.

Notice, however, that the code on line five of the example above still outputs true - that's due to the fact that I didn't reassign the value of the petHungry variable.

Here's how I could permanently change the value stored in the petHungry variable from true to false: 

var petHungry = true;
petHungry = !petHungry;

In this example, I first assign the value of true to the new variable of petHungry. Then, on line two, I assign the opposite value, the !true - read: not true - to the existing petHungry variable.

The modulus operator: %
The modulus operator is another mathematical operator in JavaScript. It returns the remainder of division.

To demonstrate how it works, imagine that a small restaurant that has 4 chairs per table, and a total of 5 tables, suddenly receives 22 guests.

How many guests will not be able to sit down in the restaurant?

You can use the modulus operator to solve this.

console.log(22 % 5); // 2

The output is 2, meaning, when I divide 22 and 5, I get a 4, and the remainder is 2, meaning, there are 2 people who couldn't get a place in this restaurant.

The equality operator, ==
The equality operator checks if two values are equal.

For example, this comparison returns true: 5 == 5. Indeed, it is true that 5 is equal to 5.

Here's an example of the equality operator returning false:  5 == 6. Indeed, it is true that 5 is not equal to 6.

Additionally, even if one of the compared values is of the number type, and the other is of the string type, the returned value is still true: 5 == "5". 

This means that the equality operator compares only the values, but not the types.

The strict equality operator, ===
The strict equality operator compares for both the values and the data types.

With the strict equality operator, comparing 5 === 5 still returns true. The values on each side of the strict equality operator have the same value and the same type. However, comparing 5 == "5" now returns false, because the values are equal, but the data type is different.

The inequality operator, !=
The inequality operator checks if two values are not the same, but it does not check against the difference in types.

For example, 5 != "5" returns false, because it's false to claim that the number 5 is not equal to number 5, even though this other number is of the string data type.

The strict inequality operator !==
For the strict inequality operator to return false, the compared values have to have the same value and the same data type. 

For example,  5 !== 5 returns false because it is false to say that the number 5 is not of the same value and data type and another number 5.

However, comparing the number 5 and the string 5, using the strict inequality operator, returns true.

console.log(5 !== "5")

2. Using the + operators on strings and numbers
Combining two strings using the + operator
The + operator, when used with number data type, adds those values together.

However, the + operator is also used to join string data type together.

For example:

"inter" + "net" // "internet"
"note" + "book" // "notebook"

If the + operator is used to join strings, then it is referred to as the concatenation operator, and you'll say that it's used to concatenate strings.

When used with numbers, the + operator is the addition operator, and when used with strings, the + operator is the concatenation operator.

Combining strings and numbers using the + operator
But what happens when one combines a string and a number using the + operator?

Here's an example:

365 + " days" // "365 days"
12 + " months" // "12 months"

Here, JavaScript tries to help by converting the numbers to strings, and then concatenating the number and the string together, ending up with a string value.

The process of this "under-the-hood" conversion of values in JavaScript is referred to as "coercion". JavaScript coerces a number value to a string value - so that it can run the + operator on disparate data types.

The process of coercion can sometimes be a bit unexpected.

Consider the following example:

1 + "2"

What will be the result of 1 + "2"?

Note that the value of 1 is of the number data type, and the value of "2" is of the string data type, and so JavaScript will coerce the number 1 to a string of "1", and then concatenate it with the string of "2", so the result is a string of "12".

The addition assignment operator, +=
The addition assignment operator is used when one wants to accumulate the values stored in a variable.

Here's an example: You are counting the number of overtime hours worked in a week.

You don't have to specify the type of work, you just want to count total hours.

You might code a program to track it, like this:

var mon = 1;
var tue = 2;
var wed = 1;
var thu = 2;
var fri = 3;
console.log(mon + tue + wed + thu + fri); // 9

You can simplify the above code by using the addition assignment operator, as follows:

var overtime = 1;
overtime += 2;
overtime += 1;
overtime += 2;
overtime += 3;
console.log(overtime); // 9

Using the addition assignment operator reduces the lines of your code.

The concatenation assignment operator, +=
This operator's syntax is exactly the same as the addition assignment operator. The difference is in the data type used:

var longString = "";
longString += "Once";
longString += " upon";
longString += " a";
longString += " time";
longString += "...";
console.log(longString); // "Once upon a time..."

Operator precedence and associativity
Operator precedence is a set of rules that determines which operator should be evaluated first.

Consider the following example:

1 * 2 + 3

The result of the above code is 5, because the multiplication operator has precedence over the addition operator.

Operator associativity determines how the precedence works when the code uses operators with the same precedence.

There are two kinds: 
  • left-to-right associativity
  • right-to-left associativity
For example, the assignment operator is right-to-left associative, while the greater than operator is left-to-right associative:

var num = 10// the value on the right is assigned to the variable name on the left
5 > 4 > 3// the 5 > 4 is evaluated first (to `true`), then true > 3 is evaluated to 
`false`, because the `true` value is coerced to `1`

Exercise: Advanced use of operators

Task 1: Using the logical && operator
You are coding an RPG game, where each character has certain skill levels based on the value saved in their score.
  1. Create a variable named  score and set it to  8
  2. Use console.log() that includes the string "Mid-level skills:" and compares the score variable to above 0 and below 10 using the && operator
The expected output in the console should be: "Mid-level skills: true".

Task 2: Using the logical || operator
Imagine you are coding a video game. Currently, you’re about to code some snippets related to the game over condition.

You need to code a new variable named timeRemaining and set it to 0. You also need to code a new variable named energy and set it to 10.

Next, you should write a piece of code that could be used to determine if the game is over, based on whether either the value of the timeRemaining variable is 0 or the value of the energy variable is 0.

Complete the task using the following steps:
  1. Declare the variable timeRemaining, and assign the value of 0 to it.
  2. Declare the variable energy, and assign the value of 10 to it.
  3. Console log the following parameters: "Game over: ", and timeRemaining == 0 || energy == 0
Note that the expected output in the console should be: "Game over: true".

Try changing the timeRemaining variable to anything above 0 and then see how it affects the result.

Task 3: Using the modulus operator, %, to test if a given number is odd
You need to code a small program that takes a number and determines if it's an even number (like 2, 4, 6, 8, 10).

To achieve this task, you need to declare six variables, as follows:
  1. The first variable, named num1,  should be assigned a number value of 2.
  2. The second variable, named num2, should be assigned a number value of 5.
  3. The third variable, named test1, should be assigned the calculation of num1 % 2. Note: executing this code will return a number.
  4. The fourth variable, named test2, should be assigned the calculation of num2 % 2. Note: executing this code will also return a number.
  5. The fifth variable, named result1, should be assigned the result of comparing if the number stored in the test1 variable is not equal to 0, in other words, this: test1 == 0.
  6. The sixth variable, named result2, should be assigned the result of comparing if the number stored in the test2 variable is not equal to 0, in other words, test2 == 0.
Run console log two times after you've set the variables:
  1. The first console log should have the following code between parentheses: "Is", num1, "an even number?", result1
  2. The second console log should have the following code between parentheses: "Is", num2, "an even number?", result2
Note: The output to the console should be as follows:

Is 2 an even number? true

Is 5 an even number? false

Try it yourself with different values to explore the modulus operator.

Task 4: Add numbers using the + operator
Console log the result of adding two numbers, 5 and 10, using the + operator.

Note: This task should be completed on a single line of code. The output in the console should be 15.

Task 5: Concatenate numbers and strings using the + operator
Code three variables:
  1. The first variable should be a string with the following value: "Now in ". Name the variable now.
  2. The second variable should be a number with the value: 3. Name the variable three.
  3. The third variable should a string with the following value: "D!". Name the variable d.
  4. Console log the following code: now + three + d.
Note: The expected output should be: "Now in 3D!".

Task 6: Use the += operator to accumulate values in a variable
Code a new variable and name it counter, assigning it to the value of 0.

On the next line, use the += operator to increase the value of counter by 5.

On the next line, use the += operator to increase the value of counter by 3.

On the fourth line, console log the value of the counter variable.

Note: The output value should be 8.

Advanced use of operators (solutions)

Task 1 Solution

var score = 8;
console.log("Mid-level skills:", score > 0 && score < 10)

Task 2 Solution

var timeRemaining = 0;
var energy = 10;
console.log("Game over:", timeRemaining == 0 || energy == 0);

Task 3 Solution

var num1 = 2;
var num2 = 5;
var test1 = num1 % 2;
var test2 = num2 % 2;
var result1 = test1 == 0;
var result2 = test2 == 0;
console.log("Is", num1, "an even number?", result1);
console.log("Is", num2, "an even number?", result2);

Task 4 Solution

console.log(5 + 10); // 15

Task 5 Solution

var now = "Now in ";
var three = 3;
var d = "D!"
console.log(now + three + d); // "Now in 3D!"

Task 6 Solution

var counter = 0;
counter += 5;
counter += 3;
console.log(counter); // 8

QUIZ 1 - Welcome to Programming


JavaScript improvements

In this reading, you will learn about the history of JavaScript and the importance of ECMA (European Computer Manufacturers Association) and ECMAScript.  

JavaScript is a programming language that had humble beginnings.

It was built in only 10 days in 1995 by a single person, Brendan Eich, who was tasked with building a simple scripting language to be used in version 2 of the Netscape browser. It was initially called LiveScript, but since the Java language was so popular at the time, the name was changed to JavaScript - although Java and JavaScript are in no way related.

For the first few years, after it was built, JavaScript was a simple scripting language to add mouseover effects and other interactivity. Those effects were being added to webpages using the <script> HTML element.

Inside each of the script elements, there could be some JavaScript code. Due to the rule that HTML, CSS, and JavaScript must be backward compatible, even the most advanced code written in JavaScript today ends up being written between those script tags.

Over the years, JavaScript grew ever more powerful, and in recent times, it's continually touted as among the top three commonly used languages.

In 1996 Netscape made a deal with the organization known as ECMA (European Computer Manufacturers Association) to draft the specification of the JavaScript language, and in 1997 the first edition of the ECMAScript specification was published.

ECMA publishes this specification as the ECMA-262 standard.

You can think of a standard as an agreed-upon way of how things should work. Thus, ECMA-262 is a standard that specifies how the JavaScript language should work.

There have been 12 ECMA-262 updates - the first one was in 1997.

JavaScript as a language is not a completely separate, stand-alone entity. It only exists as an implementation. This implementation is known as a JavaScript engine.

Traditionally, the only environment in which it was possible to run a JavaScript engine, was the browser. More specifically, a JavaScript engine was just another building block of the browser. It was there to help a browser accomplish its users' goal of utilizing the internet for work, research, and play.

So, when developers write JavaScript code, they are using it to interact with a JavaScript engine. Put differently, developers write JavaScript code so that they can "talk to" a JavaScript engine.

Additionally, the JavaScript engine itself comes with different ways to interact with various other parts of the browser. These are known as Browser APIs.

Thus, the code that you write in the JavaScript programming language allows you to: 1. Interact with the JavaScript engine inside of the browser 2. Interact with other browser functionality that exists outside of the JavaScript engine, but is still inside the browser.

Although traditionally it was possible to interact with the JavaScript engine only inside of the browser, this all changed in 2009, when Node.js was built by Ryan Dahl.

He came up with a way to use a JavaScript engine as a stand-alone entity. Suddenly, it was possible to use JavaScript outside of the browser, as a separate program on the command line, or as a server-side environment.

Today, JavaScript is ubiquitous and is running in browsers, on servers, actually, on any device that can run a JavaScript engine.

Additional resources

Here is a list of resources that may be helpful as you continue your learning journey.

These resources provide some more in-depth information on the topics covered in this module.

Mozilla Developer Network Expressions and Operators
Mozilla Developer Network Operator Precedence and Associativity
JavaScript Primitive Values
ECMA262 Specification
jQuery Official Website
React Official Website
StackOverflow Developer Survey 2021 Most Popular Technologies
Emojis

Conditional examples

In this reading, you will learn when to use the if else statement and when to use the switch statement.

Both if else and switch are used to determine the program execution flow based on whether or not some conditions have been met.

This is why they are sometimes referred to as flow control statements. In other words, they control the flow of execution of your code, so that some code can be skipped, while other code can be executed.

At the heart of both flow control structures lies the evaluation of one or more conditions.

Generally, if else is better suited if there is a binary choice in the condition.

For example, in plain English: if it's sunny, wear sunglasses. Otherwise, don't.

In this case, using an if statement is an obvious choice.

When there are a smaller number of possible outcomes of truthy checks, it is still possible to use an if else statement, such as:

if(light == "green") {
    console.log("Drive")
else if (light == "orange") {
    console.log("Get ready")
else if (light == "red") {
    console.log("Dont' drive")
else {
    //this block will run if no condition matches
    console.log("The car is not green, orange, or red");
}

However, if there are a lot of possible outcomes, it is best practice to use a switch statement because it is easier less verbose. Being easier to read, it is easier to follow the logic, and thus reduce cognitive load of reading multiple conditions.

Nevertheless, this is not a rule set in stone. It is simply a stylistic choice.

To reinforce this point, here's an example of the earlier if else conditional statement, using the switch syntax: 

//converting the previous if-else example with switch-case
switch(light) {
   case 'green':
       console.log("Drive");
       break;
   case 'orange':
       console.log("Get ready");
       break;
   case 'red':
       console.log("Don't drive");
       break;
   default:
       //this block will run if no condition matches
       console.log('The light is not green, orange, or red');
       break;
}

Exercise: Practice conditional statements

Introduction
In this exercise, you will practice working with if else statements. By the end of this exercise, you will be able to write an if else statement that determines your source of income based on your age. You will also be able to write a switch statement that determines your evening routine based on the day of the week.

Complete the following steps to create: Are You Old Enough? 
  1. Declare a variable age using the var keyword and set it to the number 10.
  2. Add an if statement that checks if the value of the age variable is greater than or equal to the number 65. Inside the if block, console.log the sentence: "You get your income from your pension".
  3. Add an "else if",  where you'll check if the value of the age is less than 65 and greater than or equal to 18. Inside this "else if" block, type "console.log" and then "Each month you get a salary".
  4. Add another "else if", and this time check if the value of the age is under 18. Inside the "else if" block, "type console.log" and then "You get an allowance".
  5. Add an "else" statement to capture any other value. Inside the block, type "console.log" and then "The value of the age variable is not numerical".
Try adjusting the age and executing the program to see how it will affect the output.

Code the days of the week program as a switch statement
  1. On the next line, define a new variable, name it day, and set its value to "Sunday".
  2. Start coding a switch statement, passing the day variable as the expression to evaluate.
  3. Inside the switch, add cases for every day of the week, starting with 'Monday', and ending with 'Sunday'. Make sure to use string values for days. Inside each case, for now, just add a console.log('Do something'), and add a break; on the line below.
  4. At the very bottom of the switch statement, add the default case and add a console.log('There is no such day').
  5. Finally, update the console.log calls for each case, based on whatever activity you have on each of the days.
Tips
  • If you need to make sure that multiple conditions are true in an if statement, you can do so using the && operator
  • In JavaScript, the correct syntax of the "greater than or equal to" operator is: >=.
  • Don't forget to add a break at the very end of each case in a switch statement.

Note: You can find solutions in a separate reading (following this one)

Solutions: Practice conditional statements

Solutions to the task - Are you old enough?

Step 1: 
Declare a variable age using the var keyword and set it to the number 10.

var age = 10;

Step 2: 
Add an "if" statement that checks if the value of the age variable is greater than or equal to the number 65. Inside the if block, type "console.log" and "You get your income from your pension".

var age = 10;
if (age >= 65) {
   console.log('You get your income from your pension')
}

Step 3: 
Add an "else", followed with an "if", where you'll check if the value of age is less than 65 and greater than or equal to 18. Inside this if block type "console.log" and "Each month you get a salary".

var age = 10;
if (age >= 65) {
   console.log('You get your income from your pension')
else if (age < 65 && age >= 18) {
   console.log('Each month you get a salary')
}

Step 4: 
Add another "else if", and this time check if the value of the age is under 18. Inside the if block, type "console.log" and "You get an allowance".

var age = 10;
if (age >= 65) {
   console.log('You get your income from your pension')
else if (age < 65 && age >= 18) {
   console.log('Each month you get a salary')
else if (age < 18) {
   console.log('You get an allowance')
}

Step 5: 
Add an "else" statement to capture any other value. Inside the block, type "console.log" and "The value of the age variable is not numerical".

var age = 10;
if (age >= 65) {
   console.log('You get your income from your pension')
else if (age < 65 && age >= 18) {
   console.log('Each month you get a salary')
else if (age < 18) {
   console.log('You get an allowance')
else {
   //this block will run if no condition matches
   console.log('The value of the age variable is not numerical')
}

Solutions to the Days of the Week program

Step 1: 
On the next line, define a new variable, name it day, and set its value to Sunday.

var day = `Sunday`;

Step 2: 
Start coding a switch statement, passing the day variable as the expression to evaluate.

var day = `Sunday`;
switch(day) {
//add your conditions
}

Step 3: 
Inside the switch, add cases for all the days of the week, starting with 'Monday', and ending with 'Sunday'. Make sure to use string values for days. Inside each case, for now, just add a console.log('Do something'), and add a break; on the line below.

var day = `Sunday`;
switch(day) {
   case 'Monday':
       console.log('Do something');
       break;
   case 'Tuesday':
       console.log('Do something');
       break;
   case 'Wednesday':
       console.log('Do something');
       break;
   case 'Thursday':
       console.log('Do something');
       break;
   case 'Friday':
       console.log('Do something');
       break;
   case 'Saturday':
       console.log('Do something');
       break;
   case 'Sunday':
       console.log('Do something');
       break;
}

Step 4: 
At the very bottom of the switch statement, add the default case and add a "console.log"('There is no such day').

var day = `Sunday`;
switch(day) {
   case 'Monday':
       console.log('Do something');
       break;
   case 'Tuesday':
       console.log('Do something');
       break;
   case 'Wednesday':
       console.log('Do something');
       break;
   case 'Thursday':
       console.log('Do something');
       break;
   case 'Friday':
       console.log('Do something');
       break;
   case 'Saturday':
       console.log('Do something');
       break;
   case 'Sunday':
       console.log('Do something');
       break;
   default:
       //this block will run if no condition matches
       console.log('There is no such day');
}

Step 5: 
Finally, update the console.log calls for each case, based on whatever activity you have on each of the days.

var day = `Sunday`;
switch(day) {
   case 'Monday':
       console.log('Read a book');
       break;
   case 'Tuesday':
       console.log('Watch a movie');
       break;
   case 'Wednesday':
       console.log('Read a book');
       break;
   case 'Thursday':
       console.log('Play basketball');
       break;
   case 'Friday':
       console.log('Socialize');
       break;
   case 'Saturday':
       console.log('Chill');
       break;
   case 'Sunday':
       console.log('Have barbecue');
       break;
   default:
       //this block will run if no condition matches
       console.log('There is no such day');
}

Exercise: Repetitive tasks with loops

In this exercise, you will practice writing "for" and "while" loops.

Task 1
Write a "for" loop that will perform exactly the same repetitive code as this:

console.log(1)
console.log(2)
console.log(3)
console.log(4)
console.log(5)
console.log('Counting completed!')

Task 2 
Write a "for" loop that will perform exactly the same repetitive code as this:

console.log(5)
console.log(4)
console.log(3)
console.log(2)
console.log(1)
console.log('Countdown finished!')

Task 3
Write a "while" loop that will perform exactly the same repetitive code as this:

console.log(1)
console.log(2)
console.log(3)
console.log(4)
console.log(5)
console.log('Counting completed!')

Note: Name your increment variable i. Update the variable in the while loop using i++.

Task 4
Write a "while" loop that will perform exactly the same repetitive code as this:

console.log(5)
console.log(4)
console.log(3)
console.log(2)
console.log(1)
console.log('Countdown finished!')

Note: In the while loop, decrement the value of i using: i = i - 1.

Task 5
Write a "while" loop that will perform exactly the same repetitive code as this:

console.log(2018)
console.log(2019)
console.log(2020)
console.log(2021)
console.log(2022)

Repetitive tasks with loops (solutions)
Here are the solutions to the for and while loop exercise.

Task 1

for (var i = 1; i <= 5; i++) {
    console.log(i);
};
console.log('Counting completed!');

Task 2

for (var i = 5; i > 0; i--) {
    console.log(i);
};
console.log('Countdown finished!');

Task 3

var i = 1;
while (i < 6) {
    console.log(i);
    i++;
};
console.log('Counting completed!');

Note: Name your increment variable i. Update the variable in the while loop using i++.

Task 4
Write a "while" loop that will perform the exact same repetitive code like the one below:

var i = 5;
while (i > 0) {
    console.log(i);
    i = i - 1;
};
console.log('Counting completed!');

Note: In the while loop, decrement the value of i using: i = i - 1.

Task 5
Write a "while" loop that will perform the exact same repetitive code like the one below:

var year = 2018;
while (year < 2023) {
    console.log(year);
    year++;
};

Loops and nested loops

Let's say I want to output a custom multiplication table.

This is a perfect use case scenario for nested loops.

The outer loop's counter variable will act as the first number to be multiplied, and the inner loop counter variable will act as the second number to be multiplied.

Here's my code:

//single loop
for (var firstNum = 0; firstNum < 2; firstNum++) {
    console.log(firstNum);
}

The output of the above code will be:

0
1

This means that my for loop starts at 0 and stops after 1.

So now I can code what will later become the inner loop, whose counter variable will be the second number in this multiplication:

//single loop
for (var secondNum = 0; secondNum < 10; secondNum++) {
    console.log(secondNum);
}

This time, the output is:

0
1
2
3
4
5
6
7
8
9

Now's the time to combine the first and the second loop:

//nested loops - one inside another
for (var firstNum = 0; firstNum < 2; firstNum++) {
    for (var secondNum = 0; secondNum < 10; secondNum++) {
        console.log(firstNum + ", " + secondNum);
    }
}

Now that I'm nesting the second for loop inside the first one, and that I'm console logging the values of both counter variables as the loops are progressing, the output looks like this:

0, 0
0, 1
0, 2
0, 3
0, 4
0, 5
0, 6
0, 7
0, 8
0, 9
1, 0
1, 1
1, 2
1, 3
1, 4
1, 5
1, 6
1, 7
1, 8
1, 9

Now that I have a list of all the numbers that will be multiplied, having the actual result of this multiplication is as easy as updating the console.log() call:

//nested loops - one inside another
for (var firstNum = 0; firstNum < 2; firstNum++) {
    for (var secondNum = 0; secondNum < 10; secondNum++) {
        console.log(firstNum + " times " + secondNum + " equals " + firstNum * secondNum);
    }
}

The output now is:

0 times 0 equals 0
0 times 1 equals 0
0 times 2 equals 0
0 times 3 equals 0
0 times 4 equals 0
0 times 5 equals 0
0 times 6 equals 0
0 times 7 equals 0
0 times 8 equals 0
0 times 9 equals 0
1 times 0 equals 0
1 times 1 equals 1
1 times 2 equals 2
1 times 3 equals 3
1 times 4 equals 4
1 times 5 equals 5
1 times 6 equals 6
1 times 7 equals 7
1 times 8 equals 8
1 times 9 equals 9

This makes for some very interesting combinations.

For example, I can make a custom division table:

//nested loops - one inside another 
for (var i = 100; i > 10; i = i - 10) {
    for (var j = 10; j > 4; j = j - 5) {
        console.log(i + " divided by " + j + " equals " + i / j);
    }
}

Here's the output of the above nested loop:

100 divided by 10 equals 10
100 divided by 5 equals 20
90 divided by 10 equals 9
90 divided by 5 equals 18
80 divided by 10 equals 8
80 divided by 5 equals 16
70 divided by 10 equals 7
70 divided by 5 equals 14
60 divided by 10 equals 6
60 divided by 5 equals 12
50 divided by 10 equals 5
50 divided by 5 equals 10
40 divided by 10 equals 4
40 divided by 5 equals 8
30 divided by 10 equals 3
30 divided by 5 equals 6
20 divided by 10 equals 2
20 divided by 5 equals 4

Feel free to try out some other combinations of nested loop iterations, and see what kind of output you'll get.

Uses of loops

In this reading, we'll discuss, at a very high level, the reasons to use loops in JavaScript.

Note that we will keep this discussion high-level because there are multiple "pieces of the puzzle" that are still missing from your understanding at this point.

This is why we will not get bogged-down in the detail of syntax and implementation, but instead, simply discuss how and why loops are used in everyday work of JavaScript developers.

Consider the following example: You work as a developer for an online store.

The store is selling letter cubes for toddlers, and the entire "Shop now" section of the site is organized in a layout where each cube on sale is displayed in a simple card component, with an image of the cube, the letter it teaches, a short description, and the price.

Cards are organized in rows, so that each row contains three cards - three different letters.

Each card is a preview of that specific letter cube on sale, and it's also a link to an entire page, dedicated to providing more info about the cubes, their teaching value, and providing the visitor with a way to complete their checkout process.

Now, here's a quick question: where would loops fit into displaying this grid of cards showcasing the letter cubes on sale?

To understand just how this works, let me code a basic prototype of how this might work.

Since you still don't have enough knowledge to display website layouts in browser with the help of JavaScript, for now I'll have to settle for using a simple string and the console.

Still, this should be a fun exercise.

var cubes = 'ABCDEFG';
//styling console output using CSS with a %c format specifier
for (var i = 0; i < cubes.length; i++) {
    var styles = "font-size: 40px; border-radius: 10px; border: 
1px solid blue; background: pink; color: purple";
    console.log("%c" + cubes[i], styles)
}

Note: In order to have the styles applied, try running this code snippet in your browser's console.

That's it, with this simple code, the output in the console shows each letter on a separate line, styled like a letter cube for toddlers.

The code itself should be mostly familiar, except for the cubes.length and the cubes[i] syntax.

Without getting into too many details, here are both code snippets explained as simple as possible.

The cubes.length returns a number. Since cubes is a string of characters the cubes.length gives me the length of the string saved in the variable.

So this gives me the number 7, effectively making my for loop look like this:

var cubes = 'ABCDEFG';
//styling console output using CSS with a %c format specifier
for (var i = 0; i < 7; i++) {
    var styles = "font-size: 40px; border-radius: 10px; border: 1px solid blue; background: pink; color: purple";
    console.log("%c" + cubes[i], styles)
}


The second piece of code that's new here is the cubes[i] snippet.

This simply targets each individual letter in the loop, based on the current value of the i variable.

In other words, cubes[i], when i is equal to 0, is: A.

Then, cubes[i], when i is equal to 1, is: B.

This goes on for as many loops my for loop runs - and this is determined by the cubes.length value.

It's also very versatile, since, if I, for example, decided to change the length of the cubes string, I would not have to update the condition of i < cubes.length, because it gets automatically updated when I change the length of the cubes string.

There are some other ways to store data in JavaScript apps that you haven't heard about.

But we can use the same approach with those other kinds of data, to achieve results that essentially work on the same principle as the one just described.

Using loops is the essence of the approach taken in developing many different pieces of functionality in software today.

Some additional examples
If I'm coding an email client, I will get some structured data about the emails to be displayed in the inbox, then I'll use a loop to actually display it in a nicely-formatted way.

If I'm coding an e-commerce site selling cars, I will get a source of nicely-structured data on each of the cars, then loop over that data to display it on the screen.

If I'm coding a calendar online, I'll loop over the data contained in each of the days to display a nicely-formatted calendar.

There are many, many other examples of using loops in code.

Using loops with data that is properly formatted for a given task is a crucial component of building software.

In the lessons that follow, we'll learn about different ways of grouping related data and of displaying it on the screen using JavaScript.

When combined with what you've already learned about loops, this gives you the skills to build various kinds of user interfaces where there is repetitive information.

Some more specific examples include:
  • looping over blog post titles in some structured data, and displaying each blog post title on a blog home page
  • looping over social media posts in some structured data, and displaying each social media post based on some conditions
  • looping over some structured data on clothing available for sale in an online clothing store, and displaying relevant data for each item of clothing
Now you understand the importance of knowing how to work with loops in JavaScript. In the upcoming lessons, we'll learn other relevant information which will allow you to be able to do this.

Exercise: Working with conditionals and loops

Exercise 1
In this exercise, you will create the code for a for loop, using the counter variable named i starting from 1.

To make the counter increment by 1 on each loop, you will use i++.

The exit condition for the for loop should match the output given below. 

Inside the loop, write an if-else statement, which will check the following conditions:

First, it will check if the value of i is 1. If it is, your code will console log the string "Gold medal".

Next, I will check if the value of i is 2. If it is, your code will console log the string "Silver medal".

Then, your code will check if the value of i is 3. If it is, it will console log the string "Bronze medal".

For all the remaining values of i, your code will console log just the value of i.

Note: The expected console log of the entire code should be as follows.
Gold medal
Silver medal
Bronze medal
4
5
6
7
8
9
10

Exercise 2. Use the completed code from the previous task, but convert the conditionals to a switch statement.
When you code the solution, the output in the console should remain exactly the same as in the previous question.

Note: You'll need three separate cases for the three medals, and a default case for all other values of the i variable.

Solution: Working with conditionals and loops

Answer 1:  

for (var i = 1; i <= 10; i++) {
    if(i == 1) {
        console.log("Gold medal")
    } else if (i == 2) {
        console.log("Silver medal")
    } else if (i == 3) {
        console.log("Bronze medal")
    } else {
        //this block will run if no condition matches
        console.log(i)
    }
}

Answer 2:  

for (var i = 1; i <= 10; i++) {
    switch(i) {
        case 1:
            console.log("Gold medal")
            break
        case 2:
            console.log("Silver medal")
            break
        case 3:
            console.log("Bronze medal")
            break
        default:
            //this block will run if no condition matches
            console.log(i)
    }
}

QUIZ 2 - Conditionals and loops


Additional resources for Conditionals and Loops

Here is a list of resources that may be helpful as you continue your learning journey.

In JavaScript, there is also a shorthand version of writing a conditional statement, known as the conditional (ternary) operator:Conditional (ternary) operator

WEEK 2 - The Building Blocks of a Program

Here you'll learn how to use objects, arrays and functions. In addition, you will learn about the most common built-in methods, and the difference between undefined, null and empty strings. And you'll explore both error handling and defensive programming. After completing this module, you will be able to:

Building and calling functions

In this reading, you will learn how to build and call a function. The purpose of this reading is to provide you with an example of function declaration (build) and function invocation (call). In the next lesson you will be writing the code.

By the end of this reading you should be able to:
  • Code simple functions that can accept an array and iterate through it  
Let's start with giving our function declaration a name:

function listArrayItems(arr) {
    // ... code to be added ...
}

So, I've declared a listArrayItems function, and I've set it up to accept a single parameter, arr - which stands for an array.

Now, I'll need to code a for loop to loop over an array.

As covered in previous lessons in this course, a for loop needs the following information: 
  1. the starting loop counter value as a temporary variable i 
  2. the exit condition (the maximum value of the loop counter variable i, above which the loop no longer runs) 
  3. how to update the value of i after each loop
Here's the information I'll use in this function declaration: 1. The loop's starting counter will be 0. The reason for setting it to zero is due to the fact that arrays are also counted from zero. 

This means that I'll have a one-to-one mapping of the current value of the i variable at any given time, corresponding to the same index position of any item in the arr array 2. 

The for loop's exit condition is when the value of i is equal or greater than arr.length. 

Since the arr.length counts the number of items in the array from one, and the array items are indexed from zero, this effectively means that as soon as i is equal to arr.length, the loop will finish and any other code after it will be run. 

This practically means that the exit condition for this for loop will be i < arr.length returning false. 

In other words, as long as i < arr.length is true, this for loop will continue to run. 3. To make sure that none of the items in the arr array are skipped, I have to increase the value of i by 1 after each loop.

Now that I know exactly how my for loop should behave, I can add it to my listArrayItems() function:

function listArrayItems(arr) {
    for (var i = 0; i < arr.length; i++) {
        // ... code pending here ...
    }
}

Now all that I have left to decide is how I want to output each item from the received arr array.

It can be as simple as console logging the array item index of the current value of i:

function listArrayItems(arr) {
    for (var i = 0; i < arr.length; i++) {
        console.log(arr[i]) //display the array item where the index is euqal to i
    }
}

If I now invoke the listArrayItems function, I can, for example, give it the following array of colors:  

var colors = ['red''orange''yellow''green''blue''purple''pink'];
listArrayItems(colors); //display all items in the array at once

The output will be:  

red
orange
yellow
green
blue
purple
pink

I can update the output any way I like. For example, here are my arr items with a number in front of each item:  

//function that takes an array as input and display all items of this array
function listArrayItems(arr) {
    for (var i = 0; i < arr.length; i++) {
        console.log(i, arr[i])
    }
}
var colors = ['red''orange''yellow''green''blue''purple''pink'];
listArrayItems(colors);

Now the output of the above code will be as follows:  

0 'red'
1 'orange'
2 'yellow'
3 'green'
4 'blue'
5 'purple'
6 'pink'

To start the count from one instead of zero, I can update my function declaration as follows:  

function listArrayItems(arr) {
    for (var i = 0; i < arr.length; i++) {
        console.log(i+1, arr[i])
    }
}

Invoking the above, updated, function declaration on my colors array, will now result in the following output:  

1 'red'
2 'orange'
3 'yellow'
4 'green'
5 'blue'
6 'purple'
7 'pink'

I can even add one or more conditions, such as:  

function listArrayItems(arr) {
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] == 'red') {
            console.log(i*100"tomato!")
        } else {
            console.log(i*100, arr[i])
        }
    }
}

Now I'm adding control flow right inside my function, based on whether a specific array member matches a specific value - in this case the string "red".

Invoking my newest updated version of the listArrayItems function on the colors array will now result in the following output:

0 'tomato!'
100 'orange'
200 'yellow'
300 'green'
400 'blue'
500 'purple'
600 'pink'

Exercise: Practicing with functions

Your task in this exercise is to code a function which will be able to take a word and locate the position of a chosen letter in that given word.  

Task 1:
Write a function named letterFinder that accepts two parameters: word and match.

Task 2:
Code a 'for' loop inside the function's body. The for loop's counter should start at zero, increment by 1 on each iteration and exit when the counter variable's value is equal to the length of the word parameter.

Task 3:
Add an if statement inside the for loop whose condition works as follows:
  1. Access each of the letters inside the passed in word using the counter variable, with word[i]. 
  2. Check if the current word[i] is equal to the value of match.
Task 4:
console.log the following inside the body of the if statement: console.log('Found the', match, 'at', i).

Task 5:
Write the else condition. Here you'll just console log the following: console.log('---No match found at', i).

Task 6:
Call the letterFinder and pass it as its first argument as the string "test" and as its second argument, the string "t".

Your output should be the following:

Found the t at 0

---No match found at 1

---No match found at 2

Found the t at 3

Solution: Practicing with functions

Task 1 solution:

// A function that accepts two parameters
function letterFinder(word, match) {

}

Task 2 solution:

function letterFinder(word, match) {
    for(i = 0; i < word.length; i++) {
        //this loop exists when i is equal to the length of the word
    }
}

Task 3 solution:

function letterFinder(word, match) {
    for(i = 0; i < word.length; i++) {
        if(word[i] == match) {
            //check if the current characater, word[i], is equal to the match
        }
    }
}

Task 4 solution:

function letterFinder(word, match) {
    for(i = 0; i < word.length; i++) {
        if(word[i] == match) {
            //check if the current characater, word[i], is equal to the match
            console.log('Found the', match, 'at', i)
        }
    }
}

Task 5 solution:

function letterFinder(word, match) {
    for(i = 0; i < word.length; i++) {
        if(word[i] == match) {
            //check if the current characater, word[i], is equal to the match
            console.log('Found the', match, 'at', i)
        } else {
            console.log('---No match found at', i)
        }
    }
}

Task 6 solution:

function letterFinder(word, match) {
    for(var i = 0; i < word.length; i++) {
        if(word[i] == match) {
            //check if the current characater, word[i], is equal to the match
            console.log('Found the', match, 'at', i)
        } else {
            console.log('---No match found at', i)
        }
    }
}

letterFinder("test""t")


Object Literals and the Dot Notation

By the end of this reading, you'll be able to:

  • Explain one of the three common ways to build objects ( using the object literal notation)
  • Outline the common way to add new properties to  objects (or update existing properties) using the dot notation
Object literals and the dot notation
One of the most common ways of building an object in JavaScript is using the object literal syntax: {}.

To be able to access this object literal, it is very common to assign it to a variable, such as:

var user = {}; //create an object

Now an object literal is assigned to the variable user, which means that the object it is bound to can be extended and manipulated in a myriad of ways.

Sometimes, an entire object can be immediately built, using the object literal syntax, by specifying the object's properties, delimited as key-value pairs, using syntax that was already covered in an earlier lesson item in this lesson.

Here's one such previously built object:

//creating an object with properties and their values
var assistantManager = {
    rangeTilesPerTurn: 3,
    socialSkills: 30,
    streetSmarts: 30,
    health: 40,
    specialAbility: "young and ambitious",
    greeting: "Let's make some money"
}

The beauty of this syntax is that it's so easily readable. 

It essentially consists of two steps: 

1. Declaring a new variable and assigning an object literal to it - in other words, this: var assistantManager = {} 

2. Assigning the values to each of the object's keys, using the assignment operator, =

Notice that it's very easy to build any kind of an object in JavaScript using this example syntax.

For example, here's a table object:

var table = {
    legs: 3,
    color: "brown",
    priceUSD: 100,
}

To access the table object, I can simply console log the entire object:  

console.log(table);//display the object in the developer console

The returned value is the entire table object:  

{legs: 3, color: 'brown', priceUSD: 100}

Additionally, I can console log any individual property, like this:  

console.log(table.color); // 'brown'

Now that I have this "syntax recipe", I can build any other object in a similar way: 

var house = {
    rooms: 3,
    color: "brown",
    priceUSD: 10000,
}

An alternative approach of building objects is to first save an empty object literal to a variable, then use the dot notation to declare new properties on the fly, and use the assignment operator to add values to those properties; for example:

var house2 = {};
house2.rooms = 4;
house2.color = "pink";
house2.priceUSD = 12345;

Additionally, nothing is preventing me from combining the two approaches. For example:  

console.log(house); // {rooms: 3, color: "brown", priceUSD: 10000}
house.windows = 10;
console.log(house); // {rooms: 3, color: "brown", priceUSD: 10000, windows: 10}

This flexbility additionally means that I can update already existing properties, not just add new ones:  

house.windows = 11;
console.log(house); // {rooms: 3, color: "brown", priceUSD: 10000, windows: 11}

Object Literals and the Brackets Notation

By the end of this reading, you'll be able to:
  • Explain how to build objects using the brackets notation
  • Explain that with the brackets notation you can use the space character inside keys, since property keys are strings
  • Explain that the keys inside the brackets notation are evaluated
Object literals and the brackets notation
There is an alternative syntax to the dot notation I used up until this point.

This alternative syntax is known as the brackets notation.

To understand how it works, it's best to use an example, so I'll go through the process of coding the house2 object again, in the same way that I did with the dot notation, only this time, I'll use the brackets notation.

var house2 = {};
house2["rooms"] = 4;
house2['color']= "pink";
house2["priceUSD"] = 12345;
console.log(house2); // {rooms: 4, color: 'pink', priceUSD: 12345}

Note that using the brackets notation, I essentially just wrap each property's key as a string, inside either the single or double quotes - just like with regular strings. 

Then I wrap the entire property key into an opening and a closing square bracket.

That's essentially all there is to it.

I can both access and update properties on objects using either the dot notation, or the brackets notation, or a combination of both, like in the following example:

var car = {};
car.color = "red";
car["color"] = "green";
car["speed"] = 200;
car.speed = 100;
console.log(car); // {color: "green", speed: 100}

For the time being, this is probably enough information on object creation. 

Before I discuss the topic of arrays and objects, let me just give you another important piece of information about the brackets notation. 

With the brackets notation, I can add space characters inside property names, like this:  

car["number of doors"] = 4;
console.log(car); // {color: 'green', speed: 100, number of doors: 5}

Additionally, I can add numbers (as the string data type) as property keys:  

car["2022"] = 1901;
console.log(car); // {2022: 1901, color: 'green', speed: 100, number of doors: 5}

However, doing this is discouraged, due to obvious reasons of having a property key as a number string not really conveying a lot of useful information.

Finally, there's one really useful thing that bracket notation has but is not available in the dot notation: It can evaluate expressions.

To understand what that means, consider the following example:

var arrOfKeys = ['speed''altitude''color'];
var drone = {
    speed: 100,
    altitude: 200,
    color: "red"
}
for (var i = 0; i < arrOfKeys.length; i++) {
    console.log(drone[arrOfKeys[i]])
}

The above code will result in the following output:  

100
200
red

Using the fact that brackets notation can evaluate expressions, I accessed the arrOfKeys[i] property on the drone object. 

This value changed on each loop while the for loop was running.

Specifically, the first time it ran, it was evaluated like this: 
  • The value of i was 0 
  • The value of arrOfKeys[i] was arrOfKeys[0], which was "speed" 
  • Thus, drone[arrOfKeys[i]] was evaluated to drone["speed"] which is equal to 100
This allowed me to loop over each of the values stored inside the drone object, based on each of its properties' keys.

Arrays are Objects

By the end of this reading, you'll be able to:
  • Explain that arrays are objects, with their own built-in properties and methods
  • Outline the common way to extend arrays using the push() method
  • and explain how to trim the last member of an array using the pop() method
Arrays are objects
In JavaScript, arrays are objects. That means that arrays also have some built-in properties and methods.

One of the most commonly used built-in methods on arrays are the push() and the pop() methods.

To add new items to an array, I can use the push() method:

var fruits = [];
fruits.push("apple"); // ['apple']
fruits.push('pear'); // ['apple', 'pear']

To remove the last item from an array, I can use the pop() method:  

fruits.pop();
console.log(fruits); // ['apple']

Tying into some earlier lessons in this course, I can now build a function that takes all its arguments and pushes them into an array, like this: 

function arrayBuilder(one, two, three) {
    var arr = [];
    arr.push(one);
    arr.push(two);
    arr.push(three);
    console.log(arr);
}

I can now call the arrayBuilder() function, for example, like this:  

arrayBuilder('apple''pear''plum'); // ['apple', 'pear', 'plum']

Even better, I don't have to console log the newly built array. 

Instead, I can return it:

function arrayBuilder(one, two, three) {
    var arr = [];
    arr.push(one);
    arr.push(two);
    arr.push(three);
    return arr;
}

Additionally, I can save this function call to a variable. 

I can name it anything, but this time I'll use the name: simpleArr.

var simpleArr = arrayBuilder('apple''pear''plum');

And now I can console log the values stored in simpleArr:  

console.log(simpleArr); // ['apple','pear','plum']

Math object cheat sheet

JavaScript has handy built-in objects. One of these popular built-in objects is the Math object.

By the end of this reading, you'll be able to:
  • Outline the built-in properties and methods of the Math object
Number constants
Here are some of the built-in number constants that exist on the Math object: 
  • The PI number: Math.PI which is approximately 3.14159
  • The Euler's constant: Math.E which is approximately 2.718
  • The natural logarithm of 2: Math.LN2 which is approximately 0.693
Rounding methods
These include: 
  •  Math.ceil() - rounds up to the closest integer 
  •  Math.floor() - rounds down to the closest integer 
  •  Math.round() - rounds up to the closest integer if the decimal is .5 or above; otherwise, rounds down to the closest integer 
  •  Math.trunc() - trims the decimal, leaving only the integer
Arithmetic and calculus methods
Here is a non-conclusive list of some common arithmetic and calculus methods that exist on the Math object: 
  • Math.pow(2,3) - calculates the number 2 to the power of 3, the result is 8 
  • Math.sqrt(16) - calculates the square root of 16, the result is 4 
  • Math.cbrt(8) - finds the cube root of 8, the result is 2 
  • Math.abs(-10) - returns the absolute value, the result is 10 
  • Logarithmic methods: Math.log(), Math.log2(), Math.log10() 
  • Return the minimum and maximum values of all the inputs: Math.min(9,8,7) returns 7, Math.max(9,8,7) returns 9.
  • Trigonometric methods: Math.sin(), Math.cos(), Math.tan(), etc.
String cheat sheet

By the end of this reading, you'll be able to:
  • Identify examples of String functions and explain how to call them
In this cheat sheet, I'll list some of the most common and most useful properties and methods available on strings.

For all the examples, I'll be using either one or both of the following variables:

var greet = "Hello, ";
var place = "World"

Note that whatever string properties and methods I demo in the following examples, I could have ran it on those strings directly, without saving them to a variable such as the ones I named greet and place.

In some of the examples that follow, for the sake of clarity, instead of using a variable name, I'll use the string itself.

All strings have at their disposal several built-in properties, but there's a single property that is really useful: the length property, which is used like this:

greet.length; // 7

To read each individual character at a specific index in a string, starting from zero, I can use the charAt() method:  

greet.charAt(0); // 'H'

The concat() method joins two strings:  

"Wo".concat("rl").concat("d"); // 'World'

The indexOf returns the location of the first position that matches a character: 

"ho-ho-ho".indexOf('h'); // 0
"ho-ho-ho".indexOf('o'); // 1
"ho-ho-ho".indexOf('-'); // 2

The lastIndexOf finds the last match, otherwise it works the same as indexOf.

The split method chops up the string into an array of sub-strings:

"ho-ho-ho".split("-"); // ['ho', 'ho', 'ho']

There are also some methods to change the casing of strings. For example:  

greet.toUpperCase(); // "HELLO, "
greet.toLowerCase(); // "hello, "

Here's a list of all the methods covered in this cheat sheet:
  • charAt() 
  • concat() 
  • indexOf() 
  • lastIndexOf() 
  • split() 
  • toUpperCase() 
  • toLowerCase()  
Exercise: Creating arrays and objects

In this exercise lab you will practice creating arrays and objects.

Tasks to complete
  1. Create a new empty array literal and assign it to the variable clothes.
  2. Add 5 of your favorite items of clothing as strings using the push() method.
  3. Remove the fifth piece of clothing from the array using the pop() method.
  4. Add a new piece of clothing using the push() method.
  5. Use console.log to show the third item from the clothes array in the console.
  6. Create a new empty object literal and assign it to the variable favCar.
  7. Using the dot notation, assign a color property to the favCar object and give it a string value with the color of your choice.
  8. Using the dot notation, assign a covertible property to the favCar object and give it a boolean value of your choice.
  9. Use the console to log the entire favCar object.
Tips
  • Remember to use the object literal syntax: {}.
  • Remember to use the array literal syntax: [].
Resources
  • Video (Conceptual): Arrays
  • Video (Mix): Introduction to Arrays
  • Video (Conceptual): Objects
  • Video (Mix): Objects
Creating arrays and objects (solutions)

Answers

Step 1
Create a new empty array literal and assign it to the variable clothes.

var clothes = [];

Step 2
Add 5 of your favorite items of clothing as strings using the push() method.

var clothes = [];
clothes.push('gray t-shirt'); // 1st item of clothing
clothes.push('blue t-shirt'); // 2nd item of clothing
clothes.push('yellow t-shirt'); // 3rd item of clothing
clothes.push('slippers'); // 4th item of clothing
clothes.push('old jeans'); // 5th item of clothing

Step 3
Remove the fifth piece of clothing from the array using the pop() method.

var clothes = [];
clothes.push('gray t-shirt'); // 1st item of clothing
clothes.push('blue t-shirt'); // 2nd item of clothing
clothes.push('yellow t-shirt'); // 3rd item of clothing
clothes.push('slippers'); // 4th item of clothing
clothes.push('old jeans'); // 5th item of clothing
clothes.pop();

Step 4
Add a new piece of clothing using the push() method.

var clothes = [];
clothes.push('gray t-shirt'); // 1st item of clothing
clothes.push('blue t-shirt'); // 2nd item of clothing
clothes.push('yellow t-shirt'); // 3rd item of clothing
clothes.push('slippers'); // 4th item of clothing
clothes.push('old jeans'); // 5th item of clothing
clothes.pop();
clothes.push('green scarf');

Step 5
Use console.log to show the third item from the clothes array in the console.

var clothes = [];
clothes.push('gray t-shirt'); // 1st item of clothing
clothes.push('blue t-shirt'); // 2nd item of clothing
clothes.push('yellow t-shirt'); // 3rd item of clothing
clothes.push('slippers'); // 4th item of clothing
clothes.push('old jeans'); // 5th item of clothing
clothes.pop();
clothes.push('green scarf');
console.log(clothes[2]);

Step 6
Create a new empty object literal and assign it to the variable favCar.

var favCar = {};    

Step 7
Using the dot notation, assign a color property to the favCar object and give it a string value with the color of your choice.

var favCar = {};
favCar.color = "red";

Step 8
Using the dot notation, assign a covertible property to the favCar object and give it a boolean value of your choice.

var favCar = {};
favCar.color = "red";
favCar.convertible = true;

Step 9
Use the console to log the entire favCar object.

var favCar = {};
favCar.color = "red";
favCar.convertible = true;
console.log(favCar);

Object Methods

You might already be familiar with objects in JavaScript.

In this video, you will learn how to design objects as combinations of data and functionality.

As you might already know, an object consists of key-value pairs, known as properties.

We can add new key-value pairs to existing objects using the dot notation and the assignment operator. 

var car = {};
car.color = "red"//update the value of a property of the car objject

These are known as properties, and can take many data types, including functions.

var car = {};

car.color = "red";

//add a method to the car object so that it can be called as car.turnkey()
car.turnKey = function() { 
  console.log('engine running'); 
}

If the function is a property of an object, it is then referred to as a method. 

This is a function that can be accessed only through the JavaScript object that it is a member of. For example, the log method, which belongs to the console object, can only be accessed through the console object.

console.log('Hello world');

Let's explore this further now. I will create an object using something known as the constructor function.

var car = {};
car.mileage = 98765;
car.color = "red";
console.log(car);

First, I'll build a new object literally named car. I type var, space, car, space, equal sign, space, followed by a set of curly braces, and finally a semicolon.

Now, I'll extend the car object by assigning it a property named mileage. 

When I inspect the object, I can confirm that it contains a mileage property set to 98765. 

I want to add another property to the car object. This time, I will add a property named color and set it to the value of "red".

I can inspect the object again by typing its name into the browser console. So now, when I type console.log(car), I get an object with two properties: the mileage property, which is set to 98765, and the color property, set to "red". 

Great, now I've added two properties to my object.

Next, I want to add a method to my car object. And this method, when called, will output some text to the console. 

So, once again, I add another property to my car object. After all, a method is just another property of the car object. It's just another key-value par that the car object holds.

What's unique is that the value I'm assigning to it is a function. 

var car = {};
car.mileage = 98765;
car.color = "red";
console.log(car);
car.turnTheKey = function() {
    console.log("The engine is running")
}
console.log(car);

So, I begin by typing car dot turnTheKey, equals, and then I type the code for my function. So function, open-close parentheses. Then the two curly braces where I will place my code. Finally, inside the curly braces, I type the console dot log followed by the message "The engine is running".

Now I can inspect my car object again by typing its name into the console log method. This time, it displays that the car object contains three properties; the color property, the mileage property, and the turnTheKey property. 

Remember that all the key-value pairs in an object are referred to simply as properties. However, if I want to differentiate between the properties that can be executed, then I refer to such properties as methods. 

So, now I want to add another method to the car object. I'll name this one lightsOn. 

Once again, I type car.lightsOn, and then I add an equals sign, and again since it's a method, I'm assigning it to a function. This function will also have a console log in its body, and I'm just logging the string with the text "The lights are on". 

//example of adding properties and methods to an object
var car = {};
car.mileage = 98765;
car.color = "red";
console.log(car);
car.turnTheKey = function() {
    console.log("The engine is running")
}
car.lightsOn = function() {
    console.log("The lights are on.")
}
console.log(car);
car.turnTheKey();
car.lightsOn()

Ok, so now I have added four properties to my object. And two of those are methods. 

I've already ensured that I'm getting the correct mileage and color from my car object. Now, I'll try executing the turnTheKey and the lightsOn methods. 

First, I'll invoke the turnTheKey method. 

Remember that this method can be accessed only through the car object, so I first need to type the name of the object that holds the turnTheKey method. In other words, I need to type the word car, followed by a dot, and then the name of my method, which is turnTheKey. 

Remember that this property is a method. So, to run it, I need to append an opening and a closing parenthesis so that the JavaScript engine can process my JavaScript code. 

Notice that this results in the "The engine is running" string logged to the console. 

Now I'll test the other method. Once again, I need to access it through the car object, so I type car.lightsOn, and again, I need to add those parentheses to invoke the lightsOn method. I press the ENTER key and notice the text displays in the console.

Success! It's important to remember that when the JavaScript engine runs this line of code, it locates the car object in its memory. Then, it finds the lightsOn method on the car object. It reads the function declaration that's saved on this property and runs it, line by line.

Since there's only a single line of code, the JavaScript engine logs the string "The lights are on" to the console. 

QUIZ 1 - Arrays, Objects and Functions


Additional resources

Here is a list of resources that may be helpful as you continue your learning journey.

JavaScript Functions
JavaScript Object Basics
typeof operator in JavaScript
Arrays are "list-like objects"

Syntax, logical and runtime errors

By the end of this reading, you'll be able to:
  • Recognize common types of errors in JavaScript
Here are some of the most common errors in JavaScript: 
  • ReferenceError 
  • SyntaxError 
  • TypeError 
  • RangeError
There are some other errors in JavaScript. These other errors include: 
  • AggregateError 
  • Error 
  • InternalError 
  • URIError
However, in this reading I'll focus on the Reference, Syntax, Type, and Range errors.

ReferenceError
A ReferenceError gets thrown when, for example, one tries to use variables that haven't been declared anywhere.

An example can be, say, attempting to console log a variable that doesn't exist:

console.log(username);

If the variable named username hasn't been declared, the above line of code will result in the following output:

Uncaught ReferenceError: username is not defined

SyntaxError
Any kind of invalid JavaScript code will cause a SyntaxError.

For example:

var a "there's no assignment operator here";

The above line of code will throw the following error:  

Uncaught SyntaxErrorUnexpected string

There's an interesting caveat regarding the SyntaxError in JavaScript: it cannot be caught using the try-catch block.  

TypeError
A TypeError is thrown when, for example, trying to run a method on a non-supported data type.

A simple example is attempting to run the pop() method on a string:

"hello".pop() // Uncaught TypeError: "hello".pop is not a function

The array-like behavior of strings was already covered in an earlier lesson in this course. 

However, as can be confirmed by running the above line of code, strings do not have all the array methods readily available to them, and trying to use some of those methods will result in a TypeError being thrown.  

RangeError
A RangeError is thrown when we're giving a value to a function, but that value is out of the allowed range of acceptable input values.

Here's a simple example of converting an everyday Base 10 number (a number of the common decimal system) to a Base 2 number (i.e binary number).

For example:

(10).toString(2); // '1010'

The value of 2 when passed to the toString() method, is like saying to JavaScript: "convert the value of 10 of the Base 10 number system, to its counter-part in the Base 2 number system".

JavaScript obliges and "translates" the "regular" number 10 to its binary counter-part.

Besides using Base 2 number system, I can also use the Base 8, like this:

(10).toString(8); // 12

I get back the value 12, which is the plain number 10, writen in Base 8 number system.

However, if I try to use a non-existing number system, such as an imaginary Base 100, since this number system effectively doesn't exist in JavaScript, I will get the RangeError, because a non-existing Base 100 system is out of range of the number systems that are available to the toString() method:

(10).toString(100); // Uncaught RangeError: toString() radix argument must be
between 2 and 36

In this reading, you've covered some of the most common errors in JavaScript.

Exercise: Error prevention

Instructions

Task 1: Code a function declaration
You need to code a function declaration named addTwoNums, which accepts numbers a and b and console logs a + b.

Task 2: Invoke the addTwoNums function with a number and a string
You need to invoke the addTwoNums using the following arguments: 5 and "5".

Task 3: Update the addTwoNums function with a try...catch block
Add the try and catch blocks inside the function definition's body. For now, just make sure that the console log of a + b is inside the try block. Additionally, the catch block should catch an error named err and, inside the body of the catch block, you need to console log the err value.

Task 4: If the passed-in arguments are not numbers, throw an error
If either of the arguments passed to the addTwoNums are not numbers, you'll throw an error.

Specifically, code a conditional with the following logic:
  • if the typeof the a parameter is not equal to 'number', throw a new ReferenceError. Inside the ReferenceError, pass a custom error message of 'the first argument is not a number'.
  • else if the typeof the b parameter is not equal to 'number', throw a new ReferenceError. Inside the ReferenceError, pass a custom error message of 'the second argument is not a number'.
  • else, console log a + b  
Once you've completed this task, all the code inside the try block will be inside these conditional statements.

Task 5: Update the catch block
Inside the catch block, update the code from console.log(err) to console.log("Error!", err).

Task 6: Invoke the addTwoNums function
Invoke the addTwoNums function using 5 and "5" as arguments.

Task 7: Add another console log under the addTwoNums function invocation
Add another line of code that console logs the string "It still works".

Solution: Error prevention

Solution to task 1: Code a function declaration

function addTwoNums(a,b) {
    console.log(a + b) //display the result
}

Solution to task 2: Invoke the addTwoNums function with a number and a string

function addTwoNums(a,b) {
    console.log(a + b)
}
addTwoNums(5"5"// "55"

Solution to task 3: Update the addTwoNums function with a try...catch block

function addTwoNums(a,b) {
    try {
        console.log(a + b)
    } catch(err) {
        console.log(err)
    }
}

Solution to task 4: If the passed-in arguments are not numbers, throw an error

function addTwoNums(a,b) {
    try {
        if(typeof(a) != 'number') {
            throw new ReferenceError('the first argument is not a number')
        } else if (typeof(b) != 'number') {
            throw new ReferenceError('the second argument is not a number')
        } else {
            console.log(a + b)
        }
    } catch(err) {
        console.log(err)
    }
}

Solution to task 5: Update the catch block

function addTwoNums(a,b) {
    try {
        if(typeof(a) != 'number') {
            throw new ReferenceError('the first argument is not a number')
        } else if (typeof(b) != 'number') {
            throw new ReferenceError('the second argument is not a number')
        } else {
            console.log(a + b)
        }
    } catch(err) {
        console.log("Error!", err)
    }
}

Solution to tasks 6 and 7: Invoke the addTwoNums function and Add another console log under the addTwoNums function invocation

function addTwoNums(a,b) {
    try {
        if(typeof(a) != 'number') {
            throw new ReferenceError('the first argument is not a number')
        } else if (typeof(b) != 'number') {
            throw new ReferenceError('the second argument is not a number')
        } else {
            console.log(a + b)
        }
    } catch(err) {
        console.log("Error!", err)
    }
}
addTwoNums(5"5")
console.log("It still works")

Exercise: Defensive programming

Defensive programming is all about assuming that all the arguments a function will receive are of the wrong type,  the wrong value or both.

In other words, you are assuming that things will go wrong and you are proactive in thinking about such scenarios before they happen, so as to make your function less likely to cause errors because of faulty inputs.

How would you then refactor the function given below with defensive programming in mind?

For this exercise, let's make sure that both of the arguments that are passed in satisfy the following criteria:
  • The length of the word parameter cannot be less than 2.
  • The length of the match parameter must be 1.
  • The type of both the word and the match parameters must be string.
You will use the code below to complete your task:

function letterFinder(word, match) {
    for(i = 0; i < word.length; i++) {
        if(word[i] == match) {
            //if the current character at position i in the word is equal to 
the match
            console.log('Found the', match, 'at', i)
        } else {
            console.log('---No match found at', i)
        }
    }
}

Here are the tasks to complete:
  1. Just above the for loop in the letterFinder function definition, declare a variable named condition1 and assign to it the following code: typeof(word) == 'string' && word.length >= 2.
  2. Declare a variable named condition2 on the next line and assign to it and assign to it a check that makes sure that the type of match is a string AND that the length of the match variable is equal to 1.
  3. Write an if statement on the next line that checks that condition1 is true, and condition2 is true
  4. Move the rest of the function's body into the if statement you wrote in the previous step.
  5. Code an "else" block after the "if" condition and console.log the following: "Please pass correct arguments to the function.".
  6. As a failing test, run the letterFinder function and pass it with any two numbers as arguments.
  7. As a passing test, run the letterFinder funciton and pass it with correct arguments, such as: letterFinder("cat", "c").
Solution: Defensive programming

Answer (full completed code)

function letterFinder(word, match) {
    var condition1 = typeof(word) == 'string' && word.length >= 2//if the word 
is a string and the length is greater than or equal to 2
    var condition2 = typeof(match) == 'string' && match.length == 1//if the 
match is a string and the length is equal to 1
    if(condition1 && condition2) { //if both condition matches
        for(var i = 0; i < word.length; i++) {
            if(word[i] == match) {
                //check if the character at this i position in the word is equal to the match
                console.log('Found the', match, 'at', i)
            } else {
                console.log('---No match found at', i)
            }
        }
    } else {
        //if the requirements don't match
        console.log("Please pass correct arguments to the function")
    }
}
letterFinder([],[])
letterFinder("cat","c")

QUIZ 2 - Error handling


Additional resources

Here is a list of resources that may be helpful as you continue your learning journey.



WEEK 3 - Programming Paradigms

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:

Return values from functions

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.

The functional programming paradigm

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
  • retur n 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.

Visual Studio Code on Coursera

In addition to having Visual Studio Code installed on your own computer, in this course and throughout this program, you'll have the opportunity to work in Visual Studio Code right here on Coursera!   

As you progress through the course, you'll be able to write code in hands-on activities called Labs.  In these labs you'll be able to open Visual Studio Code and start writing code without ever leaving the course.

You'll have plenty of opportunities to see Labs in action later in the course, but for now, use the images below as a visual guide to how Labs will look and operate in your browser.

The Labs contain instructions explaining the coding task.


When you click the button to open the lab, a new tab will open with Visual Studio Code already setup and ready for you to start writing code!


You'll see all the files for the lab in the Project folder in the left sidebar.


And the large editor area where you write your code for the lab.


You may need to use a tool called the Terminal from time to time to complete course activities. You can open this by selecting the Terminal option in the upper Visual Studio Code toolbar.


How to download files from your Visual Studio Code Lab to your local device
  1. Select the Lab Files button in your Lab Toolbar. 
  2. You'll be able to download your full workspace, specific folders, or individual files through the checkbox selection tool. 
  3. After you've selected these files, use the Download link to download your files to your local device. 

How to upload local files to your Visual Studio Code Lab

If you'd like to upload your course files from your local device to your Visual Studio Code lab, drag and drop your file from your local device into the Visual Studio Code file tree.


How to get a fresh copy of course-provided starter files

Your work will be saved and persist within your Visual Studio Code lab while you are enrolled in the course. If you'd like to get a fresh copy of the original instructor-provided files at any time, you can do this through the Lab Help option in your Lab Toolbar.  Don't worry - your original work and files will still remain in your lab until you personally remove or delete them, even when refreshing your files through the steps below.

1. First rename your original files to something like [yourfilename] [original].[your file extension]`. You can do this by right-clicking on your file in the Visual Studio Code file tree, selecting Rename, and providing a new file name.
  • For example for index.html, this could be renamed to `index [original].html`
2. Select Lab Help from your Lab Toolbar and then select Get latest version. 


3. You should now see a fresh copy of the original instructor-provided files in your lab, in addition to your own  (renamed) files.

QUIZ 1 - Introduction to Functional Programming


Additional resources

Here is a list of resources that may be helpful as you continue your learning journey.

MDN Functions Guide
MDN Glossary: Recursion
MDN Glossary: Scope
Functional Programming in JavaScript
MDN: First-class functions

Object Oriented Programming principles

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)

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)

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)

// create your classes here

Constructors

JavaScript has a number of built-in object types, such as:

 MathDateObjectFunctionBooleanSymbolArrayMapSetPromiseJSON, 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/); // null
"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".

Creating classes

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: 
  1. This code allows me to build new instances of the Train class. 
  2. 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().
  1. 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.
  2. The lightsStatus() method on the Train class just reports the current status of the lightsOn variable of a given object instance.
  3. The getSelf() method prints out the properties on the object instance it is called on.
  4. 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(200false'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(200false'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: 
  1. 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. 
  2. 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) //

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

Default Parameters

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.
Designing an OO Program

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!

QUIZ 2 - Introduction to Object-Oriented Programming


Additional resources

Here is a list of resources that may be helpful as you continue your learning journey.

Constructor
Classes
Object-oriented programming
Regular Expressions in JavaScript
RegExp object in JavaScript


For of loops and objects

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']


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( key of Object.keys(clothingItem) ) {
    console.log(keys, ":", 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();


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.


Template literals examples

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.

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.


Data Structures examples

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:

  1.  forEach 

  2. filter

  3.  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}${fruit}`);
});


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.


Using Spread and Rest

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 = [...fruits]
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.


QUIZ 3 - Advanced JavaScript Features


Additional resources

Here is a list of resources that may be helpful as you continue your learning journey.

Template literals
Arrow functions
Spread syntax
Rest parameters
JavaScript data structures

JavaScript interactivity

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.

Exercise: Web page content update

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.

Exercise: Capture Data

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.


Solution: Capture Data

Task 1 solution: The example.com website
  1. Open your favorite browser and navigate to https://example.com/.
  2. 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.
  3. 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.
Website example.com with developer tools open

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);

An example of the solution being run in the browser:

Moving data around on the web

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.


 QUIZ 4 - JavaScript in the browser


Additional resources

Here is a list of resources that may be helpful as you continue your learning journey.

MDN: Modules
Nodejs.org official docs on CommonJS
MDN: DOM
MDN: Document.querySelector
MDN: Event
MDN: EventTarget.addEventListener
MDN: Working with JSON


WEEK 4 - Testing

Here you will learn about Node.js and Node Package Manager (npm). And you will explore how to install npm packages and how to work with package.json. Furthermore, you will learn about testing in JavaScript and you'll code a simple unit test in Jest. After completing this module, you will be able to:

Installing Node and NPM

Before installing Node.js and npm on your machine, you first need to verify if it's already installed.  

Verifying the existing installation on Windows
On Windows, you can use the WINKEY+r shortcut key, which opens the Run window. Inside the Open: input of the Run window, type cmd and press the enter key. This will open the command prompt.

Inside the command prompt, type:

  • node --version

If there is Node.js installed on your Windows OS, it will return a value similar to this:

  • v16.14.2


Then you can confirm that you have npm as well, running this:

  • npm --version

 

If npm is installed, you'll get output similar to this:

  • 8.5.0


Verifying the existing Node.js and npm installation on Ubuntu (Linux)
You can quickly open a new bash (terminal) window on Ubuntu by pressing the CTRL+ALT+t shortcut key.

In the bash window that opens, type:

  • node --version && npm --version


Both version numbers should appear in the bash window.  

Installing Node.js and npm

On Windows OS
In case Node.js and npm are not installed on your Windows OS, navigate to https://nodejs.org. 

Locate the big download button, listing the LTS version. As of May 2022, the LTS version available for download is 16.15.0.

On Mac OS - XCode
To install brew, you need to install Xcode first. Homebrew does not come with its own compiler and it needs Xcode installed for it to work correctly. To install Xcode do the following:

Open a terminal.
Run the following: 
shell xcode-select --install

A popup will appear asking you to confirm the installation. Click on the Install button.
Agree to the license agreement.

brew
Macs do not come with package managers like most Linux distributions. To make up for this an external tool called brew was created. To install brew, go to the official website  (   https://brew.sh/   )  and copy the command provided, open a terminal and run the command :

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/
HEAD/install.sh)"

Once Brew is insatalled you can run the following command in the terminal

brew install node

Homebrew will download and install the dependancies, once this is complete, confirm the installation by typing 

node -v

This will display the Node.js version

Type :

npm -v

to display the NPM version number.

On Ubuntu
Use the CTRL+ALT+t shortcut key to open a new bash window, then run the following commands:

  • sudo apt update

  • sudo apt install nodejs

That's it, you should be all set.

For a more advanced set up and troubleshooting, please refer to the additional reading.

QUIZ 1 - Introduction to testing


Additional resources

Here is a list of resources that may be helpful as you continue your learning journey.


WEEK 5 - End of Course Graded Assessment

In the final module, you'll synthesize the skills you gained from the course to create code for the "Little lemon receipt maker. After you complete the individual units in this module, you will be able to take the graded assessment. You'll also have to opportunity to reflect on the course content and the learning path that lies ahead.

About the Little Lemon receipt maker exercise

In this exercise, you will work with some data provided as an array of objects, listing information about dishes available in the Little Lemon restaurant.

You will need to write a function declaration which will be able to do two things:
  1. If the function is called with the argument true, it will output the names of the dishes and calculate their final price (including 20% tax)
  2. If the function is called with the argument false, it will output the names of the dishes and give their prices without the additional tax
The expected outcome is that all the dishes' names and prices will be shown in the console output.

The text below shows the output that your code should produce:

Prices with 20% tax:
Dish: Italian pasta Price (incl.tax): $ 11.46
Dish: Rice with veggies Price (incl.tax): $ 10.38
Dish: Chicken with potatoes Price (incl.tax): $ 18.66
Dish: Vegetarian Pizza Price (incl.tax): $ 7.74

Prices without tax:
Dish: Italian pasta Price (incl.tax): $ 9.55
Dish: Rice with veggies Price (incl.tax): $ 8.65
Dish: Chicken with potatoes Price (incl.tax): $ 15.55
Dish: Vegetarian Pizza Price (incl.tax): $ 6.45

Next steps

Congratulations! You've taken another step toward improving your knowledge, skills, and qualifications. 

The next course is React Basics and in it, you'll develop a working knowledge of React. React is a powerful JavaScript library that you can use to build user interfaces for web and mobile applications (apps). In this course, you will explore the fundamental concepts that underpin the React library and learn the basic skills required to build a simple, fast, and scalable app.

Be sure to take the next course. It’s your chance to gain further insight into the world of software development. 

 THANK'S FOR READING

No hay comentarios:

Publicar un comentario

Foundations: Data, Data, Everywhere

Google Data Analytics Professional Certificate COURSE 1: Foundations: Data, Data, Everywhere Certified course payment here About this Course...