Know Your JavaScript🤌

Know Your JavaScript🤌

This blog covers the basics of JavaScript. So, lets begin✨

🔭Scope

Scope in JavaScript defines accessibility of variables, objects and functions. There are three types of scope:

  • Global Scope

When the JavaScript engine executes a script, it creates a global execution context. When we define global-scoped variable then that variable can be accessible through out the script.

var message = 'Hi';

JavaScript-Global-Variables.png Image Source: javascripttutorial.net

The variable message is global-scoped. It can be accessible everywhere in the script.

  • Local Scope

The variable which is defined inside the function is called local variable and can only be accessible inside the function.

function animal(){
    let animal1 = 'tiger';
    console.log(animal1);
}
animal();
console.log(animal1);

Output:

Screenshot 2022-08-19 160323.png

In the above code, the variable animal1, when calling outside the function is returning referenceError as the variable is defined inside the function.

  • Block Scope

    ES6 provides the let and const keywords that allow you to declare variables in block scope.

Generally, whenever you see curly brackets {}, it is a block. It can be the area within the if, else, switch conditions or for, do while, and while loops.

✨Hoisting

By the definition of MDN,

JavaScript Hoisting refers to the process whereby the interpreter appears to move the declaration of functions, variables or classes to the top of their scope, prior to execution of the code.

It allows functions to be safely used in code before they are declared.

For example,

console.log(Hoist);
var Hoist = 'The variable Has been hoisted'; //Output: undefined

JavaScript only hoists declarations, not initialization. Functions are hoisted first and then variables. Variables and constants declared with let and const are not hoisted. Function declaration are hoisted but function expressions are not.

✨Polymorphism

Polymoriphism in javascript refers to the concept of reusing a single piece of code multiple times.

For example,

class Car{
    constructor(vehicle){
        this._vehicle = vehicle;
    }
    move(){
        console.log('drive', this._vehicle);
    }
}
class Bike{
    constructor(vehicle){
        this._vehicle = vehicle;
    }
    move(){
        console.log('ride', this._vehicle);
    }
}
function getVehicle(vehicle){
    switch(vehicle.type){
        case"bike":
            return new Bike(vehicle);
        case "car":
            return new Car(vehicle);
        default:
            break;
    }
}

let vehicle = getVehicle({
    type: "bike",
});
vehicle.move() // ride {type:'bike'}
vehicle = getVehicle({
    type: 'car',
})
vehicle.move(); // drive {type:'car}

Ouput:

Screenshot 2022-08-19 185027.png

In the above code, both are 🚜vehicles and both vehicles move. But depending on the type of the vehicle, they move differently. But from the user's point of view they just have to call move() method.

✨Closures

Closure is when a function is able to remember and access its lexical scope even when that function is executing outside its lexical scope.

In laymen terms, whenever you see a function keyword within another function, the inner function has access to variables in the outer function, that is a closures.

var a = 42;
function js(){
  return a;
}
js()

This is the example of closure because a is outside the scope of function js(). Closures are just using variables that come from a higher scope.

Closure remembers the environment

The function defined in the closure 'remembers' the environment in which it was created. Closure happens when an inner function is defined in outer function and is made accessible to be called later.

function fruit(){
    var apple = 'Hello apple';
    var log = ()=>{
        console.log(apple);
    }
    return log;
}
var closure = fruit();
closure();

Output:

Screenshot 2022-08-22 003346.png

In the above code, closurevariable is now pointing to the log() function. Meaning calling closure() function is actually invoking the log() function from the fruit() function. If you see result log() functions accurately logs the value of hello variable which was originally declared in the parent function fruit(). It means the log() function has accurately "remembered" the value of the hello variable.

✨IIFE

IIFE (Immediately Invoked Function Expression) is a JavaScript function that runs as soon as it is defined.

For example,

(function fruit(){
    //your code here
})()

It is a function expression. It is moreover a self-executing function and useful in closure. It also prevents from polluting the global scope.

var sum = (function(){
    var foo = 20;
    function bar(){
        foo = foo +10;
        console.log(foo);
    }
    return bar;
})()
sum()   
sum()
sum()

Output:

Screenshot 2022-08-22 103403.png The primary reason to use an IIFE is to obtain data privacy. Because JavaScript’s var scopes variables to their containing function, any variables declared within the IIFE cannot be accessed by the outside world.

new and this keywords

The new operator will create the instance of an object. If the new keyword is called then the following actions are taken:

  • It links the newly created object to another object. It does it by setting its constructor to another object. The object type is set to its constructor function.
  • It makes the this variable point to the newly created object.
  • It invokes the constructor function.
  • object.prototype property is set to the object's prototype. For example,
function Car(name){
    console.log(this); //this points to myCar
    this.name = name;
}

var myCar = new Car('honda')
console.log(myCar)

Output: image.png For more insights,

Car is a constructor function because it is invoked using new keyword. Car function has a field called name. myCar object is created from the Car function using new keyword. It makes Car the prototype/constructor of myCar. It sets the name field to Honda. The value of myCar becomes {name: "Honda"}

✨Prototype

Prototype is a link to another object. In JavaScript, objects are chained together by prototype chain. JS objects inherit properties and methods from a prototype. Prototype property allows you to add properties and methods to any object dynamically.

For example,

function Animal(name){
    this.name = name;
}
Animal.prototype.age =10;
var Cat = new Animal('cat');
console.log(Cat)
console.log(Cat.name)
console.log(Cat.age)

Output:

Screenshot 2022-08-23 135918.png

When object Cat is inherited from object Animal, then Animal is the prototype object or the constructor of the Cat.

✨Prototypal Inheritance

Prototypal Inheritance means that if the property is not found in the original object itself then the property will be searched for in the object's parent prototype object.

For example,

function Animal(name){
    this.name = name;
}
Animal.prototype.move=function(){
    console.log('move');
}
Cat.prototype = Object.create(Animal.prototype)
function Cat(name){
    Animal.call(this,name);
}

Cat.prototype.meow=function(){
    console.log('meow');
}

var misty = new Cat('misty');
console.log(misty);
console.log(misty.name);
console.log( misty.meow());
console.log( misty.move())

Output:

Screenshot 2022-08-23 170716.png

Animal object is at the top of the inheritance. It has a Animal.prototype property on it. We also have Cat object and to execute prototypal inheritance we have to link their prototype. Cat.prototype is linked with Animal.prototype. Then we have created misty object from Cat.

Why prototypal inheritance is better?

  • It is simple, just create and extend objects. You don't worry about classes, interfaces, abstract classes, virtual base classes, constructor etc.
  • It is more powerful, you can 'mimic' multiple inheritance by extending object from multiple objects. Just handpick properties and methods from the prototypes you want.
  • It is dynamic, you can add new properties to prototypes after they are created. This also auto-adds those properties and methods to those object which are inherited from this prototype.
  • It is less verbose than class-based inheritance.

✨Memoization

Memoization is a technique for speeding up the application by caching its previously computed results. If the data is not cached, then the function is executed, and the result is added to the cache.

The function is an integral part of the programming, they help to modularity and reusable to our code, as per above definition memoization is an optimizing our code.

const memoizedAdd = () => {
    let cache = {};
    return (value) => {
        if (value in cache) {
            console.log('Fetching from cache');
            return cache[value];
        } else {
            console.log('Calculating result');
            let result = value + 10;
            cache[value] = result;
            return result;
        }
    }
}
// returned function from memoizedAdd
const newAdd = memoizedAdd();
console.log(newAdd(9)); //output: 19 calculated
console.log(newAdd(9)); //output: 19 cached

Output

image.png

✨apply, call and bind methods

apply, call and bind are used to attach a correct this to the function and invoke it. The difference is the way of function invocation.

bind()

It returns a function. This returned function can later be called with a certain context set for calling the original function. The returned function needs to be invoked separately.

For example,

var person ={
    hello: function(message){
        console.log(this.name + " says hello "+ message)
    }
}
var ngNinja = {
    name: "NgNinja Academy"
}
var sayHello = person.hello.bind(ngNinja)
sayHello("world");

Output: image.png Here, person object has a method called hello(). ngNinja object does not have it. You can bind hello() to ngNinja object and call it later in the code.

call()

call() attaches this to function and invokes the function immediately. The owner object is sent as an argument. With call(), an object can use a method belonging to another object.

For example,

var person ={
    hello: function(message){
        console.log(this.name + " says hello "+ message)
    }
}
var ngNinja = {
    name: "NgNinja Academy"
}
person.hello.call(ngNinja,"world");

Output image.png

In the above example this is set to the ngNinja object. You can send arguments to the function as a comma-separated list following the owner object.

apply()

apply() also attaches this to a function and invokes the function immediately. apply() is similar to call() except it takes an array of arguments instead of the comma-separated list.

For example,

var person ={
    hello: function(message){
        console.log(this.name + " says hello "+ message)
    }
}
var ngNinja = {
    name: "NgNinja Academy"
}
person.hello.apply(ngNinja,["world"]);

Output

image.png

Here, this is set to the ngNinja object. You can send arguments to the function as a comma-separated list following the owner object.

✨Callback Function

Callback functions are executed "later". Later it can be any action that you'd want to be completed before calling the callback function. Callback functions are passed as arguments to the outer function.

For example,

function getName(){
    return "viewers";
}
function greet(getName){
    const name = getName();
    return "Hello " + name;
}
greet(getName);

Output

image.png In the above code, we can see that we are passing the function which we want to execute later on. greet() is the outer function. And getName() is the callback function. We pass getName() function to the outer greet() function as a function argument. The value from getName() callback function is then used in the outer function greet().

✨Promises

For detailed explanation of the promise, you can read the other blog. Promises. Thank you 🧡

✨Asynchronous Js

In JavaScript Synchronous and asynchronous are code execution Pattern,

In JavaScript Code Execution done By two separate ways:

  1. Browser JS Engine (popular V8 JS Engine)
  2. NodeJs V8 Engine

Browser JS Engine parse Html file and executes JavaScript by three patterns,

  1. synchronous
  2. Asynchronous
  3. defer
index.html

<script src='index.js'>           //default Synchronous

<script async src='index.js'>      //parse as Asynchronously

<script defer src='index.js'>      //parse as deferred

NodeJS V8 Engine: NodeJS V8 engine executes its JavaScript Code as single-threaded based on the Event loop!

✨async and await

async makes a function return a Promise and await makes a function wait for a Promise. Similar to callback and promises, we have another paradigm for handling async programming. Every async function you write will return a promise, and every single thing you await will ordinarily be a promise.

In JavaScript Asynchronous pattern handled in various versions,

ES5 -> Callback

ES6 -> Promise

ES7 -> async & await For example,

let promise1 = new Promise((resolve, reject)=>{
    console.log("Hello");
})
let promise2 = new Promise((resolve,reject)=>{
    resolve(setTimeout(()=>{
        console.log('viewers')
    },5000))
})

async function display() {
    let data = await Promise.all([promise1,promise2]);
    console.log(data);
  }

display()

Output

Screenshot 2022-08-24 163246.png

In the above code, we have used two promises and used display() function with async and await. In Async & Await lot more stuff there, Just play around it. Thank you

Here JavaScript API cheatsheet for front end developer overapi.com/javascript

Screenshot 2022-08-24 165509.png Image source: overapi.com/javascript

Thanks for reading, if you like it you can subscribe to my blog. 🧡

References from:

Did you find this article valuable?

Support Sagar Medtiya by becoming a sponsor. Any amount is appreciated!