JS Brain Dump { part 1 } : 'Equality, Primitive/Object Types, and (A)synchronous JavaScript'

ยท

6 min read

This article is part of a series answering some of the most important (and sometimes confusing) JavaScript questions

1) Equality

In Javascript, you can compare items with:

  • The double equals operator (==, aka the equality or abstract comparison operator)
  • The triple equals operator (===, aka the identity or strict comparison operator)
var number_one = 13;
var number_two = 13;

console.log(number_one ==  number_two); // true
console.log(number_two === number_two); // also true

Both scenarios in the above example return true, but what exactly is being checked by the two operators? The most important thing to know about the double equals (==) is that it compares the value while also ignoring the data type. Although both number_one and number_two are both integers, the == does not care about this. It simply cares about the value held by each variable, in this case 13. In fact, behind the scenes there is an implicit type conversion, meaning that even before it checks the value, it forces both number_one and number_two to the same data type.

On the flip side, the triple equals operator (===) cares very much about data types. Not only does it check to make sure that number_one and number_two are the same value but also the same data type. In the above example it returns true since both variables are integers and have the same value.

Let's make a tiny modification and see this in more depth:

var number_one = 13;
var number_two = "13";

console.log(number_one ==  number_two); // true
console.log(number_two === number_two); // false

number_one is an integer of 13 and number_two is a string of '13'. == will do a an implicit type conversion so the difference does not matter, only the value 13, thefefore returning true. === will not do a type conversion and will compare them as they are. It returns false since a string is not the same as an integer.

2) Primitive Values and Object References

Understanding data types in Javascript is crucial to understanding how comparisons work. In Javascript, every data type can be classified as either a primitive value or an object reference.

Both behave differently and understanding this fundamental difference will make you a better Javascript developer.

All in all, there are 8 data types in Javascript:

  • Boolean
  • BigInt
  • String
  • Null
  • Undefined
  • Number
  • Symbol
  • Objects

(As someone who comes from a Python background, this list initially looked strange to me as it's missing arrays, functions, and dates but in actuality, they are under the umbrella of objects.)

So what's this have to do with primitive and value types?

Well, when a variable is assigned a primitive type (e.g., number_one = "thirteen"), the variable is set to that same value directly. On the flip side, when a variable is assigned to an object, things work differently. Rather than the variable containing the value directly, it contains a reference to it in memory.

const wes = {
  name: 'wes house',
  occupation: 'writer & engineer',
  city: 'berlin'
}

When wes is created in Javascript, it's stored as an object somewhere inside the computer in memory. The variable does not in fact contain the object, but a reference that stores the object. Just like how a street address does not contain specific information about the specific details about a house (e.g. number of rooms, people who reside there, number of stories, etc) but points to its exact location in a city, an object reference points to where the actual object resides in the computer without necessarily pointing to the values inside the object.

What does this mean in reference to equality comparison?

'wes house' === 'wes house' // true
false === false // true
1991 === 1991 // true
undefined === undefined // true

As we can see, primitive behaves just as we'd imagine them to.

Objects are a different matter:

{ website: 'hashnode' } === { website: 'hashnode'  } // false
[ ] === [ ] // false
new Date(0) === new Date(0) // false
NaN === NaN // false (NaN is an object)

All of the above comparisons are done on objects which, as stated above, are references to a place in-memory and not the value contained. Although { website: 'hashnode' } has the same exact key and value as { website: 'hashnode' }, they are two different objects, making a strict comparison return false. It takes time as a developer to intuitively understand this concept, but it's crucial to grasp not only for Javascript, but for computer science in general.

3) Asynchronous JavaScript

Although asynchronous JavaScript is a fairly advanced topic, the basic premise can be understood with only a little code being written.

In a nutshell, asynchronous programming allows developers to begin a long-running task while still being able to continue other events while that task is running. After the task is completed, your program can run its final execution with the results.

The first thing to note is the chain of events, or more specifically, synchronous code.

console.log("This runs first")
console.log("This runs second")
console.log("This runs third")

In JavaScript, the above program would run in order from top to bottom with the output:

"This runs first"
"This runs second"
"This runs third"

JavaScript is by nature a very synchronous language. It will run one statement, from top to bottom, at a time. Line three can not run until line two is finished. Line two can not run until line one is finished.

0.png

For this reason, JavaScript is often referred to as a single-threaded language.

With this synchronous method in mind, let's imagine a scenario: We have the four tasks as shown above in a program. Some of the functions do easier tasks like log things to the console or execute some arithmetic. But one of the tasks makes an HTTP request to a database in order to retrieve needed data for the app to work correctly. Let's say it's a fairly large request that can take up to ten seconds to retrieve.

0 (1).png

With synchronous programming in mind, task four would not be able to run until task three was completed. This is a big disadvantage to synchronous code and why asynchronous code is important to understand. The general motto of asynchronous code is to start something now and then finish it later. This is generally the motto we should be trying to follow when running tasks that may take longer to complete. Let's illustrate how the same series of tasks would run if they were written asynchronously.

0 (2).png

With asynchronous JavaScript, we can start task three and finish it later when the rest of the data is retrieved. In order to do this, we will give task three some sort of callback function as a parameter. That callback function will run and finish after the data is retrieved. Remember that JavaScript can run only one thing at a time. But when we run an asynchronous function, the browser takes this request and handles it outside of our single-threaded program in another part of the browser. It also takes a callback function and puts it to one side also so that it knows to execute this later one when the data is secured. Since this task is now handled outside of the browser, JavaScript can continue down the line and carry out the remaining functions (in our case, it can complete task four) while the request for data is still processing. Once the data is finally received, the callback function can be called and the program can be completed.

This is the core of asynchronous JavaScript. There is still a lot more going on and the possibilities extend further than this. But this example paints the general idea of what asynchronous programming is: it governs how we tackle tasks that may take a potentially long time. If you're making a true JavaScript application, chances are at some point you will need to use asynchronous programming.

ย