Categories
JavaScript JavaScript Basics

Handling Dates in JavaScript

Handling date and time are also important in many JavaScript programs. This is why JavaScript has a built-in Date object to handle manipulating dates. Dates objects contain a number that represents the milliseconds since January 1970 in UTC (the Linux epoch time).

We can do a lot of things with the Date object to manipulate dates. However, it has many quirks and missing functionality. Therefore, third-party libraries are better with handling dates than using the built-in Date object in many cases. Moment.js is one of the more popular ones, so it’s naturally it is the first choice when we need to manipulate dates in JavaScript.

Built in Date Object

To work with dates in JavaScript, we have to create a new Date object. The constructor for the date object takes zero or more arguments. When there are no arguments passed in, then Date object created will have the current date and time in your local time zone, as of the time of instantiation.

The parameters it can accept include a date string, another date object, or the (years, month index, day, hour, minutes, seconds, and milliseconds) together. We can pass in a date string as follows to the date constructor:

new Date('2019-01-01');

If we log the result, we get ‘Mon Dec 31 2018 16:00:00 GMT-0800 (Pacific Standard Time)’ since the date is stored in UTC and the browser is running on a computer in the Pacific Time Zone, which is 8 hours behind UTC at January 1, 2019 is when Pacific Standard Time.

As we can see, passing a date string to the Date constructor is confusing. Different browsers will parse date strings differently. Likewise, the Date.parse method also shouldn’t be used to parse date strings. We can see that date-only strings like the one we passed in are treated as UTC and not local time.

If we want to pass in a Date object to the constructor we can write:

new Date(new Date());

We get something like ‘Sun Oct 20 2019 10:57:58 GMT-0700 (Pacific Daylight Time)’ when we log the result. This is shown in your local time.

We can pass in the year, month index, day, hour, minutes, seconds, and milliseconds into the constructor. Only year and month are required. So we can write something like:

new Date(2019,0,1,0,0,0,0)

This will return ‘Tue Jan 01 2019 00:00:00 GMT-0800 (Pacific Standard Time)’ if we log it. Note that we have 0 in the second argument of the constructor. The second argument is the month index, which is 0 for January, 1 for February, and so on. So December would be 11. The rest of the arguments are what we expect. The first is the year, the third is the day, the fourth is hours, the fifth is minutes, 6th is seconds, and the last one is milliseconds.

We can convert a Date object to the UNIX timestamp, which is the number of milliseconds since January 1, 1970 UTC with the unary + operator, so if we write:

+new Date(2019,0,1,0,0,0,0)

We get 1546329600000 when we log the output because it coerces the date to a number.

Another way to get the timestamp is by using the .getTime() method.

To alter the individual components of a Date object like setting the hours or day or getting components of a Date like the day of the week or day of the month, there are methods to do that in a Date object.

Methods in the Date Object

There are methods in the Date object to get and set parts of dates, and convert time to UTC, or set time zone offset. Some important Date object methods include the following:

Date.now()

Returns the current time in the form of a UNIX timestamp with leap seconds ignored. This method is static.

Date.UTC()

Returns the current time in the form of a UNIX timestamp with leap seconds ignored. This method is static. It accepts the same arguments as the longest list of arguments for the Date constructor which is year, month index, day, hour, minutes, seconds, and milliseconds, but only year and month are required. We can use it as in the following code:

Date.UTC(2019,0,1,1,0,0,0)

Which we return something like 1546304400000.

Getter Functions

Date.getDate()

Returns the day of the month according to local time. For example, if we have:

const date = new Date(2019,0,1,0,0,0,0);  
console.log(date.getDate());

We would get 1 since we specified it as the day of the month in the constructor’s arguments.

Date.getDay()

Returns the day of the week (0–6) for the specified date according to local time, where 0 represents Sunday and 6 represents Saturday and 1 to 5 represents the days in between. For example, we can write:

const date = new Date(2019,0,1,0,0,0,0);  
console.log(date.getDay());

Then we get 2, which is Tuesday.

Date.getFullYear()

Returns the 4 digit year of the specified date according to local time. For example, we can write:

const date = new Date(2019,0,1,0,0,0,0);  
console.log(date.getFullYear());

Then we get 2019, which is the 4 digit year of date.

Date.getHours()

Return the hour (0–23) of the specified date according to local time. For example, we can write:

const date = new Date(2019,0,1,0,0,0,0);  
console.log(date.getHours());

Then we get 0 which is what we specified in the hours argument in the constructor.

Date. getMilliseconds()

Returns the milliseconds of the specified date from 0 to 999 according to local time. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getMilliseconds());

This gets the milliseconds specified in the date object, which should return 0 as we specified in the constructor.

Date.getMinutes()

Returns the minute (0–59) of the specified date in local time. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getMinutes());

Then we get 0 minutes as we specified in the constructor.

Date.getMonth()

Returns the month (From 0 for January to 11 for December) of the specified date according to local time. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getMonth());

Then we get month 0 for January as we specified in the constructor.

Date.getSeconds()

Returns the seconds (0–59) in the specified date in local time. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getSeconds());

Then we get 0 seconds as we specified in the constructor.

Date.getTime()

Returns the UNIX timestamp for the specified date, which is the number of milliseconds since January 1, 1970 00:00:00 UTC. For prior times, it will be negative. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getTime());

Then we get 1546329600000 returned from the getTime() function. A shorthand for this is to use the unary + operator, like in the following code:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(+date);

If we run the code above, we get the same result logged.

Date.getTimezoneOffset()

Return time zone offset in minutes for the current location set on your host device. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getTimezoneOffset());

Then we get 480 if your host device is set to the Pacific Time Zone, since on January 1, 2019, the Pacific Time Zone is 8 hours behind UTC, so we get that the time zone offset is 480 minutes, which is 8 hours.

Date.getUTCDate()

Returns the day of the month, from 1 to 31, in the specified date according to UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getUTCDate());

We get 1 since we specified January 1, 2019 as the date.

Date.getUTCDay()

Return the day of the week from 0 to 6 according to the specified date in UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getUTCDay());

Then we get 2 because January 1, 2019 is Tuesday.

Date.getUTCFullYear()

Return the 4 digit year in the specified date according to UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getUTCFullYear());

We get 2019 since this is what we specified in the date constructor.

Date.getUTCHours()

Return the hours from 0 to 23 in the specified date according to UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getUTCHours());

If the locale setting is set to the Pacific Time Zone, we get 8 since we specified that the hour is 0 in local time which is the same as 8 in UTC on January 1, 2019.

Date.getUTCMilliseconds()

Returns the milliseconds of the specified date from 0 to 999 according to UTC. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getUTCMilliseconds());

This gets the milliseconds specified in the date object, which should return 0 as we specified in the constructor.

Date.getUTCMonth()

Return the month from 0 for January to 11 for December in the specified time according to UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getUTCMonth());

This gets the month specified in the date object, which should return 0 like we specified in the constructor.

Date.getUTCSeconds()

Returns the seconds (0–59) in the specified date in UTC. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getUTCSeconds());

Then we get 0 seconds as we specified in the constructor.

Date.getYear()

Returns the year, which is usually 2 to 3 digits in the specified date according to the local time zone.

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getUTCSeconds());

Then we get 119 for 2019.

If we instead have:

const date = new Date(1900, 0, 1, 0, 0, 0, 0);  
console.log(date.getYear());

We get 0 for 1900. And if we have:

const date = new Date(2000, 0, 1, 0, 0, 0, 0);  
console.log(date.getYear());

Then we get 100 for 2000. So 1900 is year 0 according to the getYear() method. It’s much better to use the getFullYear() method instead of getting the correct year from a Date object.

Setter Functions

There are also corresponding setter functions for each of the getter functions we mentioned above. We have the following setter functions for the Date object:

Date.setDate()

Sets the day of the month according to local time. For example, if we have:

const date = new Date(2019,0,1,0,0,0,0);  
date.setDate(2)  
console.log(date);

We would get ‘Wed Jan 02 2019 00:00:00 GMT-0800 (Pacific Standard Time)’ when the host device is set to the Pacific Time Zone since we specified 2 in the setDate function.

Date.setFullYear()

Sets the 4 digit year of the specified date according to local time. For example, we can write:

const date = new Date(2019,0,1,0,0,0,0);  
date.setFullYear(2020)  
console.log(date.getFullYear());

Then we get 2020, which is the 4 digit year of date.

Date.setHours()

Sets the hour (0–23) of the specified date according to local time. For example, we can write:

const date = new Date(2019,0,1,0,0,0,0);  
date.setHours(3)  
console.log(date.getHours());

Then we get 3 when we call getHours which is what we specified in the hours argument in the setHours function.

Date. setMilliseconds()

Sets the milliseconds of the specified date from 0 to 999 according to local time. For example, we can write:

const date = new Date(2019,0,1,0,0,0,0);  
date.setMilliseconds(3)  
console.log(date.getMilliseconds());

This sets the milliseconds specified in the date object, which should return 3 as we specified in the setMilliseconds function when we call the getMilliseconds function.

Date.setMinutes()

Sets the minute (0–59) of the specified date in local time. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setMinutes(20)  
console.log(date.getMinutes());

Then we get 20 minutes returned from getMinutes() like we specified in the setMinutes function.

Date.setMonth()

Sets the month (From 0 for January to 11 for December) of the specified date according to local time. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setMonth(3)  
console.log(date.getMonth());

Then we get month 3 returned from getMonth() after we set it by setMonth()

Date.setSeconds()

Sets the seconds (0–59) in the specified date in local time. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setSeconds(10);  
console.log(date.getSeconds());

Then we get 10 seconds from getSeconds() like we specified in the setSeconds function.

Date.setTime()

Sets the UNIX timestamp for the specified date, which is the number of milliseconds since January 1, 1970 00:00:00 UTC. For prior times, it will be negative. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setTime(100)  
console.log(date.getTime());

Then we get 100 returned from the getTime() function since we set it to 100 with setTime .

Date.setUTCDate()

Sets the day of the month, from 1 to 31, in the specified date according to UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setUTCDate(2)  
console.log(date.getUTCDate(2));

We get 2 since we specified 2 in setUTCDate

Date.setUTCFullYear()

Sets the 4 digit year in the specified date according to UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setUTCFullYear(2020)  
console.log(date.getUTCFullYear());

We get 2020 with getUTCFullYear() since this is what we specified in the date setUTCFullYear() function.

Date.setUTCHours()

Sets the hours from 0 to 23 in the specified date according to UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setUTCHours(2)  
console.log(date.getUTCHours());

We get 2 with getUTCHours() since we specified it when we call setUTCHours().

Date.setUTCMilliseconds()

Sets the milliseconds of the specified date from 0 to 999 according to UTC. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setUTCMilliseconds(10)  
console.log(date.getUTCMilliseconds());

This gets the milliseconds with getUTCMilliseconds(), which should return 10 as we specified in the setUTCMilliseconds().

Date.setUTCMonth()

Return the month from 0 for January to 11 for December in the specified time according to UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setUTCMonth(3);  
console.log(date.getUTCMonth());

This gets the month specified in the date object, which should return 3 from getUTCMonth() like we specified in the setUTCMonth() call.

Date.setUTCSeconds()

Sets the seconds (0–59) in the specified date in UTC. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setUTCSeconds(10);  
console.log(date.getUTCSeconds());

Then we get 10 seconds when we called getUTCSeconds() since we specified in 10 when we called setUTCSeconds().

The setYear() method set the ye. It’s much better to use the setFullYear() method instead for getting the correct year from a Date object.

The Date object has a few limitations. For example, it doesn’t support time zones. This creates problems when we need time zones data in our dates. JavaScript dates only supports the local time zone, UTC, or time zone offsets relative to UTC. Only some of the conversions between these time zones are allowed when manipulating date objects. For example, when we convert Date objects to a date string, we can only choose between local time and UTC. The JavaScript Date object stores dates in UTC internally.

Moment.js

Manipulating time and date in JavaScript is painful because of the limitations that we discussed above. Even with the functions available with Date objects, there are plenty of chances for bugs and errors. Also, there are no functions for formatting times and dates which is a big problem. To solve this, we use moment.js. This is the best library available for dealing with time.

The native JavaScript Date objects have issues with time zones with YYYY-MM-DD dates being parsed into UTC time as opposed to local time. This creates bugs for developers who aren’t aware of this problem. See https://stackoverflow.com/questions/29174810/javascript-date-timezone-issue

Also there are differences in support for parts of Dates in different browsers. (See https://stackoverflow.com/questions/11253351/javascript-date-object-issue-in-safari-and-ie)

It is also hard to add and subtract timestamps with the built-in Date functions. There is no way to do this without writing a lot of code and doing a lot of checks. Also, there is no way to compare 2 times.

Formatting dates is also not available without writing your own code for using third party libraries.

Moment.js solves all of these issues by providing built-in functions to do all these common operations. It provides functions for parsing and formatting dates.

The moment constructor is where you can pass in a date string, and a moment object will be created. For example, you can pass in:

moment('2019-08-04')

You will get back a moment which you can compare with other moment objects, and add or subtract by different time spans.

If you do not pass in anything to the moment constructor, you get the current date and time.

It also takes a second argument. If you want to make sure a date is parsed as a YYYY-MM-DD date, then write moment(‘2019–08–04’, 'YYYY-MM-DD'). If you don’t know the format of your date or time, then you can pass in an array of possible formats and Moment will pick the right one:

moment('2019–08–04', ['YYYY-MM-DD', 'DD-MM-YYYY']);

After you create a Moment object, then you can do many things like formatting dates:

const a = moment('2019–08–04', 'YYYY-MM-DD').format('MMMM Do YYYY, h:mm:ss a');  
console.log(a);// August 4th 2019, 12:00:00 am

const b = moment('2019–08–04', 'YYYY-MM-DD').format('dddd');  
console.log(b);// Sunday

const c = moment('2019–08–04', 'YYYY-MM-DD').format("MMM Do YY");  
console.log(c);// Aug 4th 19

const d = moment('2019–08–04', 'YYYY-MM-DD').format('YYYY [escaped] YYYY');      
console.log(d);// 2019 escaped 2019

const e = moment('2019–08–04', 'YYYY-MM-DD').format();  
console.log(e);// 2019-08-04T00:00:00-07:00

From the above examples, we see that we can format dates in pretty much any way we want.

We can also tell what time span a date is relative to another date by writing:

const augDate = moment('2019–08–04', 'YYYY-MM-DD');  
const sepDate = moment('2019–09–04', 'YYYY-MM-DD');  
console.log(augDate.from(sepDate)); // a month ago

We can also add or subtract Moment dates:

const augDate = moment('2019–08–04', 'YYYY-MM-DD');  
const sepDate = moment('2019–09–04', 'YYYY-MM-DD');  
console.log(augDate.add(10, 'days').calendar()); // 08/14/2019  
console.log(augDate.subtract(10, 'days').calendar()); // 07/25/2019

It is easy to compare 2 dates:

moment('2010-01-01').isSame('2010-01-01', 'month'); // true  
moment('2010-01-01').isSame('2010-05-01', 'day');   // false, different month  
moment('2008-01-01').isSame('2011-01-01', 'month'); // false, different year

You can also check if a date has Daylight Saving Time in effect or not:

const augDate = moment('2019–08–04', 'YYYY-MM-DD');  
const decDate = moment('2019–12–04', 'YYYY-MM-DD');  
console.log(augDate.isDST()) // true  
console.log(decDate.isDST()) // false

And you can convert back to JavaScript date any time by calling the toDate() function on a Moment object.

As we can see, JavaScript’s Date object has limited capabilities when it comes to manipulating dates. It also doesn’t parse dates very well and has no ability for formatting dates easily. This is why we need to use libraries like Moment.js to fill in the gaps so we can create bug-free code that manipulates dates much more easily.

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 React TypeScript

How to Use the Optional Chaining Operator in Your React App Right Now

Optional chaining is a proposed feature that may be incorporated into the JavaScript specification.

The operator allows you to traverse through a nested object to get the value of variables without worrying if any of those will be undefined.

For example, without optional chaining, if you have the object below:

const person = {  
  name: 'Alice',  
  cat: {  
    name: 'Bob'  
  }  
};

If you want to get the cat’s name, you have to use the code below:

const catName = person.cat.name;

If cat is undefined or null in person, the JavaScript interpreter will throw an error. With the optional chaining operator, you can write:

const catName = person?.cat?.name;

If cat is undefined, the catName will be null.

It also works with keys of an object. Instead of const catName = person?.cat?.name;, we can write:

const catName = person?.['cat']?.['name'];

This syntax also works with functions. For example, you can write:

func?.('foo')

To call the function func with a string, where func may be undefined or null. If the function does not exist, it will not be run.

To further illustrate the example and to show you how to use it in a real application, we will build a React app that uses the NASA API, to get the latest asteroid data.

We will use the Create React App CLI program to build the app.

As optional chaining is just a proposed feature, it is not currently supported with the CLI, so we have to do some work ourselves by installing some packages and making some changes to the Babel configuration of the app to enable optional chaining.

To start, we run npx create-react-app nasa-app to create the project folder with the initial files.

Next, we install npm i -D @babel/plugin-proposal-optional-chaining customize-cra react-app-rewired to begin customizing Create React App to support the optional chaining syntax.

Next, we have to add new configuration files and edit existing ones to let our app run and build with the syntax.

First, we add a file called config-overrides.js and add the following:

const { useBabelRc, override, useEslintRc } = require("customize-cra");
module.exports = override(useBabelRc());

To let us use the .babelrc configuration file.

Then, we create the .babelrc file in the root folder of our project and add:

{  
    "plugins": [  
        [  
            "@babel/plugin-proposal-optional-chaining"  
        ],  
    ]  
}

This will add support for optional chaining syntax in our project.

Next, we have to switch to make our app run and build with react-app-rewired instead of the usual react-script program.

To do this, in the scripts section of package.json, we put:

"scripts": {  
    "start": "react-app-rewired start",  
    "build": "react-app-rewired build",  
    "test": "react-app-rewired test --env=jsdom",  
    "eject": "react-scripts eject"  
}

In here, we replaced the original scripts that use react-script to run and build our app, with react-app-rewired.

Now we can use the optional chaining syntax to build our app.

First, we have to install some packages.

Run npm i axios bootstrap react-bootstrap formik yup react-router-dom to install the axios HTTP client, React Bootstrap for styling, Formik and Yup for building forms and adding form validation, and React Router for routing URLs to the pages we build.

Now we can write some code. In App.js, we replace the existing code with:

import React from "react";  
import { Router, Route } from "react-router-dom";  
import HomePage from "./HomePage";  
import AsteroidsSearchPage from "./AsteroidsSearchPage";  
import { createBrowserHistory as createHistory } from "history";  
import "./App.css";  
import TopBar from "./TopBar";  
const history = createHistory();

function App() {  
  return (  
    <div className="App">  
      <Router history={history}>  
        <TopBar />  
        <Route path="/" exact component={HomePage} />  
        <Route path="/search" exact component={AsteroidsSearchPage} />  
      </Router>  
    </div>  
  );  
}export default App;

So that we get client-side routing to our pages. In App.css, we replace the existing code with:

.center {  
  text-align: center;  
}

Next, we start building new pages. Create a file called AsteroidSearchPage.js in the src folder and add:

import React, { useState, useEffect } from "react";  
import { Formik } from "formik";  
import Form from "react-bootstrap/Form";  
import Col from "react-bootstrap/Col";  
import Button from "react-bootstrap/Button";  
import * as yup from "yup";  
import Card from "react-bootstrap/Card";  
import "./AsteroidsSearchPage.css";  
import { searchFeed } from "./requests";

const schema = yup.object({  
  startDate: yup  
    .string()  
    .required("Start date is required")  
    .matches(  
      /([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))/,  
      "Invalid start date"  
    ),  
  endDate: yup  
    .string()  
    .required("End date is required")  
    .matches(  
      /([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|\[12]\d|3\[01]))/,  
      "Invalid end date"  
    ),  
});

function AsteroidsSearchPage() {  
  const [feed, setFeed] = useState({});  
  const [error, setError] = useState("");
  const handleSubmit = async evt => {  
    const isValid = await schema.validate(evt);  
    if (!isValid) {  
      return;  
    }  
    try {  
      const response = await searchFeed(evt);  
      setFeed(response.data.near_earth_objects);  
    } catch (ex) {  
      alert(ex?.response?.data?.error_message);  
    }  
  };

  return (  
    <div className="AsteroidsSearchPage">  
      <h1 className="center">Search Asteroids</h1>  
      <Formik validationSchema={schema} onSubmit={handleSubmit}>  
        {({  
          handleSubmit,  
          handleChange,  
          handleBlur,  
          values,  
          touched,  
          isInvalid,  
          errors,  
        }) => (  
          <Form noValidate onSubmit={handleSubmit}>  
            <Form.Row>  
              <Form.Group as={Col} md="12" controlId="startDate">  
                <Form.Label>Start Date</Form.Label>  
                <Form.Control  
                  type="text"  
                  name="startDate"  
                  placeholder="YYYY-MM-DD"  
                  value={values.startDate || ""}  
                  onChange={handleChange}  
                  isInvalid={touched.startDate && errors.startDate}  
                />  
                <Form.Control.Feedback type="invalid">  
                  {errors.startDate}  
                </Form.Control.Feedback>  
              </Form.Group>  
              <Form.Group as={Col} md="12" controlId="endDate">  
                <Form.Label>End Date</Form.Label>  
                <Form.Control  
                  type="text"  
                  name="endDate"  
                  placeholder="YYYY-MM-DD"  
                  value={values.endDate || ""}  
                  onChange={handleChange}  
                  isInvalid={touched.startDate && errors.endDate}  
                /><Form.Control.Feedback type="invalid">  
                  {errors.endDate}  
                </Form.Control.Feedback>  
              </Form.Group>  
            </Form.Row>  
            <Button type="submit" style={{ marginRight: "10px" }}>  
              Search  
            </Button>  
          </Form>  
        )}  
      </Formik>  
      {Object.keys(feed)?.map(key => {  
        return (  
          <Card style={{ width: "90vw", margin: "0 auto" }}>  
            <Card.Body>  
              <Card.Title>{key}</Card.Title>  
              {feed?.[key]?.length > 0  
                ? feed?.[key]?.map(f => {  
                    return (  
                      <div style={{ paddingBottom: "10px" }}>  
                        {f?.close_approach_data?.length > 0 ? (  
                          <div>  
                            <b>  
                              Close Approach Date:  
                              {f?.close_approach_data?.map(d => {  
                                return <p>{d?.close_approach_date_full}</p>;  
                              })}  
                            </b>  
                          </div>  
                        ) : null}  
                        <div>  
                          Minimum Estimated Diameter:{" "}  
                          {  
                            f?.estimated_diameter?.kilometers  
                              ?.estimated_diameter_min  
                          }{" "}  
                          km  
                        </div>  
                        <div>  
                          Maximum Estimated Diameter:{" "}  
                          {  
                            f?.estimated_diameter?.kilometers  
                              ?.estimated_diameter_max  
                          }{" "}  
                          km  
                          <br />  
                        </div>  
                      </div>  
                    );  
                  })  
                : null}  
            </Card.Body>  
          </Card>  
        );  
      })}  
    </div>  
  );  
}

export default AsteroidsSearchPage;

This is where we add a form to search for asteroid data from the NASA API by date range. Both the start and end date fields should be in YYYY-MM-DD format and we changed our form validation to match that in the schema object.

Once validation is done, by calling the schema.validate function, we search. The response has many nested objects, so we use the optional chaining syntax everywhere in the result cards.

We loop through close_approach_data array, and we don’t assume it’s always defined or has a greater than zero length, the same goes for the call to the map function. We do not assume that the map function is always defined.

We also use the optional chaining syntax for f?.estimated_diameter?.kilometers ?.estimated_diameter_min and f?.estimated_diameter?.kilometers ?.estimated_diameter_max.

The more levels of nesting there are, the less likely it is that you can traverse the object tree successfully without the optional chaining syntax, as there is more chance of nested objects being undefined.

Also, note that the optional chaining syntax works for returned results like Object.keys(feed)

In AsteroidSearchPage.css, which we should create in the src folder, we put:

.AsteroidsSearchPage{  
  margin: 0 auto;  
  width: 90vw;  
}

To add some margins to the page.

Next, we build the home page. Create a file called HomePage.js in the src folder and add:

import React, { useState, useEffect } from "react";  
import { browse } from "./requests";  
import Card from "react-bootstrap/Card";  
import "./HomePage.css";

function HomePage() {  
  const [initialized, setIntialized] = useState(false);  
  const [feed, setFeed] = useState([]);
  const browserFeed = async () => {  
    const response = await browse();  
    setFeed(response.data.near_earth_objects);  
    setIntialized(true);  
  };

  useEffect(() => {  
    if (!initialized) {  
      browserFeed();  
    }  
  });  
  return (  
    <div className="HomePage">  
      <h1 className='center'>Asteroids Close to Earth</h1>  
      <br />  
      {feed?.map(f => {  
        return (  
          <Card style={{ width: "90vw", margin: "0 auto" }}>  
            <Card.Body>  
              <Card.Title>{f?.name}</Card.Title>  
              <div>  
                {f?.close_approach_data?.length > 0 ? (  
                  <div>  
                    Close Approach Date:  
                    {f?.close_approach_data?.map(d => {  
                      return <p>{d?.close_approach_date_full}</p>;  
                    })}  
                  </div>  
                ) : null}  
                <p>  
                  Minimum Estimated Diameter:{" "}  
                  {f?.estimated_diameter?.kilometers?.estimated_diameter_min} km  
                </p>  
                <p>  
                  Maximum Estimated Diameter:{" "}  
                  {f?.estimated_diameter?.kilometers?.estimated_diameter_max} km  
                </p>  
              </div>  
            </Card.Body>  
          </Card>  
        );  
      })}  
    </div>  
  );  
}

export default HomePage;

This page is very similar to the AsteroidSearchPage component with the use of the optional chaining syntax.

Next, create HomePage.css in the src folder and add:

.HomePage{  
  text-align: left;  
}

To align our text to the left.

Next, we create requests.js in the src folder and add:

const APIURL = "https://api.nasa.gov/neo/rest/v1]";  
const axios = require("axios");

export const searchFeed = data =>  
  axios.get(  
    `${APIURL}/feed?start_date=${data.startDate}&end_date=${data.endDate}&api_key=${process.env.REACT_APP_APIKEY}`  
  );

export const browse = () =>  
  axios.get(`${APIURL}/neo/browse?api_key=${process.env.REACT_APP_APIKEY}`);

To add the functions for making the HTTP requests to the NASA API for getting asteroid data and searching for them.

process.env.REACT_APP_APIKEY has the API key when you add the API key to the .env file of your project with REACT_APP_APIKEY as the key. Register for an API key at NASA.

Finally, we add TopBar.js to the src folder and add:

import React from "react";  
import Navbar from "react-bootstrap/Navbar";  
import Nav from "react-bootstrap/Nav";  
import { withRouter } from "react-router-dom";

function TopBar({ location }) {  
  const { pathname } = location;  
  return (  
    <Navbar bg="primary" expand="lg" variant="dark">  
      <Navbar.Brand href="#home">NASA App</Navbar.Brand>  
      <Navbar.Toggle aria-controls="basic-navbar-nav" />  
      <Navbar.Collapse id="basic-navbar-nav">  
        <Nav className="mr-auto">  
          <Nav.Link href="/" active={pathname == "/"}>  
            Home  
          </Nav.Link>  
          <Nav.Link href="/search" active={pathname.includes("/search")}>  
            Search  
          </Nav.Link>  
        </Nav>  
      </Navbar.Collapse>  
    </Navbar>  
  );  
}

export default withRouter(TopBar);

This is the navigation bar at the top of each page in our app. We set the active prop by checking the current URL of the page so we get highlights in our links.

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