JavaScript: Abstraction, Data, and Expressions

Will Pocklington
UH COSC 4315 Group Project
17 min readFeb 25, 2019

--

In computing, everything revolves around data manipulation. Every single program, website, and project requires the analysis and control of various data types to perform some task. Of course, we humans have difficulty dealing with such a vast amount of data, not to mention the complexities that are involved in manipulating it. To ease that difficulty and assist in data analytics, we employ abstractions to help represent the data and the control methods employed in the program. Today, we will take a deep dive into the data, abstractions, and the expressions used to analyze the data in JavaScript.

Data Types:

A variable in JavaScript is dynamically-typed, meaning typing is not checked until run-time, and a variable can be changed between data types as needed.

There exist 7 basic data types in JavaScript, which are:

Numbers:

Unlike most languages, integers and floating point numbers are combined into a single data type. Of special note are Infinity, -Infinity, and NaN. Infinity and -Infinity representing infinity and negative infinity respectively. Infinity is greater than every number, and the opposite applies too -Infinity. NaN represents a computational error (like dividing by 0), with further operations on NaN resulting in NaN. This prevents fatal errors from such operations.

Strings:

There exist three types of strings in JavaScript, determined by the type of quotation used. “Double quotes” and ‘single quotes’ function the same, and simply present a sting. The third type, `backticks` allows the use of extended functionality and allow the use of embedded variables as indicated by ${…}

Boolean:

Similar to most other languages, can be True or False. Used for logical operations and returned by logical operations.

Null:

In JavaScript, the null value is not a reference to a non-existing object in a language such as in C# but rather represents nothing, empty, or unknown.

Undefined:

Similar to null, undefined means “value not assigned”

Object:

The above data types are primitive in the fact that the can only hold a single thing. Objects can be used to store collections of data and other more complicated entries. These are similar to objects in Java.

Symbol:

used to create unique identifiers for objects and their properties.

Data Abstraction:

JavaScript supports object-oriented programming similarly to other popular programming languages such as C++ and Java. However, there is a major difference: JavaScript is not class-based like those other languages despite the fact that you can declare a class in JavaScript. Instead, JavaScript uses “prototype-based inheritance,” and the usage of the “class” keyword in JavaScript is merely to mask the prototype-based classes and make the syntax looks cleaner. A prototype-based inheritance language is similar to class-based in that it involves the basic tenets of OOP: abstraction, encapsulation, inheritance, and polymorphism. In the case of prototypal OOP, abstraction only involves objects. For class-based OOP, you probably would have already seen the type of hierarchy in terms of the levels of abstraction. Here we have an example of an object alipour of class Professor that is a subclass of Human:

In JavaScript, a prototypal programming language, we would again have alipour as an object, but instead of classes professor is a prototype of alipour and human is also a prototype of the human.

In a way, you can say that each object “extend” from each other. That is why inheritance is so powerful in JavaScript: because both prototypes and objects can inherit from prototypes. Now, we will try to explore prototypes and inheritance in JavaScript through coding! We will start by creating a constructor using the function keyword in JavaScript.

Functions in the case of JavaScript can act as both subroutines and, in a sense, classes. For now, we will focus more on the OOP aspect of using functions in JavaScript. The Person function and constructor, in this case, will be our “superclass.” Now, we will create a subclass called Student.

The subclass has almost all of the same parameters except years which will indicate how long the student has attended the school. Additionally, it also calls the constructor Person to inherit its fields, completing one of the requirements of inheritance. We also need to make some indication that our code is working and that our inheritance will show some differences between the two functions Student and Person, so let’s add a new method.

Here, we use the prototype keyword to dynamically add a new method to our constructor that returns the name of the object. Now, we will implement inheritance using prototypes. In Java, we would use the extend keyword. In JavaScript, we would do something like so:

We are using the create() method of the Object prototype from the JavaScript library to create a new object of type Person.prototype that will also be a prototype, and therefore it will inherit the methods of the Person.prototype. To summarize it, the Student.prototype is now an object of the Person.prototype, and it will be able to use both its own methods and the methods of the Person function. It could be a little bit confusing at first to understand if you are used to languages that use classical inheritance, but just know that JavaScript is a lot more focused on objects than it does classes. We will now have to show the usage of inheritance in JavaScript by using the first method that we added to our Person constructor that was also inherited earlier. We will do that by also adding a new method to our Student. prototype and create an object of Student to showcase our example:

There we have it! Our first example of inheritance in JavaScript. We have created a Student object that uses a combination of a method from Student and a method from our very first constructor Person. Now, we will showcase one additional thing, which is a polymorphism. In our same example, if we were to add an additional method to our Student.prototype like so,

we will be able to override the greet() function in our Person prototype which will return “I am not John Doe” as opposed to “I am John Doe” if it were to use the original greet().

Unlike inheritance, encapsulation is only involved in some degree as JavaScript does not have data hiding through the use of keywords like “public” and “private.” We typically use Closure for data privacy in JavaScript. Here is a demonstration of using closures (for better understanding, we will not use ES6 features in this demonstration). In this image we will find out that even string i and the first parameter is not in the same scope as the return function, we still can access it.

Therefore, a closure is basically an inner function which has access to the parameters of its outer function, even the outer function has already returned.

We can use a prototype to inherit a function. The image below shows that the cal function is a child of the adult function. When we create an object (US) of the parent function, we now can use US.cal(Object.childfunction) to call the child function.

Arrays:

Another component of data abstraction are data structures that allow the programmer to bundle data into a single unit rather than dealing with all of the data at once. In JavaScript, one of the most basic data structures is the array, which is used to store simple collections of primitive data types or objects.

The above is the code used to generate an array with random access.

Maps:

Formally introduced in ES6, the Map is a more complicated data structure that associates some form of data to a key. Knowing the key allows for more efficient data searching and storage. Even objects can be used as keys in the map.

Of special note are weakMaps. Unlike the normal maps, weakMaps allow free garbage collection, at the cost of being unable to check the size of the map and to clear all contents of the map at once using the clear() method.

Also introduced in ES6 is the Set. Set functions similarly to an array, albeit not allowing for duplicate values. However, there could be issues depending on the browser used in the case of -0 not being equal to +0.

As seen above, an issue with the set is testing object equivalence, with two effectively identical sets allowed to be in the same set as distinct items due to the fact they are stored in memory as different objects.

Expressions:

JavaScript has the arithmetic expression, string expression, and logical expressions. For example, x = 5 is an expression that we assign value 5 to the variable x. There are also conditional expressions. For example, the image below shows an if statement which evaluates the x with 5 and executes the console.log.

JavaScript includes various other operators. The 5 basic mathematical operators (+,-,*,/,%) are all included. The “+” operator is also used for string concatenation. Other mathematical operators include various bit-wise operators (bit shifts, AND, OR, XOR, NOT)

The image shows a simple addition expression.

Of note is the delete operator, which will delete an object, an object’s property, or an element in an array. It will then set that value to undefined if possible and return true, else it will return false.

Much of the rest of the operators are the same as in most languages. Comparison operators include >=, <=, >, < and the strict and loose equals seen above. There exists logical OR (||), AND (&&), and NOT (!expression). The assignment operator is fairly standard as well, except that it also has options to perform all arithmetic operators before assigning, including bit-wise operations.

The image shows a simple compare expression and logical expression.

All assignment operators in JavaScript

JavaScript has only one expression that accepts three operands which is a ternary operator. The ternary operator works the same as the regular if statement, but it is more easy to write and understand.

After ES6, JavaScript gets a new feature which is arrow function. We usually write a function like the image below.

After ES6, we can write a function using an arrow operator like this.

It is much shorter, easy to read and more semantic.

JavaScript has a unique function expression which is IIFE (Immediately Invoked Function Expression). It is a self-executing anonymous function. It is used in data protection. We can wrap a function with parentheses and add parenthesis after it as shown below. Both functions executed as expected. However, the difference between IIFE and regular function is that we cannot access the data from outside.

If we try to print out the value of i, we will get an error, because we do not have access to it.

We can actually pass the value to the IIFE as shown below.

Hence, IIFE is great for data privacy, but not for data reuse.

Control Abstraction:

Control abstraction in JavaScript can be considered any part of the code that performs more complicated tasks behind the scenes. Whether it’s conditional statements, loops, or user-defined functions, there are many operations occurring at a lower-level that the programmer may not be aware of. The beauty of a high-level programming language such as JavaScript is the ability to keep the code as human-readable as possible.

Conditional Statements:

Conditional statements are blocks of code that either execute or not based on a given condition. The condition should be either true or false, such as a Boolean value or a logical expression. Conditionals are used in any programming language to determine the logical flow of the program and are commonly used in natural languages as well.

We can also add an else block to catch any cases where the condition might be false. This is often called an “if … else” statement.

Conditionals can be strung together and nested as well. Consider the example below:

The condition variable has been replaced with logical expressions. The variable n is assigned a value of 5, then the expression n < 2 is resolved to either true or false. In this case, the expression is false because 5 is greater than 2, so the subsequent block of code is not executed.

We then continue to the next conditional check after “else if…”, which combines the else and if keywords to string together conditional blocks. If the first condition returned true — if n was equal to 1, for instance — the rest of the else blocks would not be executed. In our case, we move on to check if n is greater than 7, which is also false. So, this block of code is skipped, and the last else block is executed.

While within the last block, we begin a nested conditional statement which checks if n is equal to 5. Finally, an expression is true, and the conditional block is run. It is easy to see how conditional statements can become very complex, especially when logical expressions are included.

If successive if..else if statements are not your thing, there is the switch statement. Also known as the switch case statement, the switch tests a variable and then evaluates its equivalence to a number of case statements. If a case is found for the given input, the code for that case is executed. If no case exists, either the default case code executes or the program proceeds as normal. An example:

Note the use of break at the end of each case, without the break statement at the end the code would continue and execute cases that are false.

Because of dynamic-typing (also called a “loosely-typed” language), it is common for two values of different types to be compared. This becomes a complex task and has some particular behavior in JavaScript. One easy example is the comparison between undefined and null values, or variables u and n respectively in the example below:

The first conditional expression (u == n) returns true, and the conditional block of code is executed. In JavaScript, null and undefined are loosely equal to each other. To check for strict equality, three equals signs are used. Undefined and null are not strictly equal to each other in JavaScript, so the second block of code will not run. Let’s fix that by using the !== comparison operator (note the difference between !== and !=).

Additionally, empty strings and boolean false are compared in the same manner

Another thing to consider when comparing strings:

The JavaScript engine converts the two values to the same data type when a loose comparison occurs, and the integrity of the data types are preserved when they are strictly compared. For the majority of comparisons programmers make, most of the differences between two and three equal signs are intuitive. Whenever in doubt, console log it out.

Loops:

For Loop:

The for loop in JavaScript has a comparable syntax as C and Java. In essence, a loop counter is declared (var i = 0), an expression is used to define how many times the loop should run (i < 10), and the variable is then typically incremented or decremented by some amount after each loop iteration occurs (i++). In this example, the code within the curly braces is executed ten times, and the script prints the numbers zero through nine in the browser’s console.

While we haven’t discussed much scope, JavaScript has one quirk in regards to variable declarations that are present in the example above. When a variable is declared using var, it isn’t destroyed at the end of the current scope (or block of code). This is slightly unusual compared to most programming languages, but it can be useful.

As a note, this is syntactically equivalent to omitting the var keyword while defining a loop:

for(i = 0; i < 10; i++) …

An alternative to var is let, which exhibits stricter scope behavior, and the variable is deleted once the scope has closed. The following snippet of code throws an error because i is undefined when console.log is called.

The for loop can be utilized to iterate through a collection of data. Arrays in JavaScript have a “length” property (similar to Java, arrays and other primitive data types are “wrapped” in an object and have associated methods and attributes), which can be used to define how many times the loop needs to run. The following example calculates the summation of an array of numbers:

Notice how we use numbers.length in this loop.

JavaScript offers a simpler version of the for loop to iterate through a collection, sometimes referred to as a “for-in” loop:

Generally, for loops are useful when we can easily define how many times the block of code should be executed.

While Loops:

Another common control abstraction found in JavaScript is while loops. Any for loop can be converted to a while loop, but the opposite may not always be true. Here is the equivalent while loop of the summation example above:

Essentially, what was between the parentheses of the for loop has been deconstructed and placed around the loop statement. The counter is defined before and incremented during the while loop, with only the expression remaining between the parentheses. It’s worth noting that if the condition is false as the while loop begins, the code will not be executed. Which brings us to the do-while loop.

The code within the do block is always executed at least once, even if the expression returns a false value. This example illustrates why this happens, as the comparison occurs after the block of code. For instance, if we change i to equal 11, the block of code still runs. It outputs the value to the console and increments i.

Proving useful in many algorithms, while loops and for loops are commonplace in programming languages. However, the programmer must always be careful not to create an endless loop (unless that is the intention).

Subroutines:

Subroutines are functions that can receive data, manipulate data, and return a value. In JavaScript, subroutines are referred to as functions. Subroutine functions are made up of instructions which accomplish a specific task. By encapsulating all of the instructions into a function, you can call the function in a program multiple times whenever that specific task needs to be done. Subroutines fall under the suspend and resume paradigm. When executing a program, if a function call is made the program stops and waits until the function returns a value. The returned value is then used to execute the next line of code from where the function was called. Subroutines are typically used to divide a big problem into smaller problems.

If you were a phone company and were trying to calculate how much to bill a customer you could have the following subroutines: sumOfMinutes, costOfUse, totalBill. The subroutine sumOfMinutes would calculate the number of minutes a customer used during a period of time. Once that number has been calculated, you can pass that value to costOfUse to calculate the total amount the customer will be charged prior to taxes. Finally, you can pass the returned value of costOfUse to totalBill where it will return a value of the total amount that the customer will have to pay with taxes included.

As you can see, using subroutines to divide and conquer a bigger problem is a useful feature. The creation of subroutines in JavaScript is done through functions. In order to create a function in JavaScript, you need to use the keyword ‘function’ followed by a name. The function name can consist of letters, numbers, underscores and dollar signs. After naming your function, you have the option to add parameters and finally, you have the body of the function which is enclosed in curly braces. So the syntax is the following:

function name(parameter1, parameter2,..){

Code to be executed

}

If you do not add parameters to your function then you will not be able to pass arguments to it when calling it. One thing to note is that in JavaScript arguments are passed by value and not by reference which is different from other programming languages such as C++. Let’s say that we need to create a subroutine to find the area of a rectangle. Let’s also assume that we want to create a subroutine that accepts any size rectangle. In order to achieve this, we need to create a function with parameters which will allow us to pass as arguments the dimensions of a rectangle. The code for such a subroutine would be the following:

Using arguments 5 and 4 (line 6), the area function returned the value of 20.

If the dimensions of the rectangle were to remain constant, then you could still build a subroutine to calculate the area by creating a function without parameters. This will allow you to use the variables that contain our rectangle’s information and use them to calculate the area. The following function accomplishes our task:

A rectangle with a length of 10 and width of 9 was created. Since those variables are in the scope of the function, the value of 90 was returned. Since I knew that the function did not have any parameters, I did not pass any values as arguments (line 8).

What if you try to call a function without parameters with arguments? Either the program can terminate with an error or it will ignore the arguments. Here is an example:

As you can see, the program terminated but it still showed that the function returned a value of 90 rather than 20.

Group 3 Authors:

Anh Le @anhle697

David Alvarado David Alvarado

Payne Wheat @PayneWheat

Shouchuang Zhu @shouchuangzhu

Will Pocklington @pocklingtonWill

--

--