Skip to content

Week 3 - Numbers, Math, Dates, & Loops

In JavaScript, a number value can be an integer or a float value. This means that it can include decimal values. A Number is one of the JavaScript primitive datatypes, which means that it just a value.

If you have experience with other programming languages, you may have used datatypes like int, unsigned int, double, or long. These are all numeric datatypes that constrain the numbers to a specific size. In other words, how many bits, or how much memory is needed to hold the numeric value. In JavaScript, we have Number. It holds all numeric values. That is to say, all numeric values in the safe range. There are a few properties that we can look at for this range.

Number.MAX_SAFE_INTEGER static data property represents the maximum safe integer in JavaScript (253 – 1). There is also Number.MIN_SAFE_INTEGER which is the smallest integer that can be saved in JavaScript -(253 – 1).

JavaScript also has Number.MAX_VALUE which is 21024 - 2971, or approximately 1.7976931348623157E+308 (1.7976931348623157 x 10308). This is the largest value that can be stored in JavaScript. Values larger than that will be saved as Number.Infinity. There is also a MIN_VALUE version of this too.

The difference between MAX_SAFE_INTEGER and MAX_VALUE is that the MAX_SAFE_INTEGER is the largest EXACT integer value that you can store. MAX_VALUE is the largest positive finite value a JavaScript Number can represent. It’s not about integer precision, it’s about the largest value before you overflow into Infinity. An approximation of this idea could be shown with the number 1,111,111. The integer is 1,111,111. But we could represent it as 1.111 x 106. The second version is a close approximation of the integer. By using this notation we could hold larger values without the same level of precision.

For Numbers beyond the MAX_SAFE_INTEGER range, we can use a new datatype called BigInt. More about this later.

However, just like Strings, there is also a Number Object which will be created behind the scenes for when it will be needed. This gives us a few number methods that we can use.

The Number Object has some methods that you would call directly from the number primitive variable, just like we did with the String methods. It also has a few methods that get called from the Number object directly and they want to be passed some other variable because they want to examine that other variable to see if it is numeric or if it could be converted to into a number primitive.

let num = 3.14;
//these first two methods are called on the number object created for the variable `num`.
num.toFixed(2); //round off the number to a specific number of decimal points
//Method returns a STRING
num.toString(); //returns what you see in the variable str
let strFloat = '3.14'; //A string that contains a numerical float values
let strInteger = '7'; //a string that contains an integer value
//these other methods use the Number Object container, not the variable
//they ask for a string
Number.parseInt(strFloat); //convert the number to an integer.
//Method returns an integer
Number.parseFloat(strFloat); //returns the float version of
Number.isNaN(strFloat); //check if the number in the variable is Not A Number (NaN)
//returns a true or false (Boolean)
Number.isInteger(strInteger); //checks if the value in the variable is an integer.
//returns true or false. False if the number has decimals eg: 3.14

Every value that is stored in a traditional, non-quantum, computer is stored as a series of ones and zeros, known as bits. Commonly these are grouped together 8 bits at a time. 8 bits is known as a byte.

Network speeds are measured in how many bits that they can transmit or receive per second. A 1Gb connection means that you can receive 1 Giga-bits (1,000,000,000) per second. Note the lowercase b in Gb.

Device storage is measured in bytes. If your laptop has a 512GB Solid State Drive then it can hold 512 GigaBytes of data. Note the capital B in GB.

When you are looking at the data stored or transmitted as a string of ones and zeros then you are actually looking at numbers that are written in base-2. Base-2 means that there are only 2 possible digits allowed to be used when writing a number. Base-10 is what we normally use in our daily life. We are familiar with the digits 0 - 9. Ten different digits meaning base-10.

Another common base is hexadecimal, also known as base-16. This is one of the ways you can write your colours in CSS. #FF0014 is a valid CSS colour written in hex. The red value is FF which in base-10 is 255. The green value is 00 or 0 which is the same in any base. The blue value is 14 in hex or 20 in base-10.

Numbers can be written in any base. It doesn’t change the value, it is just a different way of representing it.

So, why do we use FF as the biggest value for a colour channel?

  • Decimal (base-10) 255
  • Hexadecimal (base-16) FF
  • Binary (base-2) 1111 1111 - the way it is stored/represented in your computer

The number 255 or FF is the biggest number you can hold in a single byte.

Ever heard people talk about 24 bit or 32 bit images? how about 32 or 64 bit processors? They are talking about the number of bits that need to be used to represent the each colour pixel in the image or the number of bits that get used at a time by the CPU.

A jpg is a 24-bit image. It needs 8 bits for red, 8 bits for green and 8 bits for blue for each pixel. It has no transparency. A png can be a 32-bit image. The extra 8 bits per pixel are to represent the level of transparency for that pixel, on top of the red, green, and blue.

What about counting in binary or hex?

The way counting works in any base is actually the same. In base-10 you have 10 possible digits. Once you have used all the digits, add another column set to 1 and then go through the 10 possible digits again in the original column. Repeat until you have been through every combination and then add another column.

In base-16 (hexadecimal) we need 16 different digits. So, where do we get the last 6 after 9? We use the letters A-F.

In base-36 we use 0-9 plus the full alphabet.

In base-64 we use 0-9, plus a-z, plus A-Z, which gives use 62 digits and then + and / as the last two digits. = is also used as a special character in base-64. Base-64 is a special thing though used for encoding strings and data for transmission and storage. The counting through the digits works the same but it’s purpose goes beyond just representing numeric values.

Here are some examples with decimal, binary, and hex:

0 0 0
1 1 1
2 10 2
3 11 3
4 100 4
5 101 5
6 110 6
7 111 7
8 1000 8
9 1001 9
10 1010 A
11 1011 B
12 1100 C
13 1101 D
14 1110 E
15 1111 F
16 10000 10
...
97 1100001 61
98 1100010 62
99 1100011 63
100 1100100 64
101 1100101 65
102 1100110 66
...
254 11111110 FE
255 11111111 FF
256 100000000 100
...
998 1111100110 3E6
999 1111100111 3E7
1000 1111101000 3E8

Here is a shared Google Sheet (⌘ + click) to open, with the decimal values 0 - 260 written in decimal, binary, hexadecimal, and octal.

To write your numeric values specifically in decimal we just write the number. If we want to write a number in base-8, base-2, or base-16 then there is special notation we can use.

All four variables in the following snippet have the same value, 20, just written with different bases.

//default base is always 10
let twenty = 20;
//write a hex value by putting `0x` first
let twentyHex = 0x14;
//write a binary value by putting `0b` first
let twentyBinary = 0b10100;
//write an octal value by putting `0o` first
let tenOctal = 0o24;

Number bases for non-math lovers

Binary and Bitwise Operators

Images and other binary files are just containers for binary information. If we look at the contents inside these files, instead of text, we just see numbers. They are basically an array of bytes. A byte is a number between 0 and 255. So, a binary file is a ByteArray.

const myByteArray = new Uint8Array(8); //8 bytes long
myByteArray[0] = 32;
myByteArray[1] = 255;
myByteArray[7] = 127;
console.log(myByteArray);
// Expected output: Uint8Array [32, 255, 0, 0, 0, 0, 0, 127]

If we want to store the contents of a binary file as text, we can use base-64 as a way to encode these numbers.

If we needed to store the data from an image file inside a text file, we could do this as a list of numbers. However, a better approach is to convert the value into a base-64 encoded String.

We can take our ByteArray from the previous example and convert it into a base-64 encoded string like this:

let string64 = window.btoa(myByteArray);
console.log(string64);
//Expected output: MzIsMjU1LDAsMCwwLDAsMCwxMjc=

That string can be included in any text file as part of the data, alongside strings, booleans, and numbers. Watch the following video to learn more about this method of encoding and decoding.

All you need to know about base-64

All the basic mathematical operations can be done in JavaScript.

let answer = 1 + 2; //addition
let answer = 2 - 1; //subtraction
let answer = 2 * 2; //multiplication
let answer = 4 / 2; //division
let answer = 3 ** 2; //exponents 3 to the power of 2
let answer = 9 % 4; // modulo
// 9 divided by 4 and then return the remainder of 1

A frequent operation in programming is to repeatedly add or subtract one or the same value from a number.

let i = 7;
//add one to i
i = i + 1;
//short hand syntax to increment i
i += 1;
//or we can use the increment operator to add one
i++;
//subtract one from i
i = i - 1;
i -= 1;
i--; //decrement operator

All three versions in the above snippet are doing the same thing - they are adding or subtracting one from the variable i.

If the value that you want to add or subtract from your variable is something other than one, then you can use either of the first two approaches.

let num = 0;
let increment = 5;
num = num + increment;
num += increment;
num = num - increment;
num -= increment;

The ++ and -- operators will always add or subtract one.

JavaScript has a Math object which can carry out most common mathematical operations. If you need to round numbers up or down, complete Trigonometric calculations, determine which is the largest or smallest number, create a random number, determine if a number is positive or negative, or access the value of Pi π. All of these things can be accomplished with the Mathematical methods.

These methods all begin with the Math object name.

Math.round(num); //returns the next highest or lowest integer depending on its decimal value.
Math.floor(num); //always rounds down to the next lowest integer
Math.ceil(num); //always rounds up to the next highest integer
Math.random(); //returns a random value between 0 and 1.
Math.max(list, of, numbers); //returns the largest number from the list
Math.min(list, of, numbers); //returns the smallest number from the list
Math.abs(num); //returns the absolute value of the number
Math.sign(num); //returns 1, -1, 0, -0, NaN to tell you if the number is positive or negative
Math.sin(radians); //returns the sine value for the provided radian value
Math.cos(radians); //returns the value of Cosine for the provided radian value
Math.tan(radians); //returns the value of Tangent for the provided radian value
Math.PI; //Use this as if it were a variable holding the value of Pi

JS Math Object

And there are many more Numeric and Mathematical methods available. I encourage you to read through the list on the MDN site.

Not A Number (NaN) is an Object in JavaScript that represents a value that is “Not A Number”. You only get this value when you are trying to run a Number or Math that requires a numeric value.

There is also a global method isNaN(), which is specifically designed to check if the value in a variable is a numeric one. Just pass a value or variable to the method and it will run the test and return a boolean.

It returns true if the variable value is NOT numeric and false if the value IS a numeric one.

let a = 'I am a string';
let b = false;
let c = 123;
let d = 123.45;
let e = '42';
isNaN(a); //true
isNaN(b); //false - surprisingly a Boolean is treated like 0 or 1 for false and true. A single bit.
isNaN(c); //false
isNaN(d); //false
isNaN(e); //false

NaN and isNaN

As mentioned before, BitInt is one of the primitive types which means that it is just a value. It is used specifically when you need to store a really big number that exceeds the Number.MAX_SAFE_INTEGER to Number.MIN_SAFE_INTEGER range.

This is not something that you are likely to encounter or need during this program.

To write a BigInt in your code just append a lowercase n at the end of the number or use the BigInt() constructor method.

//numbers over 9007199254740992 is the intended use
let big = 9007199254740999n;
//but you can store smaller numbers as the BigInt type
let otherbig = 1000n;
//you can use the BigInt construtor to create one too.
const huge = BigInt(9007199254740991);

BigInt MDN reference page

Binary numbers are simply the representation of any number using base-2. When you see something written in binary it will be all ones and zeros, like this: 01100101 01100001 01110011 01110100 01100101 01110010 00100000 01100101 01100111 01100111.

If you want to write a number in Binary in JavaScript just start the number with a zero then a lowercase b.

let binaryTen = 0b00001010;
//this is the number 10 in binary

The Bitwise operators allow us to use JavaScript and work with numbers at the binary level.

& - binary AND operator

The binary & operator is used to AND two numbers at the binary level

11001010
& 00001111 //the result of this is 00001010

For each bit we compare the values in each column and if both are a 1 then the result in that column is 1.

The bitwise OR operator is | the pipe character. It will compare two binary values and if either number in the column is a 1 then the result is a 1.

The bitwise NOT operator is ~ and it will flip the bits in a number. All the zeros become ones and all the ones become zeros.

The bitwise XOR operator is ^. It will compare two binary values and return a one in each column where either bit is a one. If both bits are a one or if both bits are a zero then it returns a zero.

Sometimes we want to trim off the last few digits of a binary number or we want to add some more digits. The shift operators let us do that. The best example of this is when we want to extract the red, green, and blue parts of a colour value.

Hex colours are made up of three values 00-FF, 00-FF, and 00-FF. Each one is a number between 0 and 255.

In binary, 255 is 11111111. That is 8 ones. So, for each colour there are 8 bits. The colour white is (255, 255, 255) or #FFFFFF.

In binary white would be 11111111 11111111 11111111. That is why Jpegs are called 24 bit images. Each pixel is a colour made up of 24 bits. Black would be represented by 24 zeroes - 00000000 00000000 00000000.

If you write 24 ones as a decimal number it is 2 to the power of 24 or 16,777,216.

A random colour would be a value between 0 and 16,777,216.

So, if we had the random number 1,654,344, in binary that would be 00011001 00111110 01001000. The first 8 bits represent the red colour, the middle 8 bits are the green value, and the last 8 bits are the blue value.

If you want to extract those three parts of the one colour, we will use the shift operator.

For the red colour, we will shift the bits 16 places to the right. Basically, we are stripping off the rightmost 16 bits. Leaving us only the first 8 bits 00011001. In decimal, that would be - 25.

For the blue colour, we will use the AND operator. We AND the whole number with 255 (or 11111111). This will make the left most 16 bits zero. Only the 8 right most bits could possibly line up with our 255. The result will be 01001000 or 72.

For the green colour we need to do both things - shift over 8 bits and then AND the right most 8 bits with 11111111 (255). The green portion 00111110 is 62.

So, the RGB version of 00011001 00111110 01001000 is rgb(25, 62, 72).

Here are some CodePens using the Bitwise operators.

Generating a Random Colour, Displaying it in RGB with Contrasting Text

Section titled “Generating a Random Colour, Displaying it in RGB with Contrasting Text”

Try clicking the rerun button to see a new colour being generated.

Converting from HEX to decimal numbers for Colours

Section titled “Converting from HEX to decimal numbers for Colours”

Try changing the HEX value inside the input and see the conversion to RGB values and the change to the colour bar at the bottom.

Codepen calculating Odd and Even - open this one in a new page and open the development tools console to see the results. Run it in fullpage or debug view to access the dev tools and see the results.

Here is the script from that CodePen. When you run it, you will see that the bitwise version almost always runs faster by roughly 5% faster.

let maxNum = 1e6; //one million
let biggestEvenNum, biggestOddNum;
console.time('bitwise');
for (let i = 0; i < maxNum; i++) {
if (i & 1) {
//odd
biggestOddNum = i;
} else {
//even
biggestEvenNum = i;
}
}
console.timeEnd('bitwise');
console.time('modulus');
for (let i = 0; i < maxNum; i++) {
if (i % 2 == 0) {
//even
biggestEvenNum = i;
} else {
//odd
biggestOddNum = i;
}
}
console.timeEnd('modulus');

Tutorial about Bitwise Operators

A practical use for Bitwise operators, beyond calculating odd or even, is saving user permissions inside a single number.

Bitwise Permissions

MDN reference for Bitwise operators (⌘ + click) to open

If you were writing HTML then you could add a <time> element and write a string that represents a Date. However, this would not be an object that you could use in your script. JavaScript comes with a Date object that you can actually manipulate, convert to different times, calculate time differences, and work with just the time or just the date value.

There is a new Temporal object that is under development. It will give us a lot more control over things like time zones, time ranges, and international formatting. See below for more details about Temporal. Until that happens, we still have a basic Date object that we can use for all our basic needs.

There are actually a few different ways that you can call the Date constructor method.

let today = new Date(); //create a Date object with the current time and date from your computer.
let date1 = new Date('28/9/2016 14:30:00.000'); //a formatted string
let date2 = new Date(2016, 9, 28, 14, 30, 0); // yyyy, mm, dd, hours, mins, seconds
let date3 = new Date(1500000000000); //a timestamp with the number of milliseconds since Jan 1 1970, 12am

The first line above will create a new Date object and it will fill it with the current date and time from the computer that is running the script.

The second line creates a new Date object and sets a specific date and time. We pass in a String with a valid date and time. The values for day, month, year, hour, minutes, seconds, and milliseconds would be set inside our Date object. The String that is passed in must be a date string that would be recognized by the Date.parse( ) method. See here for examples (⌘ + click) to open

The third line accepts up to seven arguments for the parts of the Date. The last argument is the milliseconds. dt2 will contain the same date as dt1 from the example code.

The last line accepts a timestamp, which is the number of milliseconds since the start of the Unix Epoch -> Jan 1, 1970 00:00:00.000Z. In July of 2017 we passed the 1.5 Trillion mark for milliseconds in the current timestamp. You can pass any number to this method to set the time and date inside the Date object.

If you want to update any part of the date or time then we use one of the following methods.

today.setHours(12); // from 0-23. OR setHours(hour, mins, seconds, milliseconds)
today.setMinutes(3); // from 0-59. OR setMinutes(mins, seconds, milliseconds)
today.setSeconds(50); // from 0 - 59 OR setSeconds(seconds, milliseconds)
today.setMilliseconds(123); // from 0 - 999
today.setFullYear(2044);
today.setMonth(0); //value from 0 - 11 (like an array) OR setMonth( month, day)
today.setDate(); //value from 1 - 31 invalid dates will move forward to a valid one
Date.UTC(y, m, d, hr, min, sec, ms); //creates a date object and returns the timestamp
//equivalent of the date

If you want to retrieve any part of the date or time then you can use the matching “get” methods. Start with using your Date variable and then call the method on the variable

today.getHours();
today.getMinutes();
today.getSeconds();
today.getMilliseconds();
today.getFullYear();
today.getMonth(); // value from 0 - 11
today.getDate(); // value from 1 - 31
today.getDay(); //day of week Sunday (0) - Saturday (6)
Date.now(); //Using the Date object, call now( ) to get a timestamp
//which is the number of milliseconds since the start of the UNIX Epoch
//midnight January 1, 1970

There are many methods for outputting the date object’s value. Here is a list of the various methods.

today.toDateString(); //returns the date portion in human readable format
today.toTimeString(); //returns the time portion in human readable format

MDN toDateString reference (⌘ + click) to open

MDN toTimeString reference (⌘ + click) to open

today.toISOString(); //returns a string in simplified extended ISO format

MDN toISOString reference (⌘ + click) to open

today.toJSON(); //converts the date to a string intended to be used in JSON

MDN toJSON reference (⌘ + click) to open

today.toLocaleDateString('en-CA'); //returns a string representation based on the
//computer's locale settings or provided locale
today.toLocaleString('en-GB'); //same thing effectively
today.toLocaleString('en-US');

MDN toLocaleDateString (⌘ + click) to open

MDN toLocaleString (⌘ + click) to open

today.toUTCString(); //returns the date string using UTC time zone

MDN toUTCString reference (⌘ + click) to open

In the JavaScript Date object, months are stored as a number between 0 and 11.

If you want to see or use the name of the month then you need to create your own array of the month names and use the Date object month as the index for that array.

let months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Sep', 'Oct', 'Nov', 'Dec'];
let today = new Date();
console.log('Current month is:', months[today.getMonths()]);

The unary + operator is an easy way to convert a date into its numeric timestamp.

let today = new Date();
let timestamp = +today; //convert the value in the date to a timestamp
let timestamp = +new Date(); //convert the current computer time to a timestamp
let timestamp = Date.now(); //use the Prototype/Class/Static method
let timestamp = today.valueOf(); //get the timestamp of a specific date

Timestamp Video

MDN Date object reference (⌘ + click) to open

Date Object

Date objects are something that you will use more when we start working with web pages and JS in the browser. The following video gives a basic start to building a clock in the browser.

Display Time as a Digital Clock

And to understand more about how animation and looping works in the browser and how to build a more accurate clock, the following video from HTTP 203 will give you lots to think about.

JavaScript Counters the Hard Way

If you are building something that works with a lot of dates or times then it can help to have a JavaScript library that you can use. MomentJS is a great JS library http://momentjs.com/ (⌘ + click) to open for formatting and validating dates.

There is a new updated version of MomentJS, built by one of the team members from MomentJS, called Luxon. It incorporates the latest browser support for multilingual and timezone operations.

Luxon tutorial

Both the Moment.JS and Luxon libraries will be redundant once the new Temporal time and date Object becomes standardized. The Temporal object has been under review for a couple years now, but we do expect it to happen soon.

The new Temporal type for dates and times has been recently released in Firefox. It has been added to the code in V8, but is not released yet.

The Github repo for Temporal is here (⌘ + click) to open.

The english documentation for Temporal is here (⌘ + click) to open.

The polyfill for Temporal is here (⌘ + click) to open. This link is for the Beta version of the library.

Even MDN already has an official page for Temporal (⌘ + click) to open. This is the most positive sign that it is coming soon.

I would recommend that you read the documentation and learn HOW to use Temporal. It will be coming soon. It will gradually replace all the current Date and Time code currently being used.

The polyfill is how you can add support for Temporal today. There are two ways to use it. If you are building a project with Node packages and you are going to be using a build process then you can add it to your project with:

Terminal window
npm install temporal-polyfill

Then, in your script file you can import the library:

import { Temporal } from 'temporal-polyfill';

If you are not using Node and a build process for your website, then you can just add a script to include the Temporal polyfill. Just adjust the version number in the path as it changes. Make it the FIRST script tag on your page.

<script src="https://cdn.jsdelivr.net/npm/temporal-polyfill@0.3.0/global.min.js"></script>

With that added to your HTML or imported in your script you can access the Temporal object.

console.log(Temporal.Now.zonedDateTimeISO().toString());

A loop is a very common programming structure. It is actually part of the control-flow category that we discussed last week.

The purpose of a loop is to repeat one or more commands, as quickly as possible, a specific number of times or until a condition is met.

First, lets review why we have loops. They are a common feature in programming languages. Say, for example, that you wanted to create a list of five random numbers. You could declare five variables and use the Math.random( ) method to generate the numbers and assign them to the variables. We could do this with just repeating the same line of code five times.

let num1 = Math.random();
let num2 = Math.random();
let num3 = Math.random();
let num4 = Math.random();
let num5 = Math.random();

While a bit tedious, you can do this without too much effort.

Now, imagine that you need to save a thousand random numbers, or ten thousand. That would be a LOT of code to write. Loops are a programmatic way of accomplishing a similar task in a repetitive manner with minimal code. Here is an example that would generate 100,000 random numbers and save them all in an Array.

let nums = [];
for (let i = 0; i < 100000; i++) {
nums.push(Math.random());
}

That’s it. Four lines of code. 100,000 random numbers generated and saved in an Array. An Array is a numbered list. We will talk about them in detail next week.

Array objects also have built-in methods for looping over all the items inside them. We will talk about those and use them a lot over the next few semesters. The loops discussed on this page can be used with Arrays as well as pretty much any time you need to do something repeatedly.

The example above is the standard for loop. The code inside the parentheses is split into three parts. The three parts are divided by semi-colons. ;

  1. Initialization. Declare local variables for the loop. Usually just a variable that can be used to count the number of iterations of the loop. Commonly known as the counter variable. This part runs before any looping begins. You can declare as many variables as you want here, separating each declaration with a comma.
  2. Test condition. Normally this means comparing your counter variable to a maximum or minimum value. The loop will run this test once before each iteration of the loop.
  3. Increment/Decrement. Every time the loop finishes running the commands that are inside the curly braces, this part of the code runs. It runs after the commands and before the next test.

For Loops

For loops are the most common type of loop. They can be used for practically any situation that needs a loop because they are flexible.

A second type of for loop is the for...in loop. These are used to loop through a list of items that have a known number of items. They work with Objects that are iterable. We will talk more about this in the future. For now, just think of it as a short hand way to loop through an Array.

for (let prop in myArray) {
// output each value in the Array, one at a time.
console.log(myArray[prop]);
}

We will not use these very often but it is good to be familiar with them.

For..in Loops

These are closely related to for…in loops but let you target the value without having to use dot notation or the square bracket syntax. If you don’t need the index number of the array or the property name from the object then this might be of value to you.

For..in Loops

There is a difference between for...in and for...of is that for...of cannot loop over most Objects. This has to do with the difference between Iterable and Enumerable, which we will talk about later.

For those of you who are keen to understand this now:

iterable vs enumerable

Looping and Recursion

Nested Loops

There are two kinds of while loops in JavaScript, the while loop and the do..while loop. The difference between them is that the do..while loop will always run at least once because it runs the loop before checking to see if the while test passes. The while loop will test your condition before it runs the loop.

var counter = 0;
while (counter < 10) {
console.log(counter);
counter++;
}
var counter2 = 0;
do {
console.log(counter2);
counter2++;
} while (counter2 < 10);

MDN while loop ref

While Loops

There is one other variant of the while loop called do while.

do {
console.log(i); //output the value of i
i++; //increment the value of i
} while (i < 100);

Looks pretty much the same as the original while loop, right?

The difference is that the do while loop will ALWAYS run at least once. The test condition does not run until after the loop. The while loop does the test before starting.

When using while loops you do need to be careful that you don’t create an infinite loop condition. That is a loop that never ends. When this happens your code can quickly use up all the system resources and even make the browser crash.

While modern browsers are pretty good at avoiding the crash part, it will still result in your code ceasing to run.

Consider the code example below. That loop will never end. The value of isRunning will always be true.

let i = 0;
let isRunning = true;
while (isRunning) {
console.log(i);
i++;
}

We need some test condition to make the loop stop running. Inside the loop we can test the value of i and if it exceeds a desired value then we can change the value of isRunning.

while (isRunning) {
console.log(i); //output the value of i
i++; //increment the value of i
if (i > 100) {
isRunning = false;
}
}

Now the next check that while(isRunning) does will exit the loop.

What about times when we can’t change the value of the test condition?

Thankfully there is a keyword - break which can be used to immediately exit a loop (or switch statement).

const shouldStart = true;
//pretend that shouldRun was declared elsewhere and passed to the function.
//and we have no way to change it's value.
while (shouldStart) {
console.log(i); //output the value of i
i++; //increment the value of i
if (i > 100) {
break; //immediately exit the loop before the next check of shouldStart
}
}

There are two keywords that are not common but you should be aware of them.

break is used when you want to exit entirely from a loop. It can be used in for, for..in, for..of, while, or do..while loops. In the following snippet, only the numbers 0 and 1 will be output.

for (let i = 0; i < 100; i++) {
console.log(i);
if (i > 1) {
break;
}
}

continue is used when you want to increment or decrement to the next counter value, or whatever the next iteration is, in your loop. In the following snippet, nothing ever gets output. The whole loop iterates but the console.log is never called.

for (let i = 0; i < 100; i++) {
continue;
console.log(i);
}