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';
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:
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
andconst
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:
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:
In the above code, closure
variable 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:
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: 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:
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:
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
✨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:
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
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
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
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:
- Browser JS Engine (popular V8 JS Engine)
- NodeJs V8 Engine
Browser JS Engine parse Html file and executes JavaScript by three patterns,
- synchronous
- Asynchronous
- 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
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.
Here JavaScript API cheatsheet for front end developer overapi.com/javascript
Image source: overapi.com/javascript
Thanks for reading, if you like it you can subscribe to my blog. 🧡
References from: