Tuesday, November 23, 2021

JavaScript Essential - Notes

JavaScript - Notes


-- Variables

* Variables cannot start with numbers or symbols and it cannot contain space

user name => invalid
!username => invalid
1user_name => invalid

user_name => valid
userName  => valid
username  => valid

* let and var can be reassigned but const cannot
* if any object is declared with const then the properties of the object can be added/removed but we cannot reassign new object to the variable

Examples of declaration


var userName; // Global scope within the function block
let userName;

// Example 1
for(let i=0; i<5; i++) {
console.log(i)
}
console.log(i) // i is not defined , cos i declared using let is available only inside for loop

// Example 2
for(var i=0; i<5; i++) {
console.log(i)
}
console.log(i) // it prints value 5 cos i was declared using var keyword. it becomes global scope

// Example 3
function loop() {
  for(var i=0; i<5; i++) {
    console.log(i)
  }
}
loop()
console.log(i) // i is not defined. Now the var is inside function so the variable is global inside the function alone


-- Variable Hoisting

When the browser is going through its compile phase it will put both functions and variable declarations into memory first. Few people refer this as moving up the declaration to the top of the code.

Example:
userName = 'yusuf';
console.log(userName);
var userName;

-- Strict Mode

Strict mode tells the browser to run more restricted version of the javascript. This will help browser from making mistakes and eliminates silent errors. We can enable it using "use strict" as our first line of code in the program.

Example: We cannot assign value to a variable without declaring
userName = 'yusuf' // Reference error userName not defined

We can also enable strict mode within function that will execute only that function in strict mode.

-- Objects and Arrays


Host or Environment object: 

Depending on client or server it will be available. E.g. window object for browser and global object for node js

Native object: 

These are independent of the environment like Array, JSON, Promise etc...

Array methods: filter, map, reduce

- Filter: 
For each element in the list it expects true or false from filter method. Based on that new array will be formed

Example 1:
let num = [1,1,2,2,3,3]
let newNum = num.filter( (v,i) => {
  if(i%2==0) { // filtering based on index
    console.log(v,i,'true')
    return true 
  } else {
    console.log(v,i,'false')
    return false
  }
})
console.log(newNum)
Result:
1 0 true
1 1 false
2 2 true
2 3 false
3 4 true
3 5 false
[ 1, 2, 3 ] 

Example 2:
let num = [1,1,2,2,3,3]
let newNum = num.filter( (v,i) => {
  if(v%2==0) { // filtering based on value
    console.log(v,i,'true')
    return true 
  } else {
    console.log(v,i,'false')
    return false
  }
})
console.log(newNum)
Result:
1 0 false
1 1 false
2 2 true
2 3 true
3 4 false
3 5 false

- Map:

For each element we can manipulate the value or give new value and using that new array will be formed.

Example 1:
let num = [1,1,2,2,3,3]
let newNum = num.map( (v,i) => v*2) // manipulating values of the array
console.log(newNum)
Result: [ 2, 2, 4, 4, 6, 6 ]

Example 2:
let num = [1,1,2,2,3,3]
let newNum = num.map( (v,i) => i*2) // manipulating values based on index of the array
console.log(newNum)
Result: [ 0, 2, 4, 6, 8, 10 ]

Example 3:
let num = [1,1,2,2,3,3]
let newNum = num.map( (v,i) => 2) // returning any static value for each time
console.log(newNum)
Result: [ 2, 2, 2, 2, 2, 2 ]

- Reduce:

It allows to create a single value out of the array. Each time the reduce function is called we need to return the new accumulator value that will be used in next call. The final accumulator returned will be the final value of the reducer.

Example 1: Add all elements of array

let num = [1,3,2,5,4]
let newNum = num.reduce( (acc,val, i) => {
  console.log(acc, val, i)
  return acc+val
})
console.log('Final value:', newNum)

During first call acc will be 1st element and val will be 2nd element. What we return from the function will become acc of next call (here acc+val 1+3=4 becomes acc of next call)

Result:
 1 3 1
 4 2 2
 6 5 3
11 4 4
Final value: 15

Example 2: What if we add the index instead of value

let num = [1,3,2,5,4]
let newNum = num.reduce( (acc,val, i) => {
  console.log(acc, val, i)
  return acc+i
})
console.log('Final value:', newNum)

Here acc = 1 (initially) then we are adding indexes to it each time it becomes 1+1+2+3+4 (i.e. acc+idx1+idx2+idx3+idx4)

Result:
1 3 1
2 2 2
4 5 3
7 4 4
Final value: 11

Example 3: What if we do not do any calculation and return one static value during the last element's call

let num = [1,3,2,5,4]
let newNum = num.reduce( (acc,val, i) => {
  console.log(acc, val, i)
  if(i==4) return 100
})
console.log('Final value:', newNum)

Here we are not using acc value at all. We know our array has max index=4 so we are checking if i==4 then returning static 100 as value. So this 100 will be the last value returned from reducer.

Below you can see, apart from 1st time the acc value is undefined cos we are not returning anything from each function call.

Result:
1 3 1
undefined 2 2
undefined 5 3
undefined 4 4
Final value: 100

So, in general reduce function will be used to return a single value based out an array. For each element we can do the manipulation and return a value that becomes accumulator for next element call. Final accumulator returned will be the output of the reducer.

To Be Continued....