Categories
JavaScript JavaScript Basics

Using HTML5 APIs in Your Web App

HTML5 brings a lot of exciting new features for developers to enhance their web apps. It allows developers to access data from new hardware and adds multimedia capabilities that weren’t available before and required plugins. Some new things include audio and video APIs, WebRTC for streaming video and audio, accessing battery data from mobile devices, location a device’s physical location, and much more.

The API specifications are very detailed. Everything is defined up to the level of individual functions that developers can call to make sure the APIs exist. For example, we can call functions in the Battery Status API to get the battery level of a device and use properties to access the battery level and charging status. The specification is very precise, and it tells developers what to do to make use of the APIs. We can know how APIs interact with the software that uses it and how the software should deal with the results returned from the API. There are still many APIs that are not finalized yet and shouldn’t be used in production. They are experimental and are subject to breaking changes.

Every browser has different levels of supports for the new APIs. You must check carefully to see if the browsers you want for your web app work with the desired APIs. However, in most cases, support for the most popular APIs more consistent among the most popular browsers.

To check for API support for different browser APIs, we can use the Mozilla Developer Network documentation located at https://developer.mozilla.org/en-US/ or use websites like www.caniuse.com which lists all the APIs and the browser support for each. We can see which versions support it in the details so we can handle the usage correctly.

The following are some of the APIs that are in the HTML5 API specifications:

  • Battery status: lets us check the battery status of a device
  • Clipboard: lets us copy content to the operating system’s clipboard
  • Drag and drop: lets us add drag and drop items around our apps
  • Fetch: lets us make HTTP requests more easily than with XMLHttpRequest
  • File: lets us access files securely on the user’s computer
  • Forms: added new types that we can use for form validation and render form fields differently
  • Geolocation: lets us locate the device’s location
  • getUserMedia/Stream: lets us retrieve audio and video from an external device like a camera
  • Indexed database: lets us store database data locally
  • Internalization: provides international formatting and string comparison features
  • Screen orientation: lets us check the screen orientation of a device
  • Selection: lets us select elements using CSS selectors
  • Server sent events: allows servers to push data to clients without requesting it on the client-side
  • User timing: lets us get more precise timestamps to measure the performance of our applications
  • Vibration: lets us make devices vibrate if it has this capability
  • Web audio: lets us process audio on the client-side
  • Web speech: lets us add text to speech features into our web apps
  • Web sockets: lets us make real-time communication between client and server
  • Web workers: lets us run tasks in the background in user browsers

Below we’ll discuss some of the most popular HTML5 APIs.

Geolocation API

The Geolocation API allows us to get the physical location of a device when given permission by the user. It is a well-supported API implemented in more than 90% of desktop and mobile browsers. We can get the geolocation information of a device by using the navigator.geolocation object. This gives us information like the latitude, which is given in decimal degrees, the longitude in decimal degrees, the altitude in meters, the direction the device is heading towards, the speed the device is traveling, and the accuracy of the latitude and longitude measured in meters.

When a JavaScript app initiates a request for the device’s position, it has to go through a number of steps before it will be able to receive the data. First, the app must request permission to get the data from the user. This is typically done with a popup or notification.

Once the user allows the app to get the data, then an icon will be displayed indicating that the app can get the data through the Geolocation API. There are a few ways that the data can be obtained. The most accurate is using a device’s GPS. This will take longer but it’s the most accurate way to do it. If GPS is not available or we want it to get the location faster, then we use the device’s wireless network connection, the cell tower that your phone or mobile device is connected to, or the IP address of the device.

Accessing the User’s Location

Geolocation in JavaScript is done with the navigator.geolocation object’s getCurrentPosition method. It takes 3 arguments. The first is a callback for when geolocation data is successfully retrieved. The callback function should have a Position object that we can use to get the data. The second argument is a callback function which is called when getting geolocation data failed. This callback function should have a PositionError object with the details of the error. The third argument is an object with the options for geolocation which controls how location lookup is done.

The Position object that’s in the success callback we pass in in the first argument will have the 2 properties. It has a coords property with the coordinates of the device on Earth, which has the latitude, longitude, altitude, etc., which are all the properties we described before. Also there’s a timestamp property that lets us know when the data was retrieved.

To get the location of a device, we can put the following in a script file:

navigator.geolocation.getCurrentPosition(  
   (position) => {  
     for (key in position.coords) {  
       console.log(key, position.coords[key])  
     }  
   });

When this script is run, the browser will ask for permission to enable geolocation. If we allow that, then we get the data in the position object. When we open the Chrome developer console of our browser and click on the Console tab, we get something like the following:

latitude 41.2833669  
longitude -120.040943  
altitude null  
accuracy 960  
altitudeAccuracy null  
heading null  
speed null

altitude, heading, speed are null because the device isn’t moving and it’s also not moving up or down.

Using the Geolocation API with Google Maps

Using Google Maps, we can convert our latitude and longitude into a location on the map. To do this, we use the Google Map API to add our coordinates. To use the Google Maps API, we have to sign up for an API key. It’s free for low usage situations, but regardless, we have to put in a credit card number to sign up. We can sign up with the ‘Get started’ link on https://developers.google.com/maps and follow the instructions.

Once we sign up, we put the following code to display a Google map of your device’s location. First, in index.html, we add:

<html>  
  <head>  
    <title>Google Map</title>  
    <link href="styles.css" rel="stylesheet" type="text/css" />  
  </head>  
  <body>  
    <div id="map"></div>  
    <script src="script.js"></script>  
    <script  
      async  
      defer  
      src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"  
    ></script>  
  </body>  
</html>

Then in scripts.js, we add:

initMap = () => {  
  navigator.geolocation.getCurrentPosition(position => {  
    const map = new google.maps.Map(document.getElementById("map"), {  
      center: { lat: position.coords.latitude, lng: position.coords.longitude },  
      zoom: 8  
    });  
  });  
};

And in styles.css we add:

#map {  
  height: 100%;  
}

html,  
body {  
  height: 100%;  
  margin: 0;  
  padding: 0;  
}

All we had to do is to get the geolocation data like in the previous example, then from the position object we access the location in the callback. We pass in the element that we want to display our map in and latitude and longitude in the center object into the Google Map’s constructor. We also pass in the zoom property to set the default zoom level. It’s important that we have the code that we have in styles.css since the height by default will be 0. We have to set it explicitly in order for the map to be displayed. Also in index.html, we have to substitute YOUR_API_KEY with your own Google Map API key that you got when you signed up.

Accessing Audio and Video from Devices

With HTML5, we can get audio and video from devices that we attached to our computers or cameras built into portable devices without any plugins. The WebRTC API is the way to do this. WebRTC stands for Web Real-Time Communications. If your browser supports WebRTC, we should get a navigatior.getUserMedia() method, which gets the audio and video from the user’s device.

It is supported in most of the popular browsers, so it’s safe to use. If it’s not supported in a browser you want to use, we can add a polyfill to add support for it. The getUserMedia object gets takes a few parameters. The first one is an object that has the boolean video and audio properties. For example, if we want to get both video and audio, then pass in {video: true, audio: true}. The second parameter of the getUserMedia function are a callback function for when getting the data is successful and the last one is a callback function that’s called when there’s an error getting the data.

To use the getUserMedia function, we can write the following code to get audio from a microphone and play it back in our browser. In index.html, we add the following:

<html>  
  <head>  
    <title>Audio Playback</title>  
  </head>  
  <body>  
    <h1>Audio Playback</h1>  
    <audio id="audio"></audio>  
    <script src="script.js"></script>  
  </body>  
</html>

Then in scripts.js we add:

window.onload = () => {  
  navigator.getUserMedia =  
    navigator.getUserMedia ||  
    navigator.webkitGetUserMedia ||  
    navigator.mozGetUserMedia ||  
    navigator.msGetUserMedia;  
  if (navigator.getUserMedia) {  
    const audio = document.getElementById("audio");  
    navigator.getUserMedia(  
      {  
        video: false,  
        audio: true  
      },  
      stream => {  
        audio.srcObject = stream;  
        audio.play();  
      },  
      error => {}  
    );  
  }  
};

We check that getUserMedia is supported in our browser of choice before running the function. Then in the first argument, we pass in { video: false, audio: true } to get the audio only. Then in the success callback function, we get the stream object which contains the audio that’s inputted from the microphone, and assign it directly to the srcObject property of our audio element. Then we call play on the audio element to play the audio. When we load our page then we should get a prompt to allow the browser to receive audio from the microphone. If we choose to allow it, then audio should play from the microphone if we speak to or send any sound to it.

HTML5 APIs are great. It lets developers access hardware and files securely, allowing us to create much richer web applications. We barely scratched the surface on what we can do with those APIs. There are too many of them available to us to cover them all here, but they give us many tools to incredible experiences for our users.

Categories
JavaScript JavaScript Basics

How to Get Property of a JavaScript Object

All JavaScript dictionaries are objects, so getting the properties of a JavaScript object is the same as getting the keys of a JavaScript dictionary.

There are a few ways to get the keys of an object in JavaScript.

There are 2 ways to get the length of the list of keys of an object.

Object.keys

Object.keys gets the top level list of keys of an object and returns an array of them. For example:

const a = {foo: 1, bar: 2};
const length = Object.keys(a).length // 2

You can call find on the keys array to look for the key, like the following:

Object.keys(a).find(k => k == 'foo') // 'foo'

Object.getPropertyNames

Object.getPropertyNames also gets a list of all top level of keys of an object and return them as an array. For example:

const a = {foo: 1, bar: 2};
const length = Object.getOwnPropertyNames(a).length // 2

You can call find on the keys array to look for the key, like the following:

Object.getOwnPropertyNames(a).find(k => k == 'foo') // 'foo'

for…in Loop

There is a special loop for looping through the keys of an object. You can do the following:

const a = {foo: 1, bar: 2};
let keysCount = 0;
for (let key in a) {
    keysCount++;
}
console.log(keysCount) // 2

hasOwnProperty

You can check if an object has a property by calling hasOwnProperty of an object. For example:

const a = {foo: 1, bar: 2};
a.hasOwnProperty(key); // true
Categories
JavaScript JavaScript Basics

Controlling Your JavaScript Program’s Workflow With Loops and Branches

Conditional Statements

Conditional statements allow our code to run differently depending on the conditions given.

For example, if we want to display “You are too young to drink” when age is less than 21, we can use a conditional statement to do this.

There are a few ways to conditionally run code in JavaScript. One is the if...else statement. If you have lots of cases, then you can use the switch statement to simplify your code.

If…Else

The if...else statement is a way to run code depending on what condition you pass into the condition of the if statement.

Whatever condition you pass into it has to evaluate to a Boolean expression, or it can be automatically converted into a Boolean.

The if statement can be used by itself, but the else statement must be used with the if statement. The else statement is used when you want to execute something when the if statement is false.

You can also write else if (condition) if you want to run something with the given condition, and you have multiple cases with different conditions.

To write an if...else statement, we write:

if (condition){
 // run code
}

We do this in the simplest cases, such as when we only want to run something if we have some condition.

If we want to run something different when thecondition is false, then we write:

if (condition){
 // run code
}
else {
 // run other code
}

If we have more than two cases, then we can use else if like so:

if (condition1){
 // run code
}
else if (condition2){
 // run different code
}
else {
 // run code when condition1 and condition2 are both false
}

But else if and else don’t always have to be optional.

If you want to log a message for drinkers given their age, we can write:

const age = 19;
if (age < 21){
  console.log('You are too young to drink');
}
else {
  console.log('You are old enough to drink');
}

In the code above, we log, “You are too young to drink” if age is less than 21. Since age is 19, which is less than 21, we log “You are too young to drink.” If age is set to 22, then we log “You are old enough to drink.”

If your if...else statement only has two cases, we can shorten it by writing:

condition ? a : b

Here, a and b are any piece of code you want to execute, but it should be used if a and b are short since it’s meant to be written in one line.

So for the example above, we can also write:

const age = 19;
console.log(age < 21 ? 'You are too young to drink' : 'You are old enough to drink');

If we want to write if statements with multiple cases, we write:

const score = 80;
if (score >= 80){
  console.log('You get an A');
}
else if (score >= 65 && score < 80){
  console.log('You get a B');
}
else if (score >= 50 && score < 65){
  console.log('You get a C');
}
else {
  console.log('You failed');
}

In the example above, we have multiple cases. We determine what to log based on the range of thescore.

If the score is 80 or higher, we log, “You get an A.” If thescore is higher than or equal to 65 and less than 80, we log, “You get an A.” If the score is higher than or equal to 50 and less than 65 we log, “You get an A.” Otherwise, we log, “You failed.”

Switch statement

The if...else statement above can also be rewritten with the switch statement. A switch statement can be written like so:

switch (expression) {
  case value1:
    // Statements
    break;
  case value2:
    // Statements
    break;
  case value3:
    // Statements
    break;
  default:
    // Statements
    break;
}

In the switch block above, if we have anexpression equal to value1, then the statements in that block are executed.

This rule also applies to the other blocks. It’s critical to have the break statement at the end of every case block so it won’t run the other case blocks once the correct block is run. The default block runs if the value given doesn’t match any value in the case block.

An example of a switch statement would be the following to log “Hello” given a language:

const language = "Spanish";
switch (language){
 case "English":
   console.log("Hello");
   break;
 case "Spanish":
   console.log("Hola");
   break;
 case "Portugese":
   console.log("Ola");
   break;
 case "French":
   console.log("Bonjour");
   break;
 default:
   console.log(`I don't speak ${language}`);
}

In this statement, we log a hello message if we set language to English, Spanish, Portuguese, or French. Otherwise, we log `I don’t speak ${language}`, where language is anything that’s not English, Spanish, Portuguese, or French.


<img class="do t u hm ak" src="https://miro.medium.com/max/12000/0*8hfiungQLRRSm5fM" width="6000" height="4000" role="presentation"/>

Photo by Tine Ivanič on Unsplash

Loops

Loops are for running repeated operations. We need them so we can avoid writing the same code too many times. They let us repeatedly run code until the ending condition is met.

In JavaScript, we have the for loop, the while loop, and the do...while loop.

For loop

The for loop has three parts.

There’s the initialization code, which lets us define how to begin the loop by setting a variable to some initial value.

They also have a condition that is evaluated in every iteration, and if the condition is true, the loop continues to execute.

Then there’s the third expression which is run after each iteration of the loop.

The three expressions aren’t required, but they’re almost always included. They’re usually used for repeatedly running code a determined number of times.

For example, with the for loop, given that we have the name array, we can traverse the loop by running:

let names = new Array('Bob','Jane', 'John');
for (let i = 0; i < names.length; i++){
  console.log(names[i]);
}

A for loop is usually written with the starting condition as the first statement, then the ending condition in the second statement, and the index changing condition in the third statement. The statements are separated by the semicolons. Because arrays start with index zero in JavaScript, we terminate the loop when the array’s index reaches one less than the array’s length.

In the example above, the steps for running the loop are:

  1. The variable i is set to 0 at the beginning of the loop
  2. names[i] is retrieved from the array and logged in the console
  3. i is incremented by 1, so i becomes 2
  4. The three steps above are repeated until i becomes 3, which is the value of names.length, and the loop ends because 3 < 3 is false.

For…in loop

The for...in loops lets us traverse the properties of an object.

For example, if we have this object …

let obj = {a: 1, b: 2, c: 3}

… then we can use the for...in loop to loop through the properties of this object by running:

for (let prop in obj){
  console.log(obj[prop]);
}

prop will contain the property name or keys of the object. So prop will be a, b, or c as the loop is running. In the loop above, we log the values given those keys by passing prop into the bracket of the obj object.

For…of loop

The for...of loop lets us loop through an iterable object like an array in a convenient manner. It eliminates the need for setting those conditions to traverse through the whole array as we did with the plain for loop.

For instance, if we want to use the for...of loop to traverse the names array we have above, then we write:

let names = new Array('Bob','Jane', 'John');
for (const name of names){
  console.log(name);
}

The name variable automatically gets an entry of the names variable as we run the loop — so first we log Bob, then we log Jane, then we log John.

Note that we used const since we didn’t have to do anything with the array entries, but we can also use let if we want do something to each entry.

For example, if we define nums by writinglet nums = [1,2,3], then we can add 1 to each entry of the array by writing:

let nums = [1,2,3];
for (let num of nums){
  num += 1;
  console.log(name);
}

By switching out const for let, then we can add 1 to each entry of nums. So we log 2, 3, and 4.

Other iterable objects that work with the for...of loop include maps, sets, strings, and TypedArray.

If we loop through a string, then we get the individual characters of the string in each iteration. For example, if we have …

const str = 'foo';

for (const char of str) {
  console.log(char);
}

… then we get f, o, and o in each iteration.

For TypedArrays, if we have …

const typedArray = new Uint8Array([0x00, 0x06]);

for (const value of typedArray) {
  console.log(value);
}

… then we get 0 and 6 when we log the entries.

If we loop through a map, we get the entries of the map like we do below:

const map = new Map([['a', 4], ['b', 5], ['c', 6]]);

for (const entry of map) {
  console.log(entry);
}

We log ['a', 4], ['b', 5], and ['c', 6].

Also, we can use the destructuring operator to break up the keys and values of each entry, like so:

for (const [key, value] of map) {
  console.log(value);
}

In the code above, we just log the values of map, which are 4, 5, and 6.

Sets are also iterable objects, so we can loop through them, like so:

const set = new Set([1, 1, 2, 2, 3, 6]);

for (const val of set) {
  console.log(val);
}

We should get 1, 2, 3, and 6 logged since sets eliminate duplicate values.

The arguments object is a special object that’s available in each function. It has the arguments passed into the object, regardless of what you defined in your parameters. We can loop through it with the for...of loop

For example, if we have …

(function() {
  for (const arg of arguments) {
    console.log(arg);
  }
})(4, 5, 6);

… then we log 4, 5, and 6 since that’s what we passed into the anonymous function as arguments.

While loop

The while loop will loop whenever a condition stays true.

For example, the loop below will run if the index number i is less than 3:

const array = [1,2,3];let i = 0;
while(i < array.length){
  console.log(i);
}

If the condition in the parentheses is never true, then the loop content will never run, and if it’s always true, then it runs forever, creating an infinite loop.

Do…while loop

The do...while loop will always execute the first iteration.

const array = [1,2,3];let i = 0;
do{
  console.log(i);
}
while(i < array.length)

In the example above, it will at least log 0, but it will also log 1 and 2 in this case since those two numbers are less than 3.

With the above loops, you can call break to stop the loop or return before the loop is completely finished.

//do while loop
const array = [1,2,3];let i = 0;do{
  console.log(i);  if (i == 1}{    break;  }}
while(i < array.length)//while loop
i = 0;while(i < array.length){  if (i == 1{    break;  }
  console.log(i);
}//for loop
for (let j = 0; j < array.length; j++){  if (j == 1){
    break;
  }
  console.log(j);
}

In the above examples, you will not see 2 logged.

An example of returning from within the loop:

const loop = ()=>{
  const array = [1,2,3];
  for (let j = 0; j < array.length; j++){
    if (j == 1){
      return j;
    }
    console.log(j);
  }
}
loop() //returns 1

You can also skip iterations with the continue statement:

const array = [1,2,3];
for (let j = 0; j < array.length; j++){  if (j == 1){
    continue;
  }
  console.log(j) // 1 will be skipped;
}
Categories
JavaScript JavaScript Basics

Use the For-Of Loop to Iterate Through JavaScript Iterable Objects

Starting with ES2015, we have a new kind of loop to loop over iterable objects. The new for...of loop is a new kind of loop that lets us loop over any iterable objects without using a regular for loop, while loop, or using the forEach function in the case of arrays. It can be used directly to iterate through any iterable objects, which include built-in objects like Strings, Arrays, array-like objects like arguments and NodeList, TypedArray, Map, Set and any user-defined iterables. User-defined iterables include entities like generators and iterators.

If we want to use the for...of loop to iterate over an iterable object, we can write it with the following syntax:

for (variable of iterable){  
  // run code  
}

The variable in the code above is the variable representing each entry of the iterable object that is being iterated over. It can be declared with const , let or var . The iterable is the object where the properties are being iterated over.

For example, we can use it to iterate over an array-like in the following code:

const arr = [1,2,3];  
  
for (const num of arr) {  
  console.log(num);  
}

The code above, the console.log statements will log 1, 2, and 3. We can replace const with let if we want to assign the variable we used for iteration in the for...of loop. For example, we can write:

const arr = [1,2,3];  
  
for (let num of arr) {  
  num *= 2 ;   
  console.log(num);  
}

The code above, the console.log statements will log 2, 4, and 6 since we used the let keyword to declare the num so we can modify num in place by multiplying each entry by 2. We cannot reassign with const so we have to use let or var to declare the variable we want to modify in each iteration.

We can also iterate over strings. If we do that we all get each character of the string in each iteration. For example, if we have the code below:

const str = 'string';  
  
for (const char of str) {  
  console.log(char);  
}

Then we get the individual characters of 'string' logged in each line.

Likewise, we can iterate over TypedArrays, which contains binary data represented by a series of numbers in hexadecimal format. For example, we can write the following code:

const arr = new Uint8Array([0x00, 0x2f]);  
  
for (const num of arr) {  
  console.log(num);  
}

In the example above, console.log will log 0 and 47. Note that the logged value is in decimal format but the entered value is in hexadecimal format.

If we iterate over Maps, then we get each entry of the Map. For example, we can write the following code to iterate over Maps:

const map = new Map([['a', 2], ['b', 4], ['c', 6]]);  
  
for (const entry of map) {  
  console.log(entry);  
}

If we log the entries, we get ['a', 2], ['b', 4], and ['c', 6] . Maps consist of key-value pairs as their entries. When we iterate over a Map, we get the key as the first element and the value as the second element is each entry. To get the key and value of each entry into its own variable we can use the destructuring operator, like in the following code:

const map = new Map([['a', 2], ['b', 4], ['c', 6]]);  
  
for (const [key, value] of map) {  
  console.log(key, value);  
}

Then when we log the entries, we get 'a' 2, 'b' 4, and 'c' 6.

We can also use the for...of loop for Sets. For example, we can loop over a Set by doing the following:

const set = new Set([1, 1, 2, 3, 3, 4, 5, 5, 6]);  
  
for (const value of set) {  
  console.log(value);  
}

We set that we get 1, 2, 3, 4, 5, and 6 logged since the Set constructor automatically eliminates duplicate entries by keeping the first occurrence value in the Set and discarding the later occurrence of the same value.

The for...of loop also works for iterating over the arguments object, which is a global object that has the arguments that were passed into the function when the function is called. For example, if we write the following code:

(function() {  
  for (const argument of arguments) {  
    console.log(argument);  
  }  
})(1, 2, 3, 4, 5, 6);

We see that we see 1, 2, 3, 4, 5, and 6 logged since this is what we passed in when we called the function. Note that this only works for regular functions since the context of this has to be changed to the function being called instead of window. Arrow functions don’t change the content of this, so we won’t get the correct arguments when we run the same loop inside an arrow function.

Also, we can iterate over a list of DOM Node objects, called a NodeList . For example, is a browser implemented the NodeList.prototype[Symbol.iterator] , then we can use the for...of loop like in the following code:

const divs = document.querySelectorAll('div');  
  
for (const div of divs) {  
  console.log(div);  
}

In the code above we logged all the div elements that are in the document.

With for...of loops, we can end the loop by using the break , throw or return statements. The iterator will close in this case, but the execution will continue outside the loop. For example, if we write:

function* foo(){   
  yield 'a';   
  yield 'b';   
  yield 'c';   
};   
  
for (const o of foo()) {   
  console.log(o);   
  break;  
}

console.log('finished');

In the code above, we only log ‘a’ because we have a break statement at the end of the for...of loop, so after the first iteration, the iterator will close and the loop ends.

We can loop over generators, which are special functions that return a generator function. The generator function returns the next value of an iterable object. It’s used for letting us iterate through a collection of objects by using the generator function in a for...of loop.

We can also loop over a generator that generates infinite values. We can have an infinite loop inside the generator to keep returning new values. Because the yield statement doesn’t run until the next value is requested, we can keep an infinite loop running without crashing the browser. For example, we can write:

function* genNum() {  
  let index = 0;  
  while (true) {  
    yield index += 2;  
  }  
}

const gen = genNum();  
for (const num of gen) {  
  console.log(num);  
  if (num >= 1000) {  
    break;  
  }  
}

If we run the code above, we see that we get numbers from 2 to 1000 logged. Then num is bigger than 1000 so that the break statement is run. We cannot reuse the generator after it’s closed, so if we write something like the following:

function* genNum() {  
  let index = 0;  
  while (true) {  
    yield index += 2;  
  }  
}

const gen = genNum();  
for (const num of gen) {  
  console.log(num);  
  if (num >= 1000) {  
    break;  
  }  
}

for (const num of gen) {  
  console.log(num);  
  if (num >= 2000) {  
    break;  
  }  
}

The second loop won’t run because the iterator that was generated by the generator is already closed by the first loop with the break statement.

We can iterate over other iterable objects that have the method denoted with the Symbol.iterator Symbol defined. For example, if we have the following iterable object defined:

const numsIterable = {  
  [Symbol.iterator]() {  
    return {  
      index: 0,  
      next() {  
        if (this.index < 10) {  
          return {  
            value: this.index++,  
            done: false  
          };  
        }  
        return {  
          value: undefined,  
          done: true  
        };  
      }  
    };  
  }  
};

Then we can run the loop below to show log the generated results:

for (const value of numsIterable) {  
  console.log(value);  
}

When we run it, should see 0 to 9 logged when console.log is run in the loop above.

It’s important that we don’t confuse the for...of loop with the for...in loop. The for...in loop if for iterating over the top-level keys of objects including anything up the prototype chain, while the for...of loop can loop over any iterable object like arrays, Sets, Maps, the arguments object, the NodeList object, and any user-defined iterable objects.

For example, if we have something like:

Object.prototype.objProp = function() {};  
Array.prototype.arrProp = function() {};
const arr = [1, 2, 3];  
arr.foo = 'abc';for (const x in arr) {  
  console.log(x);  
}

Then we get 0, 1, 2, ‘foo’, ‘arrProp’ and ‘objProp’ logged, which are keys of objects and methods that are defined for the arr object. It included all properties and methods up to the prototype chain. It inherited all properties and methods from Object and Array that were added to Object and Array’s prototype so we get all the things in the chain inheritance in the for...in loop. Only enumerable properties are logged in the arr object in arbitrary order. It logs index and properties we defined in Object and Array like objProp and arrProp.

To only loop through properties that aren’t inheritance from an object’s prototype, we can use the hasOwnPropetty to check if the property is defined on the own object:

Object.prototype.objProp = function() {};  
Array.prototype.arrProp = function() {};
const arr = [1, 2, 3];  
arr.foo = 'abc';for (const x in arr) {  
  if (arr.hasOwnProperty(x)){  
    console.log(x);  
  }  
}

objProp and arrProp are omitted because they’re inherited from Object and Array objects respectively.

The for...of loop is a new kind of loop that lets us loop over any iterable objects without using a regular for loop, while loop, or using the forEach function in the case of arrays. It can be used directly to iterate through any iterable objects, which include built-in objects like Strings, Arrays, array-like objects like arguments and NodeList, TypedArray, Map, Set and any user-defined iterables. User-defined iterables include entities like generators and iterators. This is a handy loop because it lets us over any iterable object rather than just arrays. Now we have a loop statement that works with iterable object.

Categories
JavaScript JavaScript Basics

How to do Exponentiation in JavaScript

There are multiple to compute exponents with JavaScript.

The newest way is the exponentiation operator **, available with ES2016 or higher.

For example, we can do this:

const a = 2 ** 3; // 8

It is right associative, so a ** b ** c is equal to a ** (b ** c). This works with all exponents.

For example:

const a = 2 ** (3 ** 4);
const b = 2 ** 3 ** 4;
a == b // true, both are 2.4178516392292583e+24

Detail browser compatibility is available at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Browser_compatibility

We can also use the Math.pow function, like this:

const a = Math.pow(2,3) // 8

It takes 2 arguments, the first is the base and the second is the exponent. Math.pow works with all exponents.

Math.pow is compatible with all recent browsers.