loading...
Cover image for Learn Data Structure & Algorithm in JavaScript | Part 02

Learn Data Structure & Algorithm in JavaScript | Part 02

edisonnpebojot profile image Edison Pebojot(๐Ÿ‘จโ€๐Ÿ’ป) Updated on ใƒป14 min read


Prerequisite (๐Ÿ‘€)

If you're reading this article right now, please considered to review(Click here to review) our Part 01: Big-O Notation Primer or full read our Part 01: Big-O Notation Primer:

Part Table of Contents Description
01 Big-O Notation By the end of this chapter, you will understand how to analyze an implementation of an algorithm with respect to both time (execution time) and space (memory consumed).
02 JavaScript Unique Parts Big-O is important for analyzing and comparing the efficiencies of algorithms. The analysis of Big-O starts by looking at the code, and, applying the rules, applying the rules is because to simplify the Big-O notation linear or quadratic rule is not enough.
03 JavaScript Numbers This part 3 will focus on JavaScript number operations, number representation, Number objects, common number algorithms, and random number generation.
04 JavaScript Strings This part 4 will focus on strings, JavaScript String object, and the String objectโ€™s built-in functions. You will learn how to access, compare, decompose, and search strings for commonly used real-life purposes. In addition, the chapter will explore string encoding, decoding, encryption, and decryption.
05 JavaScript Arrays As a JavaScript developer, you will use the array often; it is the most commonly used data structure. Arrays in JavaScript come with a lot of built-in methods. By the end of this part, you will understand arrays and choose the right method
06 JavaScript Object This part will focus on what JavaScript objects are, how they are declared, and how their properties can be changed. In addition, this part will cover how JavaScript classes are implemented using prototypal inheritance. Also this part will be short.
07 JavaScript Memory Management A variable takes up some memory. In C, the programmer allocate and deallocate memory manually. In contrast, modern JavaScript engines have garbage collectors that delete unused variables. However, there are pitfalls(unexpected) that developers can fall into(โ—) This part will show these unexpected and present techniques to help the garbage collector minimize the memory problems.
08 Recursion This part 8 introduces the concept of recursion and recursive algorithms(Remember they are different, we will discuss them later(๐Ÿ˜‰)). We will also discuss the definition of recursion and fundamental rules for recursive algorithms.
09 Sets This part focuses on the concepts of sets from both a mathematical definition and on the implementation. Also, Common set operations, as well as their implementations, are covered in great detail (๐Ÿ’ก).
10 Searching and Sorting This part 10 focuses on searching and sorting for arrays. By the end of this part 10, you will understand how to use sorting and searching algorithms for arrays. Also, this article is a bit complicated for beginners, so as much as possible the visual aids is your friend (๐Ÿ‘€). (๐Ÿ˜ƒ)
11 Hash Tables A hash table is a fixed-sized data structure in which the size is defined at the start. This part 11 explains how hash tables work, and the method of generating a unique key. By the end of this part 11, you will understand various hashing techniques and know how to implement a hash table. (๐Ÿ˜ƒ)
12 Stacks and Queues This part 12 covers stacks and queues(pronounce as kyooz (๐Ÿ”ˆ)) not (kwewe) okay? hehehe (๐Ÿ˜…); both are data structures used in the implementation of complex data structures. You'll learn what the stacks and queues are, how they're used, when they're used, and how to implement them (๐Ÿ˜ƒ) Let's go! (๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ)
13 Linked Lists A linked list is a data structure in which each node (or element) points to another node. Unlike arrays, which have a fixed size, a linked list is a dynamic data structure. By the end of this part 13, you will understand how to implement and work with linked lists. And oh! (๐Ÿ˜ฎ) There are two types of linked lists: singly (โžก๏ธ) and doubly (โ†”๏ธ). Letโ€™s examine the singly linked list first.(๐Ÿ˜ƒ) Let's go! (๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ)
14 Caching Caching is the process of storing data into temporary memory so that it can be easily retrieved for later use if it is required again. As an example, a database keeps data cached to avoid re-reading the hard drive, and a web browser caches web images to avoid re-downloading. In this part 14, two caching techniques will discussed: LFU and LRU caching.
15 Trees A general tree data structure is composed of nodes with children nodes. The top node is called the root node. This part 15 will explore different types of trees such as binary trees, binary search trees, and self-balancing binary search trees. First, this part 15 will cover what trees are and how they are structured. Then, it will cover methods of traversing(crossing or taking a zigzag path) the tree data structure in detail. Finally, you will learn about binary search trees and self-balancing binary search trees to understand how to store searchable data. (๐Ÿ˜ƒ)
16 Heaps A heap is an important data structure that returns the highest or lowest element in O(1) time. This part 16 will focus on explaining how heaps are implemented as well as how to work with them. One example is heap sort, which is a sorting algorithm based on heaps.
17 Graphs In this Part 17, you will learn graph basics, including fundamental terminology and graph types. The Part 17 will also cover working with these different graph types and methods of representing graphs in data structures. Finally, algorithms for traversing, searching, and sorting graphs are explored to solve problems such as finding the shortest path between two graph nodes. (๐Ÿ‘)
18 Advance Strings Part 18 will cover more complex string algorithms than covered in the previous section. Now that you have heard of certain other data models or structures, they should be easier to comprehend. Specifically, Part 18 will focus on string searching algorithms. (๐Ÿ˜‰)
19 Dynamic Programming Dynamic programming involves breaking down problems into their subproblems. Solving the subproblems and saving those results into memory to access them whenever a repeated problem needs to be solved, the algorithmic complexity decreases significantly (โฌ‡๏ธ). To explain dynamic programming, letโ€™s re examine the Fibonacci sequence that was discussed in Part 8. Then Part 19 will cover the rules of dynamic programming and walk you through some examples to make the concepts more concrete. (๐Ÿ˜‰)
20 Bit Manipulation Bit manipulation is an advanced topic that JavaScript developers typically do not need to know. However, you should learn a bit about bit manipulation if you want to implement high-performance server-side code. Understanding bit manipulation requires some knowledge of digital logic. Any introductory course in discrete math or circuits would be helpful to understand these concepts.

Review: Part 01 Big-O Notation Primer (๐Ÿ“–)

Big-O is important for analyzing and comparing the efficiencies of algorithms. The analysis of Big-O starts by looking at the code, and, applying the rules, applying the rules is because to simplify the Big-O notation linear or quadratic rule is not enough. The following are the most often used rules:

  • Eliminating constant
  • Adding up Big-O Notations
  • Multiplying Big-O Notations
  • Determining the polynomial of the Big-O notation

Part 02: JavaScript: Unique Part(๐Ÿ˜ฑ ๐Ÿ”ฅ โšก)

Alt Text
This part 2 will briefly discuss some exceptions and cases of JavaScriptโ€™s syntax and behavior, so you may see (๐Ÿ‘€) some changes in JavaScript that may not be familiar to you. (๐Ÿ˜…)

Also, this part 2 will focus on concepts that are fundamental to JavaScript and will help you to develop a better understanding of the process of designing algorithms in JavaScript. So this part 2 would be easy. (๐Ÿ‘Œ)

JavaScript Scope (๐Ÿ”ญ๐Ÿ”ญโญโญ)

The scope is what defines the access of variables. In JavaScript, variables can belong to the global scope or to the local scope. Global scope variables are variables that belong in the global scope and are accessible from anywhere in the program.

Global Declaration: Global Scope (๐ŸŒ)

In JavaScript, variables can be declared without using any operators.

Note:(๐Ÿ“) An operator performs some operation. For example 1 + 2, where +(or plus symbol) is an operator and produces a result which is 3 in this case. But here, we don't use an operator:

Hereโ€™s an example:

number=3 number

However, since number is a global variable, avoid doing this at all costs because this is one of the worst practices in JavaScript. Hackers may use the global variables for hacking purposes (โš ๏ธ). Anyway, always use var or let to declare variables: (๐Ÿ˜‰)

// Without var or let
number=3
number

// With var or let
var number_one=3
let number_two=3
number_one
number_two
Enter fullscreen mode Exit fullscreen mode

Finally, when declaring variables that wonโ€™t be modified, use const: (๐Ÿ‘)

// With const
const number=3
number
Enter fullscreen mode Exit fullscreen mode

Declaration with var: functional Scope (โญ•)

In JavaScript, var is used to declare variables. These declarations of variables(var and not let and const) โ€œfloatโ€ all variables way up to the top. This is known as variable hoisting. Variables that are declared at the bottom of the script will not be the last thing executed in a JavaScript program during runtime. In short, it will declare the variable from the top(โฌ†๏ธ). Here is an example:

function scope(){ bottom = "No!, I am the real bottom"; // Top console.log(bottom); var bottom="I am the real bottom"; // Bottom } scope(); // it will prints "No!, I am the real bottom" - no error

Note:(๐Ÿ“) Notice that it prints "No!, I am the real bottom". Why? Because the variable at the bottom(which is var buttom) is hoisted all the way up to the top leaving the initialization ="I am the real bottom" useless. That's why it use the initialization at the top instead in the bottom which is bottom = "No!, I am the real bottom" that's why it prints "No!, I am the real bottom"

Here's another example but the previous one is the same as writing this one:

function scope(){ var top="I am the real top"; // Top console.log(top); top = "No!, I am the real top"; // Top } scope(); // it will prints "I am the real top" - no error

Note:(๐Ÿ“) Notice something? It prints "I am the real top" instead of "No!, I am the real top" Why? Because the variable at the bottom(which is top) is hoisted all the way up to the top leaving the the initialization useless or not hoisted that's why it instead uses the initialization to the top printing "I am the real top" (๐Ÿ’ก๐Ÿ’ก)

The bottom variable declaration, which was at the last line in the function, is floated or hoisted to the top(โฌ†๏ธ), but not the initialization, and then logging the variable. The var keyword is the scope of the variable is the closest function scope.

Don't try to understand for now, we will explain it further.

In the following code, the scope function is the function scope closest to the print variable. Let's give an example:

function scope_one(print){ if(print){ var insideIf = 'I help var to access the function scope!'; } return insideIf } scope_one(true); // prints 'I help var to access the function scope!'

To illustrate, the preceding function(which is scope_one) is equivalent to the following code scope_two:

function scope_two(print){ var insideIf; if(print){ insideIf = 'I help var to access the function scope!'; } return insideIf } scope_two(true); // prints '12'

In Java, this syntax would have thrown an error (โŒโŒ) because the insideIf variable is generally available only in that if statement block and not outside it.

var a=1 function scope_three() { if(true) { var a=4 } return a } scope_three()

4 was printed, not the global variable with a value 1, because it was redeclared and available only in that function scope. Function scope helped variable to have its scope inside the function once it was declared inside it. Okay! (๐Ÿ™Œ)

Declaration with let: Block Scope (โญ•)

Another keyword that can be used to declare a variable is let. Any variables declared in this way are in the closest block scope (meaning, they are only available where they are declared). Here's an example:

function scope_four(){ if(print){ let insideIf = "I don't help let to access the function scope! Depending where they are declared or available"; } return insideIf } scope_four() // See something? Remember that it might produce an "Error" once you clicked the run button

In this example, nothing is logged to the console(or error) because the insideIf variable is available only inside the if statement block.

Equality and Types (๐Ÿ‘ฉ๐Ÿ‘จ)

JavaScript has different data types than in traditional languages such as Java. Letโ€™s explore how this impacts things such as equality comparison. (๐Ÿ˜‰)

Variable Types

In JavaScript, there are seven primitive data types. And here's a list of 7(seven) primitive(primary) data types:

  • boolean
  • number
  • string
  • undefined
  • object
  • function
  • symbol (symbol wonโ€™t be discussed)

Undefined is a primitive value that is already available to a variable once it has been declared(except if it has a value):

Example:

var nothing; nothing // will print undefined since is already available to a variable once it has been declared(except if it has a value)

Another one is typeof, typeof is the primitive operator used to return the type of a variable.

Example:

var is20 = false; // boolean console.log(typeof is20); // boolean var age = 19; console.log(typeof age); // number var lastName = "Bae"; console.log(typeof lastName); // string var fruits = ["Apple", "Banana", "Kiwi"]; console.log(typeof fruits); // object var me = {firstName:"Sammie", lastName:"Bae"}; console.log(typeof me); // object var nullVar = null; console.log(typeof nullVar); // object var function1 = function(){ console.log(1); } console.log(typeof function1) // function var blank; console.log(typeof blank); // undefined // click run

Truthy/Falsey Check

True/false checking is often used in if statements. In many languages, the parameter inside the if() function must be a boolean type(boolean type is true or false value). However, JavaScript is more flexible with this. Hereโ€™s an example:

if(node){
//...
}
Enter fullscreen mode Exit fullscreen mode

Here, node is a variable. If that variable is empty, null, or undefined, it will be evaluated as false in JavaScript. Here are commonly used expressions that evaluate to false:

  • false
  • 0
  • Empty strings ('' and "")
  • NaN
  • undefined
  • null

Here are commonly used expressions that evaluate to true:

  • true
  • Any number other than 0
  • Non-empty strings
  • Non-empty object

Here's an example:

var print; if(print) { return true } else { return false } // What do you think this code will going to print, true or false?

=== VS ==

JavaScript is a scripting language, and the variable types are interpreted as the code runs. Hence, === checks for both the
type and the value, while == checks only for the value.

Example:

var x=1,y=1,z="1" if(x==y){ console.log('In ==, x and y has the same value') } if(x==z) { console.log('In ==, x and z has the same value') } if(x===y){ console.log('In ===, x and y has the same value and type') } if(x===z) { } else { console.log('In ===, x and z has the same value but not type') } // Study the results after

1 == "1" returns true because the value "1" is forced to a number after(or before) the comparison and interpreted its value. On the other hand, 1 === "1" returns false because the type of "1" is a string, while 1 is a number.

Objects

Most strongly typed languages such as Java use isEquals() to check whether two objects are the same. You may be tempted to simply use the == operator to check whether two objects are the same too in JavaScript right? However, this will not evaluate to true.

var a={},b={} if(a==b){ console.log(true) } else { console.log(false) } if(a===b){ console.log(true) } else { console.log(false) } // Notice something? Is it false? Why?

Although these objects are equivalent (same empty properties and same empty values), they are not equal. Namely, the variables have different addresses in memory to store.

This is why most JavaScript applications use utility libraries such as lodash or underscore, which have the isEqual function to check two objects or values strictly. This occurs by comparing the property or values of an object(not the object itself). In this example, each property is compared:

function isEquivalent(a, b) { // arrays of property names var aProps = Object.getOwnPropertyNames(a); var bProps = Object.getOwnPropertyNames(b); // Object.getOwnPropertyNames(a) returns all own properties of the object // If their property lengths are different or not equal, they're different objects if (aProps.length != bProps.length) { return false; } for (var i = 0; i < aProps.length; i++) { var propName = aProps[i]; // If the values of the property are different or not equal if (a[propName] !== b[propName]) { return false; } } // If everything matched, correct return true; } isEquivalent({'hi':12},{'hi':12}); // returns true

However, this would still work for objects that have a string or a number like "1" or 1. But arrays(or {}) and functions(or function()):

var a={'a':{},'b':function(){}}
var b={'a':{},'b':function(){}}

isEquivalent(a,b) // Will return to false
Enter fullscreen mode Exit fullscreen mode

This is because functions and arrays cannot simply use the == operator to check for their equality. Here's another example:

var function1 = function(){console.log(2)}; var function2 = function(){console.log(2)}; function1 == function2; // prints 'false'

Although the two functions perform the same operation, the two functions have different addresses in memory to store, and therefore, the equality operator returns false.

The equality check operators, == and ===, can be used only for strings and numbers. To implement an equivalence check for objects, each properties or values in the object needs to be checked.

Summary (๐Ÿ“š)

var declares the variable within the function scope, let declares the variable in the block scope, and variables can be declared in the global scope; however, global scope should be avoided. For type checking, typeof should be used. Finally, for equality checks, use == to check the value, and use === to check for the type as well as the value. However, use these only on non-object types such as numbers, strings, and booleans


Up Next๐Ÿ‘‰ Part 03: JavaScript Numbers ๐Ÿ”ฅ ๐Ÿ”ฅ (July 04, 2020)


Posted on by:

edisonnpebojot profile

Edison Pebojot(๐Ÿ‘จโ€๐Ÿ’ป)

@edisonnpebojot

I started using computers and writing software around 2008 and 2009, I taught myself Programming. However, I wasn't a typical "nerd-klutz". ๐Ÿ˜…

Discussion

pic
Editor guide
 

Check your example, I believe you have a wrong print at the end

function scope_one(print){
if(print){
var insideIf = 'I help var to access the function scope!';
}
console.log(insideIf);
}
scope_one(true); // prints '12'

Plus when you are talking about hoisting would be better to cover function declaration specifics as well

 

There's an error in your article.

Under Truthy/Falsey Check section,

You mention that non-empty objects evaluate to "truthy", which is right, but it's misleading because empty objects will also evaluate to "truthy".