Some Javascript guide

Who is this guide for?

This guide is for those who do not know javascript and wish to learn the basics of it.

Objective

After this tutorial you should have rough understanding of how to use javascript and be able to use it to do very, very basic stuff.

What is used in the tutorial?

  • Your preferred browser (I will be using chrome)
  • Your preferred text editor (I recommend sublime text)

Terminology

Why use Javascript?

Javascript, as of this writing, is very widely used. From making your webpages work, to making your server work, to making your javascript console program, it is probably the most hyped / in-thing a programmer can delve into right now. By learning the basics of javascript, you can attempt to learn javascript frameworks like react and vue.

Guide Start

The Browser

I will be using Google Chrome on macOS for this guide.

Learning via the Console

Open up chrome if it is not open yet and open a new tab. Press cmd + option + i for mac or ctrl + shift + i for windows to open up the inspector.

Inspector

Now head over to the console tab where we will do some javascript.

Console tab

Clear any logs if any by pressing the 'Clear console' button

Clear console button

It is the bottom right button of the 4.

Now you will do a standard command whenever you learn a programming language. You will type console.log('Hello World!') and then press enter. You should see Hello World! on the console.

Hello world

What you just did was to get the console to log the string 'Hello World!' (string means text).

In Javascript '' & "" both represents string. I prefer to use '' because you need not hold onto shift to type single quotes unlike for "".

You also see there is another line that says undefined, you can pretty much ignore that for now.

Now we shall try to log a number. Type console.log(1) and press enter. You should see that the number 1 appears. Now try with console.log('1') instead. You will see that 1 appears again but as black instead of the blue of the first 1.

console logging 1

From this we can see that Javascript has a datatype for text (String) and a datatype for numbers (Number). To help further illustrate the difference between a string and a number in Javascript, we shall do a bit of math.

Enter console.log(1+1). You should see 2 if my math did not fail me.

console logging 1 + 1

Similarly you can do subtraction, multiplication, and division in Javascript. Try console.log(1-2), console.log(2*3), and console.log(1/20).

subtraction, multiplication, division

TIP

* - multiply

/ - divide

Now try doing console.log('1' + '1').

concatenation

Woah, what is this behaviour that we are seeing? Well to put simply, in the 1+1 scenario, Javascript recognises this as addition between 2 numbers, thus it will do the math and output the result which is 2. However, in the '1' + '1' scenario, Javascript recognises those 2 1 as strings due to '', thus Javascript does something called 'Concatenation'.

What I am trying to get at is that computers do not understand that the string '1' is a actually a number 1 and that we would actually like to have done addition instead of concatenation. If you expected that in the '1' + '1' scenario will result in 2 then you should now understand that it gave 11 instead of 2 due to how Javascript deals with different datatypes.

But then you may wonder about -, *, and / between strings. Wellll, using + between strings changes the operation to become 'Concatenation' but for -, *, and /, there are no concepts of string 'minus / multiply / divide' string in Javascript, thus Javascript will forcefully convert the strings into numbers and attempt to do math.

Try console.log('0' - '3'), console.log('4' * '100'), console.log('200' / '3'), and console.log('a' - 'b').

math operators with strings

As you can see, Javascript converts the strings to become numbers and then do the math operations which worked except for the last scenario. Javascript is unable to convert 'a' and 'b' into numbers, thus returning NaN (Not a Number) as the result.

TIP

You may have also noticed that there is a limit to how many decimal points it can show before it rounds for the last decimal place.

Variables

Now that we have some basic commands and operations down, let's move on to Variables. The simpliest way to describe variables is that they 'store' information. The somewhat more proper description is that variables point to the location in memory where the data is stored.

Either way let's start getting familiar with them. Enter let name = 'Your name here', then enter name by itself.

declare name variable

As you can see from the image, the variable name was assigned the value 'Your name' and we were able to retrieve the value from it by simply entering the variable.

TIP

There is also another keyword for declaring variables which is var instead of let but I won't delve into the differences here.

What we just did was declaring a variable called name then we assigned a value of 'Your name here' to it. The declaration part was done by using the let keyword. You can actually declare a variable without assigning a value to it, so the code would look like let name, then you can assign it afterwards just by doing name = 'Your name here' (without the let as it has already been declared).

TIP

If you tried to declare the same variable again, you would see a error message saying it has already been declared.

Now let's do 2 variables by spliting up our name to first and last. Enter let firstName = 'Your first name here' then let lastName = 'Your last name here'. After that, enter console.log(firstName + lastName).

firstName + lastName

As you can see similarly to our + operation previously, Javascript saw that the values of the 2 variables were strings, thus it went ahead and concatenated them. Your name is probably missing a space between let's fix that by typing console.log(firstName + ' ' + lastName)

firstName + ' ' + lastName

Boolean

true or false is what booleans are all about literally. Booleans exists to facilitate checks in logic. To give some example, enter 2 * 3 == 6.

2 * 3 == 6

As you can see from the result given, 2 times 3 is 6. The check is done by comparing the result of 2 * 3 against the specifiec check value 6. This is done via the == operator.

We also have other operators to do different checks like != (not equal check), > (more than check), >= (more than or equal check), < (less than check), <= (less than or equal check).

Test them out like so:

let a = 10
let b = 20
a < b // true
a > b // false
a * 2 == b // true
a * 2 <= b // true
a * 2 >= b // true
let c = '10'
a == c // ?
a === b // ?

TIP

// - For writing comments in Javascript. Will not be executed by Javascript.

For the last 2 cases, I would like you to try it yourself to see how Javascript deals with such comparison.

If you tried them, you would see that the == operator is not as 'strict' as the === operator. == is ok with different datatypes of supposed 'same value' whereas === will not consider different datatypes to be equal at all even if the have the 'same value'.

Math.random

Let's throw some randomness in to change it up a little. We will generate a number and then we will check if it is more than 5. First we need to learn how to use Math.random. Enter Math.random() and you should see a random decimal value that is 0 <= random decimal value < 1.

Math.random

But generating values that are between 0 and 1 will never get us a value more than 5, so let's increase the range by multiplying. Enter Math.random() * 10. Now the range of value is from 0 to 9.999999999999999.

Math.random() * 10

Now we can do some checks, enter Math.random() * 10 > 5.

Math.random() * 10 > 5

if statements

Let's complicate this check a little with a new keyword if.

if (Math.random() * 10 > 5) {
	console.log('More than 5!')
}

From the code above, we can see how if statements are used. Reading it like english would be something along the lines of 'If Math.random() times 10 gives a result that is more than 5, we will log in the console "More than 5!"'. You may not see it now but the if statement is a powerful tool that allows programs behave differently depending on certain variables.

else and else if

We can chain checks by using else and else if keywords like so:

let randomInt = Math.random() * 10
if (randomInt > 8) {
	console.log('More than 8!')
} else if (randomInt > 5) {
	console.log('More than 5!')
} else {
	console.log('Less than or equal to 5!')
}

TIP

the {} brackets are necessary if we want more than 1 line of code for each checks.

Mini Exercise 1: Leap Year check

This exercise will require that you:

  1. Generate a random year between 0 to 9999
  2. Check if the random year is a leap year
  3. Log the year in the console if it is a leap year

Generating random integers instead of floats (decimals)

Up till now, we have been using Math.random to generate numbers for us but it has always been giving us decimals, or floats in technical terms. For Mini Exercise 1, what we need are integers (no decimal points). Thus a simple way is to floor the values that come from Math.random.

// get a random float
// multiply it by 10
// floor it to get random integers
Math.floor(Math.random() * 10)

Change the range to be 0 to 9999

Math.floor(Math.random() * 10000)

Checking leap years

A brief explanation on what a leap year is:

A leap year (also known as an intercalary year or bissextile year) is a calendar year containing one additional day (or, in the case of lunisolar calendars, a month) added to keep the calendar year synchronized with the astronomical or seasonal year. - Wikipedia

The algorithm as extracted from Wikipedia is:

  1. if (year is not divisible by 4) then (it is a common year)
  2. else if (year is not divisible by 100) then (it is a leap year)
  3. else if (year is not divisible by 400) then (it is a common year)
  4. else (it is a leap year)

As you can see, wikipedia puts the algorithm in a form of pseudo code. To check if a number is divisible by another number, we use the % (modulus) operator. The % operator gives the remainder after the division. With the remainder we can tell if the number is divisible when the remainder is 0. Thus we can check like so:

2016 % 4 == 0 // true

Now you have all the parts you need to finish the mini exercise.

Implementing Wikipedia's pseudo code
let randomYear = Math.floor(Math.random() * 10000)

if (randomYear % 4 != 0) {
	// Not leap year
} else if (randomYear % 100 != 0) {
	// Is leap year
	console.log(randomYear)
} else if (randomYear % 400 != 0) {
	// Not leap year
} else {
	// Is leap year
	console.log(randomYear)
}

How I would write the code
let randomYear = Math.floor(Math.random() * 10000)

if (randomYear % 4 == 0 && randomYear % 100 != 0 || randomYear % 400 == 0) {
	console.log(randomYear)
}

Logical Operators

You see some new operators in "How I would write the code": && and ||. These are called "Logical Operators" and they are used with boolean values normally.

&&

Returns true only if both booleans are true.

truefalse
truetruefalse
falsefalsefalse

||

Returns true if either of the booleans is true.

truefalse
truetruetrue
falsetruefalse

Example of their usage:

let c = true
let d = false

// Without using variables
true || false // true

// Using variables
c && c // true
c && d // false
d && c // false
d && d // false

c || c // true
c || d // true
d || c // true
d || d // false

for loops

Well, I would like to generate 10 random years and then check each of them but I am too lazy to write the code 10 times just to do that. This is where we utilise loop statements and the 1 we will be learning now is for loop.

for (let i = 0; i < 10; i++) {
	console.log(i)
}
// Output
/*
0
1
2
3
4
5
6
7
8
9
*/

Let's break down the for loop:

  • for (/* declare and initialise */; /* check */; /* increment */) is the general outline (Note the ; as they seperate the different parts)
  • let i = 0 creates a variable called 'i' with initial value of 0
  • i < 10 is the check the loop will execute at the start of every iteration
  • i++ increases i by 1 at the end of each iteration
  • { /* code to execute for each iteration */ }

The best way to understand for loops is to utilise the debugger. I won't show you how to use the debugger yet but I will show u how for loops work through it.

Flow:

  1. Declares variable i first
  2. Assign i with value 0
  3. Check if i less than 10
  4. 0 < 10 is true, proceed to body
  5. Log i in the console
  6. Increase i by 1
  7. Repeat step 3 to 6 another 9 times
  8. When i eventually becomes 10, i < 10 will be false, for loop breaks out

Hopefully you understand how for loops work now, at least the main parts.

We can also do a 'reverse' loop like so:

for (let i = 9; i >= 0; i--) {
	console.log(i)
}
// Output
/*
9
8
7
6
5
4
3
2
1
0
*/

We can also print a grid like so:

let grid = ''

// nested for loops to print 5 rows of 10 '*'
for (let i = 0; i < 5; i++) {
	// We use `j` for our inner `for` loop
	for (let j = 0; j < 10; j++) {
		grid += '*' // OR grid = grid + '*'
	}
	grid += '\n' // \n - new line 
}

console.log(grid)
// Output
/*
**********
**********
**********
**********
**********
*/

We can also print a pyramid like so:

let pyramid = '\n'
let rows = 5

for (let i = 0; i < rows; i++) {
	// spaces before the '*' for each row
	for (let j = 0; j < rows - 1 - i; j++) {
		pyramid += ' '
	}

	// the '*' pyramid
	for (let j = 0; j < 1 + i*2; j++) {
		pyramid += '*'
	}

	pyramid += '\n'
}

console.log(pyramid)
// Output
/*
    *
   ***
  *****
 *******
*********
*/

Incorporate for loop into the leap year check

Let's incorporate the for loop into the leap year check we did:

  1. Generate a random year
  2. Check if it is a leap year, if so log it
  3. Repeat this 10 times

Updated leap year checking
for (let i = 0; i < 10; i++) {
	let randomYear = Math.floor(Math.random() * 10000)

	if (randomYear % 4 == 0 && randomYear % 100 != 0 || randomYear % 400 == 0) {
		console.log(randomYear)
	}
}

Array

What is an 'Array'?. If you look up the english dictionary, specifically 'dictionary.com', it basically means a group or an arrangement. In Javascript context, and generally most computing concepts, 'Array' refers to a list of items. So in a rough sense, array is a collection. 'Array' and 'List' both mean collections but these terms have different meanings depending on the programming language or context they are used in, but I digress. All you need to know is these 2 terms exists and they both generally mean the same thing but are different.

That aside, let's look at an array in action.

let numbers = [1, 2, 3, 4, 5, 6]
console.log(numbers)
// Output
// (6) [1, 2, 3, 4, 5, 6]

If you execute the above code, you will see that the array get printed out. The (6) refers to the length of the array, then it shows the array itself.

We can also mix it up a little

let mixed = [1, 2, 3, 'four', 'five', 'six', true, false]
console.log(mixed)
// Output
// (8) [1, 2, 3, "four", "five", "six", true, false]

Javascript allows arrays to contain whatever, but you generally won't use mix arrays much (nearly never for me).

We can also create an empty array like so:

let a = []

But an empty array by itself is rather pointless, so let's add some items into it.

let a = []
a.push(1)
a.push(2)
a.push(3)
console.log(a)
// Output
// (3) [1, 2, 3]

As you can see, we have a push function to help us add an item to the array.

TIP

Did you know that the log in console.log() is also a function?

You probably subconsciously know that push adds the new item at the back of the array. What if we would like to add the new item at the front?

let a = []
a.unshift(1)
a.unshift(2)
a.unshift(3)
console.log(a)
// Output
// (3) [3, 2, 1]

What about adding an item in between rather than at the start or end.

let a = [1, 2, 3]
a.push(1)
console.log(a)
// Output
// (3) [1, 2, 3]
// let's add 4 in between 1 and 2
let a = [1, 2, 3]
a.splice(1, 0, 4) // (add at position `1`, remove 0 elements, item to add)
console.log(a)
// Output
// (4) [1, 4, 2, 3]

To clarify further, position 1 means this

array:    [1, 2, 3]
positions: 0  1  2

What this means is the the 1st item is position (index) 0, the 2nd item is index 1, so on and so forth. This is known as zero-based index. In normal situations we usually label the first item to have a position of 1 but in programming, the first item is most commonly index 0. I am not really sure why, but I am sure you can google about it and learn more.

So we just covered adding to an array, what about removing?

let a = [1, 2, 3, 4, 5, 6]

a.pop() // removes last item
console.log(a)
// (5) [1, 2, 3, 4, 5]

a.shift() // removes first item
console.log(a)
// (4) [2, 3, 4, 5]

a.splice(2, 1) // starting at index `2`, remove 1 element
console.log(a)
// (3) [2, 3, 5]

TIP

Want to know what input the splice function needs? Check out this page. Or just google something like 'mdn splice' (which is what I did). If you are not sure what you are looking at, just read the main content and just know these stuff exists. I know that is a rather unsatisfying solution but the knowledge will eventually link up and you will understand.

Well I went over functions to remove items from an array rather briefly but you probably got it right?

Now that we can add and remove, what about getting the nth index element?

let a = [1, 2, 3, 4, 5, 6]

console.log(a[0]) // get 1st element and log it
// 1

console.log(a[2]) // get 3rd element
// 3

console.log(a[a.length - 1]) // get last element and log it (minus 1 due to starting from 0)
// 6

// a.length is as it implys, it gives the length of the array

Let's incorporate array in the pyramid printing just to see an example usage! Do take some time to digest this piece of code. Look at the video below to see it in action.

let pyramidSizes = [3, 1, 5, 0, 10]

for (let i = 0; i < pyramidSizes.length; i++) {
	// Get the iteration's pyramid size
	let pyramidSize = pyramidSizes[i]
	let pyramid = ''

	for (let j = 0; j < pyramidSize; j++) {
		// spaces before the '*' for each row
		for (let k = 0; k < pyramidSize - 1 - j; k++) {
			pyramid += ' '
		}

		// the '*' pyramid
		for (let k = 0; k < 1 + j*2; k++) {
			pyramid += '*'
		}

		pyramid += '\n'
	}

	console.log(pyramid)
}

Mini Exercise 2: Reverse string

  1. Reverse a string. E.g. 'abc' to 'cba'

strings are essentially an array of characters. Javascript allows us to access a character using the [] operators. Try this mini exercise before looking at my answer.

Mini Exercise 2 Answer
let toBeReversed = '1234567890abc'
let reversed = ''

for (let i = toBeReversed.length - 1; i >= 0; i--) {
	reversed += toBeReversed[i]
}

console.log(reversed)
// cba0987654321

Mini Exercise 3: Ceasar Cipher

In cryptography, a Caesar cipher, also known as Caesar's cipher, the shift cipher, Caesar's code or Caesar shift, is one of the simplest and most widely known encryption techniques. It is a type of substitution cipher in which each letter in the plaintext is replaced by a letter some fixed number of positions down the alphabet. For example, with a left shift of 3, D would be replaced by A, E would become B, and so on. The method is named after Julius Caesar, who used it in his private correspondence. - Wikipedia

A simple illustration of this:

-Ceasar cipher with LEFT shift of 3-
Original string:  A B C D E F
                  | | | | | |
                  | | | | | |
                  | | | | | |
Encrypted string: X Y Z A B C

-Ceasar cipher with RIGHT shift of 3-
Original string:  A B C D E F
                  | | | | | |
                  | | | | | |
                  | | | | | |
Encrypted string: D E F G H I

This mini exercise will require you to:

  1. Implement Ceasar Cipher that only does RIGHT shift and only handle lowercase characters
  2. The cipher must be able to take in any integer (including negative)

Some test cases for you to check with:

1. Right shift 3 - 'the quick brown fox jumps over the lazy dog' -> 'wkh txlfn eurzq ira mxpsv ryhu wkh odcb grj'
2. Right shift 10 - 'the quick brown fox jumps over the lazy dog' -> 'dro aesmu lbygx pyh tewzc yfob dro vkji nyq'
3. Right shift 3000 - 'the quick brown fox jumps over the lazy dog' -> 'dro aesmu lbygx pyh tewzc yfob dro vkji nyq'

Wondering how you can obtain the corresponding character based on nth shifts? Well before we can go into that. We need to learn about 'Character codes'.

Here is a table of character that I painstakingly built:

Character CodeCharacter
32[space]
33!
34"
35#
36$
37%
38&
39'
40(
41)
42*
43+
44,
45-
46.
47/
480
491
502
513
524
535
546
557
568
579
58:
59;
60<
61=
62>
63?
64@
65A
66B
67C
68D
69E
70F
71G
72H
73I
74J
75K
76L
77M
78N
79O
80P
81Q
82R
83S
84T
85U
86V
87W
88X
89Y
90Z
91[
92\
93]
94^
95_
96`
97a
98b
99c
100d
101e
102f
103g
104h
105i
106j
107k
108l
109m
110n
111o
112p
113q
114r
115s
116t
117u
118v
119w
120x
121y
122z

TIP

Wondering what is before 32 and what is after 122? Well go google it yourself!

With this knowledge that characters are actually represented by numbers, we can actually use Javascript to convert characters to number and vice versa. Thus providing us a possible way to implement ceasar cipher. Don't see how this helps? Read on.

Given a string (of only lowercase alphabets), we will be able to get their character codes, for example 'abc' will give 97, 98, 99. If we want to do a right shift of 3, we can just add 3 to the numbers giving us 100, 101, 102 which then corresponds to 'def'. The functions that will help us are: charCodeAt and fromCharCode.

Example usage:

'a'.charCodeAt(0) // at index 0 of the string
// 97

String.fromCharCode(97)
// "a"

You see that the 2 functions are used from 2 different places. charCodeAt is a function that exists on all strings whereas fromCharCode is under the 'String' object (we will delve into objects soon). Which makes sense to separate it like so since fromCharCode function existing in all strings would not make sense (Getting characters from a character code when the string already has the characters like so 'a'.fromCharCode(97)? I think not).

With this knowledge, try to implement the ceasar cipher on your own.

Mini Exercise 3 Answer
let toBeCeasarCiphered = 'abcdefghijklmnopqrstuvwxyz'
let encryptedString = ''

let rightShift = 10

for (let i = 0; i < toBeCeasarCiphered.length; i++) {
	let charCode = toBeCeasarCiphered.charCodeAt(i)
	charCode += rightShift % 26 // for shifts bigger than 25

	if (charCode > 122) {
		charCode = charCode % 122 + 96 // for characters to wrap back to 'a'
	}

	encryptedString += String.fromCharCode(charCode)
}

console.log(encryptedString)
// defghijklmnopqrstuvwxyzabc

Functions

Time for you to learn how to create your own functions.

A function is essentially a group of code.

function a:
	code a
	code b
	code c

Everytime we call function a, code a, code b, code c will be done.

Pros of functions:

  • You get to reduce number of code written by reusing functions
  • Allows of abstraction and small modules/compartments/parts of codes to be grouped thus making the system easier to understand / work with

Cons of functions:

  • You need to write the function
  • Intricate processes are hidden away thus you may not know how it works unless you delve into the function

Example of a function:

// Create a function
function logSomeStuff() {
	console.log('a')
	console.log('b')
	console.log('c')
	console.log(1 + 1)
}

// Use the function
logSomeStuff()

/* Output
a
b
c
2
*/

From the above code, you can see that the function keyword is used to define/start a function. The name follows afterwards with the (). The () are for parameters, in this case there are none which is why it is empty. Following that is the body of the function encompassed by the {}.

We can also get functions to return a value to us.

function randomDigit() {
	return Math.floor(Math.random() * 10)
}

randomDigit()
// 4

TIP

Why randomDigit above gives 4: IEEE-vetted random number - RFC 1149.5

As you can see from our randomDigit function, the random digit is returned to us via the return keyword.

Let's go back to the 'Leap Year Check' we did previously (hopefully you still remember it). As we know functions are meant to group code together for reuse. In the 'Leap Year Check' scenario, we had to type out the code everytime we wanted to check a new random year. With functions, we can reduce the number of code we write.

leapYearCheck Function:

// year is the parameter of the leapYearCheck function
function leapYearCheck(year) {
	// We are return a boolean on whether the given year is a leap year or not
	return year % 4 == 0 && year % 100 != 0 || year % 400 == 0
}

leapYearCheck(2016)
// true

leapYearCheck(2017)
// false

leapYearCheck(1800)
// false

leapYearCheck(1600)
// true

With this function we can make the checking of the random years easier (kinda).

function leapYearCheck(year) {
	return year % 4 == 0 && year % 100 != 0 || year % 400 == 0
}

for (let i = 0; i < 10; i++) {
	let randomYear = Math.floor(Math.random() * 10000)

	if (leapYearCheck(randomYear)) {
		console.log(randomYear)
	}
}

Mini Exercise 4: Calculate Coin Change function

  1. Given an amount of money
  2. Return an array of coins

Coins that exists in our example: 1 cent, 5 cents, 10 cents, 20 cents, 50 cents, 1 dollar

This mini exercise will assume that we try to maximise the big coins as much as possible rather than just return all of them as 1 cent coins. So if we have to find $3 change in coins, the function will return [0, 0, 0, 0, 0, 3] rather than [200, 0, 0, 0, 0, 0].

Some test cases for you to use:

coinChange(200)
// (6) [0, 0, 0, 0, 0, 2]

coinChange(350)
// (6) [0, 0, 0, 0, 1, 3]

coinChange(10)
// (6) [0, 0, 1, 0, 0, 0]

coinChange(5)
// (6) [0, 1, 0, 0, 0, 0]

coinChange(1287)
// (6) [2, 1, 1, 1, 1, 12]
Mini Exercise 4 Answer
// `amount` is in cents
function coinChange(amount) {
	let oneDollars = Math.floor(amount / 100)

	// We take the remainder for calculating number of 50 cents
	amount %= 100 // same as amount = amount % 100
	let fiftyCents = Math.floor(amount / 50)

	amount %= 50
	let twentyCents = Math.floor(amount / 20)

	amount %= 20
	let tenCents = Math.floor(amount / 10)

	amount %= 10
	let fiveCents = Math.floor(amount / 5)

	amount %= 5
	let oneCents = amount

	return [oneCents, fiveCents, tenCents, twentyCents, fiftyCents, oneDollars]
}

TIP

Did you manage to do this exercise? I hope you did.

Did you do it roughly the same way I did it? If you didn't, I hope you understand my answer.

Object: What it is

You might want to skip this part and move on to Object: Using it as this part delves a bit too deep for beginners. If you choose to read this part, well, just know that you are probably missing some extra knowledge that allows me to explain object.

We will now learn about objects. Actually we have been using objects this whole time. 'Almost everything in Javascript is an Object' - Someone. That phrase is true.

Let's use the typeof keyword to see what some types there are

typeof(console)
// "object"

typeof([])
// "object"

typeof('')
// "string"

typeof(10)
// "number"

typeof(3.14159)
// "number"

typeof(console.log)
// "function"

That doesn't seem like almost everything is an object? Well, before I show you why almost everything is an object, we need to know about 'prototypical inheritance'. What is prototypical inheritance? Well, we need to understand the concept of 'inheritance' first.

Inheritance, in terms of programming, means something along the lines of

...inheritance enables new objects to take on the properties of existing objects...'

We can use an analogy with fruits to help better understand.

  • Apple is a fruit.
  • Orange is a fruit.
  • Apple's 'parent' is a 'Fruit'.
  • Orange's 'parent' is 'Fruit'.

  • Apple and Orange are not the same despite having the same 'parent'.
  • Apple is red while Orange is orange.
  • However, Apple and Orange can be considered 'siblings'.

  • If we were to introduce a new fruit, Pear, it would be a fruit with a green color.

  • The similarities between Apple, Orange, and Pear is that they are all able to be grown and eaten.
  • Thus, 'Fruits' are able to be grown and eaten.
  • 'Is Growable' and 'Is Edible' are properties of 'Fruit'.
  • When something is a child of 'Fruit', it inherits such properties and becomes 'Growable' and 'Edible'.

Similarly, in the case of console, console is an object, which means it would have inherited properties of object.

So what is object? Let's create an object and take a look at it.

let someObject = {} // `{}` is an object

typeof(someObject)
// "object"

typeof({})
// "object"

// in the console type the following:
someObject.__proto__ // stands for prototype

You should see an object like this: __proto__

constructor - the function used to 'construct' the object. In this case it is the function Object (kinda confusing but note the case sensitivity). toString - a function that exists on all objects, this function converts the object into a string representation.

From the above image, we can see that someObject's prototype is actually Object's prototype. So what is prototype? It is a part of an object that contains properties to be 'inherited' by the object's child objects. Thus, from the above image, we can see that every object will have that exact 'prototype'.

Let's take a look at 'String'.

String's prototype chain:

''.__proto__ gives the 'String' prototype. __proto__

''.__proto__.__proto__ get the __proto__'s proto which is the 'Object' prototype. __proto__

Number's prototype chain:

let aNumber = 0

aNumber.__proto__
// Returns a 'Number' prototype

aNumber.__proto__.__proto__
// Returns the 'Number' prototype's prototype which is also the 'Object' prototype

Object: Using it

If you didn't read the above part or you read it but didn't understand, WELL, just know that objects hold data. Similar to an Array holding data, objects also hold data.

// Objects can be anything
let blankObject = {}

blankObject
// {}

let randomObject = {
	name: 'Whatever', // note the comma
	width: 10,
	height: 20
}

randomObject.name
// "Whatever"

randomObject.width
// 10

randomObject.height
// 20

randomObject.name = 'some other name'

randomObject.name
// "some other name"

// We can add in a new property like so
randomObject.abc = 'def'

randomObject.abc
// "def"

randomObject
/*
{
	abc: "def",
	height: 20,
	name: "some other name",
	width: 10,
	__proto__: Object
}
*/

// objects can hold anything
// including other objects

randomObject.innerObject = {}

randomObject.innerObject.a = 1
randomObject.innerObject.b = 'something'

randomObject
/*
{
	abc: "def",
	height: 20,
	innerObject: { a: 1, b: 'something' },
	name: "some other name",
	width: 10,
	__proto__: Object
}
*/

You get the idea that object is literally whatever data you want to keep in it.

Let's use objects in the generation of the pyramid as an example.

// Convert the pyramid generator to a function for easy reuse

// rows - number of rows for the pyramid
// char - the character used to make the pyramid
function generatePyramid(rows, char) {
	let pyramid = ''

	for (let j = 0; j < rows; j++) {
		// spaces before the '*' for each row
		for (let k = 0; k < rows - 1 - j; k++) {
			pyramid += ' '
		}

		// the '*' pyramid
		for (let k = 0; k < 1 + j*2; k++) {
			pyramid += char
		}

		pyramid += '\n'
	}

	// We return the pyramid string instead of console.log
	return pyramid
}

// test the function
console.log(generatePyramid(5, '$'))
/*
    $
   $$$
  $$$$$
 $$$$$$$
$$$$$$$$$
*/

// I want to use an array of objects to generate a bunch of different pyramids
let pyramidSettings = [
	{
		rows: 5,
		char: '$'
	},
	{
		rows: 3,
		char: '0'
	},
	{
		rows: 8,
		char: 'l'
	}
]

for (let i = 0; i < pyramidSettings.length; i++) {
	// Get the current iteration's pyramid setting
	let pyramidSetting = pyramidSettings[i]
	
	let pyramid = generatePyramid(pyramidSetting.rows, pyramidSetting.char)

	console.log(pyramid)
}

/*
	$
   $$$
  $$$$$
 $$$$$$$
$$$$$$$$$

  0
 000
00000

       l
      lll
     lllll
    lllllll
   lllllllll
  lllllllllll
 lllllllllllll
lllllllllllllll
*/

Mini Exercise 5: Filter and Sort People

Now we will be learning about filtering and sorting with Javascript. You know how when you google something, google is actually filtering away the irrelevant results and then sorting the remaining base on how relevant they are? We aren't going to do that crazily complex filter and sort, what we will do are the basics, naive way of filtering and sorting.

  1. You are given an Array of person object
  2. Person object contains:
    • Name
    • Gender
    • Age
  3. You will create filter functions:
    • filterByName(people, query)
      • The criteria is if the person's name contains the query
      • E.g. query is 'o', the people who fit this criteria are:
        • John
        • Bobby
        • Chloe
        • ...
      • Google 'javascript string contains' and check out the answers in 'stackoverflow' to learn how to check if a string is in a string. OR Look at the answer below.
    • filterByGender(people, gender)
    • filterByAge(people, fromAge, toAge)
  4. You will create sort functions:
    • sortByName(people, isAsc)
      • Alphabetical order
        • Ascending: aa, ab, ac, ad, bb, bc, bd
        • Descending: bd, bc, bb, ad, ac, ab, aa
    • sortByGender(people, isAsc)
      • Alphabetical order
        • Ascending: f, m
        • Descending: m, f
    • sortByAge(people, isAsc)
      • Numerical order
        • Ascending: 20, 23, 25, 30, 35
        • Descending: 35, 30, 25, 23, 20
  5. Your functions cannot change the original array

TIP

I have given you the function names and their expected parameters.

Note that you are suppose to pass the people array into the people parameter.

query - the string to filter name by

gender - the string to filter gender by

fromAge - the starting age (inclusive)

toAge - the ending age (inclusive)

isAsc - boolean for if it is ascending order or not (otherwise descending)

The people you will be working with

let people = [
	{
		name: 'John',
		gender: 'm',
		age: 30
	},
	{
		name: 'Rick',
		gender: 'm',
		age: 23
	},
	{
		name: 'Jessica',
		gender: 'f',
		age: 26
	},
	{
		name: 'Bobby',
		gender: 'm',
		age: 45
	},
	{
		name: 'Chloe',
		gender: 'f',
		age: 34
	},
	{
		name: 'Kai',
		gender: 'm',
		age: 19
	},
	{
		name: 'Hernandez',
		gender: 'm',
		age: 26
	},
	{
		name: 'Mary',
		gender: 'f',
		age: 23
	},
	{
		name: 'Pauline',
		gender: 'f',
		age: 50
	},
]

TIP

for sorting arrays, you should use the sort function

Filter Functions Guide

  1. Prepare an empty array to contain the people that meet the filter criteria
  2. Iterate (for loop) the people array
  3. For each person in the the array, check if they meet the criteria
  4. If the person does meet the criteria, add them to the new array
  5. After iterating through the people array, return the filtered array

Sort Functions Guide

  1. You will need to make a 'copy' of the people array (google 'javascript make copy of array')
  2. Using the built in sort function, you can sort the copied array
  3. return the sorted array
Mini Exercise 5 Answers

filterByName

function filterByName(people, query) {
	let filteredPeople = []

	for (let i = 0; i < people.length; i++) {
		let person = people[i]

		if (person.name.indexOf(query) > -1) { // OR .includes for ES6 // What is ES? go google 'javascript es6'
			filteredPeople.push(person) // remember how to add to an array?
		}
	}

	return filteredPeople
}

filterByName(people, 'o')

/*
(3) [{...}, {...}, {...}]
 > 0: {name: "John", gender: "m", age: 30}
 > 1: {name: "Bobby", gender: "m", age: 45}
 > 2: {name: "Chloe", gender: "f", age: 34}
 length: 3
 >__proto__: Array(0)
*/

filterByGender

function filterByGender(people, gender) {
	let filteredPeople = []

	for (let i = 0; i < people.length; i++) {
		let person = people[i]

		if (person.gender == gender) {
			filteredPeople.push(person)
		}
	}

	return filteredPeople
}

filterByGender(people, 'm')

/*
(5) [{...}, {...}, {...}, {...}, {...}]
 > 0: {name: "John", gender: "m", age: 30}
 > 1: {name: "Rick", gender: "m", age: 23}
 > 2: {name: "Bobby", gender: "m", age: 45}
 > 3: {name: "Kai", gender: "m", age: 19}
 > 4: {name: "Hernandez", gender: "m", age: 26}
 length: 5
 > __proto__: Array(0)
*/

filterByAge

function filterByAge(people, fromAge, toAge) {
	let filteredPeople = []

	for (let i = 0; i < people.length; i++) {
		let person = people[i]

		// Remember how to combine boolean expressions?
		if (person.age >= fromAge && person.age <= toAge) {
			filteredPeople.push(person)
		}
	}

	return filteredPeople
}

filterByAge(people, 20, 30)

/*
(5) [{...}, {...}, {...}, {...}, {...}]
 > 0: {name: "John", gender: "m", age: 30}
 > 1: {name: "Rick", gender: "m", age: 23}
 > 2: {name: "Jessica", gender: "f", age: 26}
 > 3: {name: "Hernandez", gender: "m", age: 26}
 > 4: {name: "Mary", gender: "f", age: 23}
 length: 5
 > __proto__: Array(0)
*/

sortByName

function sortByName(people, isAsc) {
	let copiedPeople = people.slice()

	if (isAsc) {
		// Woah a function declaration in a function call in a function declaration?
		// If you haven't already googled 'javascript array sort' and read up in 
		// mozzila developer network or some other similar website regarding this 
		// function... Maybe go google it and read up?
		copiedPeople.sort(function (person1, person2) {

			// Some strings can be 'more' than other strings
			// Remember the character code? Character codes are numbers, so the string
			// can be compared via the character codes

			if (person1.name < person2.name) {
				return -1
			} else if (person1.name > person2.name) {
				return 1
			}
			return 0
		})
	} else {
		copiedPeople.sort(function (person1, person2) {
			// swap the `1` and `-1`
			if (person1.name < person2.name) {
				return 1
			} else if (person1.name > person2.name) {
				return -1
			}
			return 0
		})
	}

	return copiedPeople
}

sortByName(people, true)
/*
(9) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
 > 0: {name: "Bobby", gender: "m", age: 45}
 > 1: {name: "Chloe", gender: "f", age: 34}
 > 2: {name: "Hernandez", gender: "m", age: 26}
 > 3: {name: "Jessica", gender: "f", age: 26}
 > 4: {name: "John", gender: "m", age: 30}
 > 5: {name: "Kai", gender: "m", age: 19}
 > 6: {name: "Mary", gender: "f", age: 23}
 > 7: {name: "Pauline", gender: "f", age: 50}
 > 8: {name: "Rick", gender: "m", age: 23}
 length: 9
 > __proto__: Array(0)
*/

sortByGender

function sortByGender(people, isAsc) {
	let copiedPeople = people.slice()

	if (isAsc) {
		copiedPeople.sort(function (person1, person2) {
			if (person1.gender < person2.gender) {
				return -1
			} else if (person1.gender > person2.gender) {
				return 1
			}
			return 0
		})
	} else {
		copiedPeople.sort(function (person1, person2) {
			// swap the `1` and `-1`
			if (person1.gender < person2.gender) {
				return 1
			} else if (person1.gender > person2.gender) {
				return -1
			}
			return 0
		})
	}

	return copiedPeople
}

sortByGender(people, true)
/*
(9) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
 > 0: {name: "Jessica", gender: "f", age: 26}
 > 1: {name: "Chloe", gender: "f", age: 34}
 > 2: {name: "Mary", gender: "f", age: 23}
 > 3: {name: "Pauline", gender: "f", age: 50}
 > 4: {name: "John", gender: "m", age: 30}
 > 5: {name: "Rick", gender: "m", age: 23}
 > 6: {name: "Bobby", gender: "m", age: 45}
 > 7: {name: "Kai", gender: "m", age: 19}
 > 8: {name: "Hernandez", gender: "m", age: 26}
 length: 9
 > __proto__: Array(0)
*/

sortByAge

function sortByAge(people, isAsc) {
	let copiedPeople = people.slice()

	if (isAsc) {
		copiedPeople.sort(function (person1, person2) {
			return person1.age - person2.age
		})
	} else {
		copiedPeople.sort(function (person1, person2) {
			return person2.age - person1.age
		})
	}

	return copiedPeople
}

sortByAge(people, false)
/*
(9) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
 > 0: {name: "Pauline", gender: "f", age: 50}
 > 1: {name: "Bobby", gender: "m", age: 45}
 > 2: {name: "Chloe", gender: "f", age: 34}
 > 3: {name: "John", gender: "m", age: 30}
 > 4: {name: "Jessica", gender: "f", age: 26}
 > 5: {name: "Hernandez", gender: "m", age: 26}
 > 6: {name: "Rick", gender: "m", age: 23}
 > 7: {name: "Mary", gender: "f", age: 23}
 > 8: {name: "Kai", gender: "m", age: 19}
 length: 9
 > __proto__: Array(0)
*/