DEV Community

Michael Otu
Michael Otu

Posted on

JavaScript Essentials: Part 4

Previously in JavaScript Essentials: Part 3, we discussed quite a lot about objects and arrays and their methods for data manipulations. In this part, we will look at:

Destructuring

We can destructure an array and an object. The idea of destructuring has something to do with "breaking down" a value into various parts. It has to do with assignments.

Let's consider an array. We know the first item in the array is at index 0. When we want to assign the first element in the array to a variable, usually we'd do, variable = array[0].

Example

const numbers = [1, 2, 3];

const [firstElement, secondElement, thirdElement] = number;

console.log(firstElement);
console.log(secondElement);
console.log(thirdElement);
Enter fullscreen mode Exit fullscreen mode

We positioned the variables in the same manner as the values in the array. So in a way, it is as if we are creating an array. The above would have been:

const numbers = [1, 2, 3];

const firstElement = numbers[0],
  secondElement = numbers[1],
  thirdElement = numbers[2];

// the variables could have had their own `const` keyword on different lines

console.log(firstElement);
console.log(secondElement);
console.log(thirdElement);
Enter fullscreen mode Exit fullscreen mode

Now, let's consider an object. When we want a value from the object, we'd usually do, variable = object.property.

// we want the first and last name

const firstName = profile.firstName;
const lastName = profile.lastName;

console.log(`Full name: ${firstName} ${lastName}`);
Enter fullscreen mode Exit fullscreen mode

We can extract the first and last names only.

const profile = {
  firstName: "John",
  lastName: "Doe",
  job: "Debugger",
  isBald: false,
  numberOfPets: 3,
};

const { firstName, lastName } = profile;

console.log(`Full name: ${firstName} ${lastName}`);
Enter fullscreen mode Exit fullscreen mode

We provide an alias name for the property names specified in the object as const { property: aliasName } = object

const { firstName: anotherVarForFirstName, lastName } = profile;

console.log(`Full name: ${anotherVarForFirstName} ${lastName}`);
Enter fullscreen mode Exit fullscreen mode

Rest

Rest in JavaScript is the same as destructuring an array or object. In the array example, how would you extract the first element and not bother about the "rest"? We could use indexing. True. Then what about getting the rest of the data and not the first?

const numbers = [1, 2, 3];

// destructure the first and the rest of the elements
const [firstElement, ...theRestOfTheElements] = numbers;

console.log(firstElement);
// 1
console.log(theRestOfTheElements);
// [ 2, 3 ]
Enter fullscreen mode Exit fullscreen mode

We can do the same for an object.

const profile = {
  firstName: "John",
  lastName: "Doe",
  job: "Debugger",
  isBald: false,
  numberOfPets: 3,
};

const { firstName, ...restOfTheProperties } = profile;

console.log(firstName);
// John
console.log(restOfTheProperties);
// { lastName: 'Doe', job: 'Debugger', isBald: false, numberOfPets: 3 }
Enter fullscreen mode Exit fullscreen mode

Know that when destructuring using the rest approach, the rest variable must be the last in the destructuring array.

Spreading

Let's try this out. I want you to play with it and let me know what you think. Create an array variable and assign some values to it. Create another array and assign it to the previous array variable. Modify one of the values in the first array. Print out both arrays. What did you notice? Try the process with two objects. You really have to try it out else, you won't know first-hand what I am talking about and how devastating it could be.

// we have the original array
const firstArray = [1, 3];

// we assign a reference (not a copy of the original to another)
const secondArray = firstArray;

// we update the first element in the original array
firstArray[0] = 5;

// log the content of both arrays
console.log({ firstArray, secondArray });
// { firstArray: [ 5, 3 ], secondArray: [ 5, 3 ] }

// we have to copy the original and assign the value to the
// new array or use spreading
const thirdArray = [...firstArray];

// alter the 2nd element in the original array
firstArray[1] = -1;

// log the content of all the arrays
console.log({ firstArray, secondArray, thirdArray });
// { firstArray: [ 5, -1 ], secondArray: [ 5, -1 ], thirdArray: [ 5, 3 ] }
Enter fullscreen mode Exit fullscreen mode

Does, ...firstArray look familiar? It is called spreading here and not rest. Well, it solves the "copying" issue with arrays. It can be used to combine several arrays or objects into one.

const personal = {
  firstName: "John",
  lastName: "Doe",
};

const physical = {
  isBald: false,
  hasFatBelly: true,
};

const employment = {
  job: "Debugger",
  salary: 257000,
};

const emotional = {
  isHappy: true,
};

const profile = { ...personal, physical, employment, emotional };
Enter fullscreen mode Exit fullscreen mode

Operators

We discussed the mathematical operators previously in JavaScript Essentials: Part 1 under the Calculator section. We will expand on that topic here.

Arithmetic Operators

Arithmetic operators are binary operators. This means they operate on two values.

Operator Description Example
+ Addition a + b
- Subtraction a - b
* Multiplication a * b
/ Division a / b
% Modulus (remainder) a % b
** Exponentiation a ** b
// adding numbers with the plus
console.log(3 + 3); // answer = 6
console.log(1 + 2 + 4); // answer = 7

// subtraction with dash
console.log(6 - 3); // answer = 3
console.log(-16 - 3); // answer = -19

// multiplication with asterisk
console.log(5 * 3); // answer = 15
console.log(30 * 15); // answer = 450

// division with forward slash
console.log(30 / 5); // answer = 6
console.log(12.25 / 0.5); // answer = 24.5

// modulo (is the remainder after division is done)
// with the percentage sign (%)
console.log(5 % 2); // answer = 1
console.log(2 % 5); // answer = 2

// exponent with two asterisks (**)
console.log(5 ** 2); // answer = 5 * 5 = 25
Enter fullscreen mode Exit fullscreen mode

Assignment Operators

Operator Description Example
= Assignment a = b
+= Addition assignment a += b
-= Subtraction assignment a -= b
*= Multiplication assignment a *= b
/= Division assignment a /= b
%= Modulus assignment a %= b
**= Exponentiation assignment a **= b
// assignment
let a = 10;
let b = 4;
console.log({ a, b });

// addition assignment
// a += b is the same as a = a + b
a += b;
console.log({ a, b });

// subtraction assignment
// a -= b is the same as a = a - b
a -= b;
console.log({ a, b });

// try your the rest out
Enter fullscreen mode Exit fullscreen mode

Comparison Operators
Comparison operators evaluate to a boolean.

Operator Description Example
== Equal to a == b
!= Not equal to a != b
=== Strictly equal to a === b
!== Strictly not equal to a !== b
> Greater than a > b
< Less than a < b
>= Greater than or equal to a >= b
<= Less than or equal to a <= b
const a = 10;
const b = 4;

// equal to
console.log(`${a} is Equal to ${b} is, ${a == b}`);
console.log(`${a} is Strictly Equal to is, ${b} ${a === b}`);
Enter fullscreen mode Exit fullscreen mode

= is different from == and ===. The single equal to sign (symbol) is the assignment operator. It is used when "putting" values into a variable.

// it will be in your best interest to stick to === instead of ==
const strTwo = "2";
const intTwo = 2;

// is "2" the same as 2???
// the answer is yes and no
// javascript is javascript
// yes because the values (look) are the same... they are all 'two'
// however, strictly speaking, the two values are of different types
// strTwo is a string and intTwo is a number so if we are going to compare them,
// we have to be strict

console.log(`'${strTwo}' is Equal to ${intTwo} is, ${strTwo == intTwo}`);
console.log(
  `'${strTwo}' is Strictly Equal to is, ${intTwo} ${strTwo === intTwo}`
);
// does this give you some funny ideas to check out??
Enter fullscreen mode Exit fullscreen mode

! is a logical operator which we will discuss shortly. ! means not or negation. So, != or !== is not equal to or not strictly equal to respectively. They are the negations. So in the case that a condition is supposed to be true, it becomes false and false when true. You can say that the !, not operator flips (negates) the truthfulness of a condition.

Logical Operators

Operator Description Example
&& Logical and a && b
\ \
! Logical not !a

The Logical not as mentioned above negates a truth value.

a !a result
true !true false
false !false true

The logical and evaluates to true when both values are true or else false.

a b a && b
true true true
true false false
false true false
false false false

The logical or evaluates to true when at least one of the values is true.

| a | b | a || b |
| :---: | :---: | :------: |
| true | true | true |
| true | false | true |
| false | true | true |
| false | false | false |
| | | |

Unary Operators

These are operators that work on one value.

Operator Description Example
+ Unary plus +a
- Unary minus -a
++ Increment a++
-- Decrement a--
typeof Type of typeof a

++ and -- are the increment and decrement operators. They operate on the value and assign the result to the same variable.

// when the game starts, set the life and power to the default
let attackPower = 0;
let playerLife = 5;
console.log({ playerLife, attackPower });
// { playerLife: 5, attackPower: 0 }

// when the player picks a bullet, increase the attack power
attackPower++;
// same as attackPower += 1
console.log({ attackPower });
// { attackPower: 1 }

// when the player gets shot, decrease the player's life
playerLife--;
// same as playerLife -= 1
console.log({ playerLife });
// { playerLife: 4 }
Enter fullscreen mode Exit fullscreen mode

JavaScript Operator Precedence

Computations with the operators are done in a certain order. This is known as operator precedence.

  • Parentheses () - Evaluate expressions inside parentheses first.
  • Exponentiation ** - Right-to-left.
  • Unary +, -, !, ++, --, typeof - Right-to-left.
  • Multiplication *, /, % - Left-to-right.
  • Addition +, - - Left-to-right.
  • Relational <, >, <=, >= - Left-to-right.
  • Equality ==, !=, ===, !== - Left-to-right.
  • Logical AND && - Left-to-right.
  • Logical OR || - Left-to-right.
  • Conditional ?: - Right-to-left.
  • Assignment =, +=, -=, *=, /=, %= , ... - Right-to-left.

Control structures (if statements, loops)

Control structures are constructs used to alter the flow of data. They can change how the data flows, either to repeat some action for a determined number of times or perform some actions based on some conditions.

If and else statement

The if and else statement takes the form.

if (/* some condition */) {
  // do some thing if the condition mentioned is true
} else {
  // do some thing else when the condition doesn't hold
}
Enter fullscreen mode Exit fullscreen mode

The "some condition" referred to, is a boolean (conditional) expression. This or these expressions would evaluate to a truth value. When the resultant value is true, the body of the if block is executed. If not, then the body of the else is executed. The body (block) is found within the { and }.

if and else can not be used as variable names. They are keywords.

Consider the snippet below:

let pay = 30;
const RATE = 0.05;
const didOverTime = true;

// if the employee did overtime
if (didOverTime) {
  pay = pay + pay * RATE;
}

console.log(`Total take home: ${pay}`);
Enter fullscreen mode Exit fullscreen mode

The pay is increased by some rate when the employee does overtime. What happens if the didOverTime is false? Try it out. Set the didOverTime to false.

Now, we can choose to do something else when the employee doesn't do overtime. We can be the wicked employer and make a profit by reducing the employee's pay. We can do this by adding some code to the else block.

let pay = 30;
const RATE = 0.05;
const didOverTime = true;

// if the employee did overtime
if (didOverTime) {
  pay = pay + pay * RATE;
} else {
  pay = pay - pay * RATE;
}

console.log(`Total take home: ${pay}`);
Enter fullscreen mode Exit fullscreen mode

We can rewrite this snippet in a simple way, improving it.

let pay = 30;
const RATE = 0.05;
const didOverTime = true;

let payChange = pay * RATE;

if (didOverTime) {
  pay += payChange;
} else {
  pay -= payChange;
}

console.log(`Total take home: ${pay}`);
Enter fullscreen mode Exit fullscreen mode

We introduced a new variable, payChange, which holds the amount to be added or deducted from the employee's pay based on the state (value) of the didOverTime.

It is not compulsory to always add the else block. You can smartly write your program so that you will not need to add an else block. Know that there are cases that this works well and there are cases that it doesn't. You need to be calculative here.

Let's look at the FizzBuzz program. So, the fizz buzz is a program that say:

  • "fizz" when a value is a multiple of 3
  • "buzz" when a value is a multiple of 5
  • "fizzbuzz" when a value is a multiple of 3 and 5

The idea here is to demonstrate that we can change the if and else statements to have the else if statement.

In this program, we would use these operators === and %. === is to check if the values are equal to and % for the remainder.

This is a pseudocode.

if the given number is a multiple of 3
 print "fizz"
else if the given number is a multiple of 5
 print "buzz"
else if the given number is a multiple of 3 and 5
 print "fizzbuzz"
Enter fullscreen mode Exit fullscreen mode

Try it. Write the fizzbuzz program using the hints left in the above pseudocode. Try your solution with the given value as, 3, 6, 10, 15. You'd have a problem. Most certainly. The solution is to rearrange the if statements. I hope this helps you resolve the problem.

It is helpful to think in pseudocode when you are having a hard time grasping how to implement a solution. Pseudocode is more a less how you are thinking about the approach to the solution rather than the code to solve the problem. It is like writing down what you are thinking about when brainstorming.

Nested if and else statements

Well, everything is feasible. We can nest an if and else statements in another if and else statement. It is fun and not fun sometimes.

if (condition 1 is true) {
 if (condition 2 and condition 3 are true) {
  do something
 } else {
    do something
 }
} else {
 do something
}

Enter fullscreen mode Exit fullscreen mode

Be creative and create a nested nested if and else statements. Frankly, I am not fun of nesting the if and else statements. So I find another way to do it. We will discuss short-circuiting in the future.

Ternary operator

The ternary operator is a one-line if and else statement. It is devoid of complex logic that would span more than a line. We will modify the two if and else statements above. With the ternary operator, we reduce the if and else block to an inline expression.

variable = condition ? true body : false body;
Enter fullscreen mode Exit fullscreen mode

The condition is a boolean expression. true body is what happens when the condition resolves to true and the false body, when false.

let pay = 30;
const RATE = 0.05;
const didOverTime = true;

// if (didOverTime) {
//   pay = pay + pay * RATE;
// } else {
//   pay = pay - pay * RATE;
// }

// using ternary
pay = didOverTime ? pay + pay * RATE : pay - pay * RATE;
// this reads as, if didOverTime, pay = pay + pay * RATE, else pay = pay - pay * RATE
console.log(`Total take home: ${pay}`);
// Total take home: 31.5
Enter fullscreen mode Exit fullscreen mode

Use the ternary operator for the second example.

It is cool to be smart in programming but there are times that smartness can be dangerous not just to you but also to the company and team. So be smart and wise. The fact that it is feasible doesn't mean doing it.

Switch statement

There is another conditional statement known as the switch statement. Usually, it is preferred a chain of if and else statements. The basic form of a switch statement is:

switch someValue {
 case someValue is thisValueA:
  do something
  break;
 case someValue is thisValueB:
  do something
  break;
 ...
 default:
  do something by default if none of these values matches the someValue
}
Enter fullscreen mode Exit fullscreen mode

The ... means a bunch of other cases.

The above is the same as:

if (someValue is thisValueA) {
 do something
} else if (someValue is thisValueB) {
 do something
}
...
else {
 do something by default if none of these values matches the someValue
}
Enter fullscreen mode Exit fullscreen mode

... is a bunch of else if statements. And it is for this reason that we'd use a switch in place of if and else statements.

Here is an example of a switch statement

const day = "Friday";

switch (day) {
  case "Monday":
    console.log("Today is Monday");
    break;
  case "Tuesday":
    console.log("Today is Tuesday");
    break;
  case "Wednesday":
    console.log("Today is Wednesday");
    break;
  default:
    console.log("Unknown day");
}
Enter fullscreen mode Exit fullscreen mode

What do you think is the output? Rewrite the above switch statement program, using if and else.

The break keyword jumps (moves) the execution (data) flow out of the switch statement. What happens when you don't put a break? Try it out.

switch, case and break are Javascript keywords so don't use them as variable names.

For loop

It is usually the case that we replay our favourite song over and over again. We put the song in a loop. The song is repeatedly played. This same idea applies to loops in programming. One of the looping contrast in JavaScript is the for loop. for is a keyword so don't use it as a variable. At this point, when you hear something is a keyword, it means don't use it as a variable name.

The fundamental reason to use a looping statement is to execute some logic repeatedly. This can be a finite number of times or based on a condition. For loop is usually used when the number of repetitions needed is known (finite).

We can use the loops to:

  • go over (iterate) an array or a string. Eg: find the number of characters in a string array
  • execute some logic for some known number of times. Eg: console log "Hello world" 10 times

We would be looking at three kinds of for loops here.

  • Traditional for loop which is of the form
  for (init; condition; step) {
    // some logic
  }
Enter fullscreen mode Exit fullscreen mode
  • init tells you where the loop starts
  • condition is a boolean expression that indicates when the loop should be terminated (stopped). The body of the loop gets executed as far as the condition holds
  • step indicates how the looping condition is influenced. Sometimes it is an increment and at times it's a decrement.

Example

  // console log numbers between 0 and 10
  for (let loopingNumber = 0; loopingNumber <= 10; loopingNumber++) {
    console.log(loopingNumber);
  }
Enter fullscreen mode Exit fullscreen mode
  • For this example that we have for the for loop and in the header of the for loop, we set the initial value of the loopingNumber to 0.
  • Then the condition is that, as far as the loopingNumber is less than or equal to 10, execute the body of the for loop.
  • The loopingNumber is then incremented as the next step in this case. loopingNumber++ is the same as loopingNumber += 1 or loopingNumber = loopingNumber + 1.
  • So as far as the loopingNumber is less than 10, the condition holds and the console.log(loopingNumber); is executed.

Usually in the condition part, the comparison operators are used there. What happens when we use < instead of <=? Try it out. Be curious.

Example

  // let's loop through the array and print out the number of characters in it
  const daysOfTheWeek = [
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
    "Sunday",
  ];

  for (let index = 0; index < daysOfTheWeek.length; index += 1) {
    console.log(
      `${daysOfTheWeek[index]} at index ${index} has ${daysOfTheWeek[index].length} characters`
    );
  }
  // Monday at index 0 has 6 characters
  // Tuesday at index 1 has 7 characters
  // Wednesday at index 2 has 9 characters
  // Thursday at index 3 has 8 characters
  // Friday at index 4 has 6 characters
  // Saturday at index 5 has 8 characters
  // Sunday at index 6 has 6 characters
Enter fullscreen mode Exit fullscreen mode
  • Since we wanted to start from the first element in the array, we set the index variable to 0 knowing that array indexing starts at 0 in Javascript
  • We can alter the initial value of index to start from another element.
  • In the condition, we check if the index is less than the array size, daysOfTheWeek.length

    • For-In Loop is of the form
  for (variable in object) {
    // some logic
  }
Enter fullscreen mode Exit fullscreen mode

The for in loop is used on arrays (anything that can be iterated) and objects. The variable, in the case of an array-like value, is the index and for an object is the key.

Let's rewrite the above for loop, using for in loop.

  const daysOfTheWeek = [
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
    "Sunday",
  ];

  for (const index in daysOfTheWeek) {
    console.log(
      `${daysOfTheWeek[index]} at index ${index} has ${daysOfTheWeek[index].length} characters`
    );
  }
  // Monday at index 0 has 6 characters
  // Tuesday at index 1 has 7 characters
  // Wednesday at index 2 has 9 characters
  // Thursday at index 3 has 8 characters
  // Friday at index 4 has 6 characters
  // Saturday at index 5 has 8 characters
  // Sunday at index 6 has 6 characters
Enter fullscreen mode Exit fullscreen mode

Let's implement one for an object.

  const profile = {
    firstName: "John",
    lastName: "Doe",
    job: "Debugger",
    isBald: false,
    numberOfPets: 3,
  };

  for (const key in profile) {
    console.log(`${key} points to, ${profile[key]}`);
  }
  // firstName points to, John
  // lastName points to, Doe
  // job points to, Debugger
  // isBald points to, false
  // numberOfPets points to, 3
Enter fullscreen mode Exit fullscreen mode
  • For-Of Loop is of the form
  for (variable of collection) {
    // some logic
  }
Enter fullscreen mode Exit fullscreen mode

The for of loop is used on collections, iterables, like an array, strings, etc. The variable, in this case, points to the element itself.

Let's rewrite the above for loop, using for of loop.

  for (const element of daysOfTheWeek) {
    console.log(
      `${element} at index ${daysOfTheWeek.indexOf(element)} has ${
        element.length
      } characters`
    );
  }
  // Monday at index 0 has 6 characters
  // Tuesday at index 1 has 7 characters
  // Wednesday at index 2 has 9 characters
  // Thursday at index 3 has 8 characters
  // Friday at index 4 has 6 characters
  // Saturday at index 5 has 8 characters
  // Sunday at index 6 has 6 characters
Enter fullscreen mode Exit fullscreen mode

This will not work on an object because an object is not an iterable. If you want to do this on an object, you'd have to manipulate it. Object.keys(yourObject) or Object.values(yourObject) to get the keys or values as an array.

For the last example of loops, let's look into the past. One of the validation rules for an email was to have a single '@' sign. So we'd write a program that counts the number of '@' signs in an email. The idea will be the same for a list of emails so I will go with the list of emails and also use that as an opportunity to use nested for loops.

Example

const emailList = [
  "johndoes@email.com",
  "pancake@email@ny.com",
  "tenya123@@email@ny.com",
];

const AT_SIGN = "@";

const validation = {};

for (const email of emailList) {
  let numberOfAtSigns = 0;

  for (const character of email) {
    if (character === AT_SIGN) {
      numberOfAtSigns++;
    }
  }

  validation[email] = numberOfAtSigns;
}

console.log(validation);
// {
//     'johndoes@email.com': 1,
//     'pancake@email@ny.com': 2,
//     'tenya123@@email@ny.com': 3
// }
Enter fullscreen mode Exit fullscreen mode

Does this need an explanation? What do you think it does? If something is new, it the nested for loops. Look at this new example. There are several ways to write this. So try the others you can think of.

const emailList = [
  "johndoes@email.com",
  "pancake@email@ny.com",
  "tenya123@@email@ny.com",
];

const AT_SIGN = "@";

const validation = emailList.map((email) => {
  const emailPartsLength = email.split(AT_SIGN).length;
  const numberOfAtSigns = emailPartsLength > 1 ? emailPartsLength - 1 : 0;

  // we can replace the above two lines with
  // const numberOfAtSigns = email.split("").filter(character => character === AT_SIGN).length
  // why didn't we split at '@'

  return { [email]: numberOfAtSigns };
});

console.log(validation);
// [
//     { 'johndoes@email.com': 1 },
//     { 'pancake@email@ny.com': 2 },
//     { 'tenya123@@email@ny.com': 3 }
// ]
Enter fullscreen mode Exit fullscreen mode

There a keywords known as break and continue used in for loops. So let's say based on some conditions, you want to stop the for loop at some point. Use the break. If you want to skip the computation on a certain element or based on some condition, you can use continue. The continue skips the current iteration and goes to the next. You can experiment with it.

While loop

The while loop is like the for loop. However, it is used when the repetition is infinite or the termination of the loop is conditional. In general, a while loop is in the form:

while (condition) {
  // do something as far as the condition is true
}
Enter fullscreen mode Exit fullscreen mode

Let's do this for a loop using a while loop.

// console log numbers between 0 and 10
for (let loopingNumber = 0; loopingNumber <= 10; loopingNumber++) {
  console.log(loopingNumber);
}
Enter fullscreen mode Exit fullscreen mode

while loop version

let loopingNumber = 0;

while (loopingNumber <= 10) {
  console.log(loopingNumber);
  loopingNumber++;
}
Enter fullscreen mode Exit fullscreen mode

Here, the init part is moved outside the header of the header and the step is moved inside the body of the while loop. What remains is the condition. So as far as the condition holds, the console.log(loopingNumber); is executed and the looping number is incremented.

Example

Let's write a fizz buzz program using a while loop. In this case, we want the first "fizzbuzz" value which will be 15, a multiple of 3 and 5.

let number = 1;

// as far as the number is not a fizzbuzz
while (!(number % 3 === 0 && number % 5 === 0)) {
  number++;
}

// the loop breaks when find a number that is a fizzbuzz

console.log(`The first fizzbuzz is ${number}`);
// The first fizzbuzz is 15
Enter fullscreen mode Exit fullscreen mode

Conclusion

So far we have updated our knowledge and arsenal. We can control the following execution using conditionals and loops. We can now write some huge programs efficiently. We will look into the password and email validation in the next part. Try writing your own validations based on what we have done so far.

We have more on javascript to discuss such as:

  • Functions
  • Callbacks, promises, async & await
  • Next big thing

Top comments (1)

Collapse
 
morphzg profile image
MorphZG

Thanks for sharing