Skip to content

Instantly share code, notes, and snippets.

@deependhamecha
Last active July 13, 2024 07:04
Show Gist options
  • Save deependhamecha/78bcc2dc96f5d7d7056986c06f695ec0 to your computer and use it in GitHub Desktop.
Save deependhamecha/78bcc2dc96f5d7d7056986c06f695ec0 to your computer and use it in GitHub Desktop.
Core JS

Core.js

Versions
1 es5
2 es6
3 es2015
4 es7
5 es2016
6 es2017
7 es2018
8 es2019
9 esnext

Different Function declaractions in JS :

function getData() {} // Normal Function

(function() {})(); // Immediate call

var b = function() {}; // function expression

var c = function setData() {}; // named function expression

var d = () => {}; // Arrow function 

Note : All these functions refer to global object(node) / window object(window)

Note : JavaScript functions are executed using the scope they were defined in.

Immediately Call function

var b = function() {
  return 'Hello';
}();

b(); // Not a Function
b // 'Hello'

Above has its own execution context.

If you want to use another context,

name = 'Hey';

(function(name) {
  console.log(name);
}('Hello'));

These both are in different context. Now what if you want to use another.

name = 'Hey';

(function(global, name) {
  console.log(name+" "+global);
}(name, 'Hello'));

Keep a Function but dont call it

If you keep the below code, it will throw an error

function () {
  return 'Hello';
}

So wrap it in a paranthesis,

(function () {
  return 'Hello';
});

If you want to call it, then

(function () {
  return 'Hello';
}());

(function () {
  return 'Hello';
})();

Call and Apply Functions

If you want to change this reference in a function then call the method with call function or apply :

function add(c,d) {
  return this.a + this.b + c + d;
}

var o = { a: 1, b: 2 };

add.call(o, 2, 4); // 9

add.apply(o, [2,4]); // 9

Bind Functions

It creates a clone of the function provided.

Call and Apply functions change this reference of a function during invocation. What if you want to define while declaration ?

** Bind to the rescue **

function d() {
  return this.name;
}

var o = { name : 'Deepen' };

// Create a new method using bind.
// This will copy the function but assigns this to given object reference
var g = d.bind(o);

g(); // Deepen
var dude = function() {
	return this.firstname+ " " + this.lastname;
}.bind(a);

Now, you can also provide additional parameters to bind, which will permanently define those arguments to the called function.

var dude = function(txt) {
	return txt;
}.bind(window, 'My Text');

dude();

Now, check this example,

var dude = function(a,b) {
	return a+b;
}.bind(window, 2);

dude(); // NaN
dude(3); // 5

If you do not provide all arguments to bind, its Okay, however, if pass arguments to calling function, it will apply to next following argument to function parameters.

Object.constructor

All objects will have a constructor property. Objects created without the explicit use of a constructor function (i.e. the object and array literals) will have a constructor property that points to the Fundamental Object constructor type for that object.

var o = {};
o.constructor === Object; // true

var o = new Object;
o.constructor === Object; //true

var a = [];
a.constructor === Array; // true

var a = new Array;
a.constructor === Array //true

var n = new Number(3);
n.constructor === Number; // true

If you ned to know exact Class Type of an Object, use constructor property of the object to determine.

Functions as Constructor

This code ensures function to be always called as Constructor :

function Book(name, year) { 
  if (!(this instanceof Book)) { 
    return new Book(name, year);
  }
  this.name = name;
  this.year = year;
}

Core JavaScript and Prototype (Deprecated)

Unlike Other Programming Languages, JavaScript does not depend on classes for inheritance. Rather it follows a prototype architecture inheritance.

So, how does it work? Well, every object has one property named prototype (proto) which links or points to its parent. It may or may not have a value pointing to another object.

So, when you write:

var myObject = {};

has a property named prototype. In this case, as it is an Object, it points to Object.prototype.

If you want to create an object with no prototype linking to another object (not even Object.prototype) then use following code:

var myObject = Object.create(null);

Object.create() links to another object, in this case, its prototype is set to null (not referencing to anyone).

var d = {}
var e = []
var f = Object.create(null);

console.log(Object.getPrototypeOf(d) === Object.prototype);
console.log(Object.getPrototypeOf(e) === Array.prototype);
console.log(Object.getPrototypeOf(f) === null);

Setting Prototype

It should not be done, as it may cause performance issues.

Creating Properties

For Objects

var myObject = {}

Object.defineProperty(myObject, 'property1', {
  value: 'Deepen',
	configurable: true,
	writable: true,
	enumerable: true
})

console.log(myObject.property1) // Output: Deepen
  • Configurable - It cannot be replaced(i.e. its key cannot be replaced) but its value can be edited if false.
  • Writable - Its value cannot edited if false.
  • Enumerable - It cannot be iterated if false. (for each loop)

We will see each properties in detail, just hang on:

For Arrays

var myObject = []

Object.defineProperty(myObject, 0, {
  value: 'a',
	configurable: true,
	writable: true,
	enumerable: true
})

Object.defineProperty(myObject, 1, {
  value: 'b',
	configurable: true,
	writable: true,
	enumerable: true
})

Object.defineProperty(myObject, 2, {
  value: 'c',
	configurable: true,
	writable: true,
	enumerable: true
})

Now, when yo do:

console.log(myObject); // [ 'a', 'b', 'c' ]
for(var obj in myObject) {
  console.log(obj) // 0 1 2
}
Enumerable

However, when you change enumerable property to false (myObject[1]), see what happens:

var myObject = []

Object.defineProperty(myObject, 0, {
  value: 'a',
	configurable: true,
	writable: true,
	enumerable: true
})

Object.defineProperty(myObject, 1, {
  value: 'b',
	configurable: true,
	writable: true,
	enumerable: false
})

Object.defineProperty(myObject, 2, {
  value: 'c',
	configurable: true,
	writable: true,
	enumerable: true
})

Now, when yo do:

console.log(myObject); // [ 'a', [1]: 'b', 'c' ]
for(var obj in myObject) {
  console.log(obj) // 0 2
}

It does not allow to enumerate(iterate via for each loop), however you can use for loop and iterate and point to each array index like this:

for(var i=0;i<myObject.length;i++) {
  console.log(myObject[i]); // 0 1 2
}

Now, what if you change the key:

var myObject = []

Object.defineProperty(myObject, 0, {
  value: 'a',
	configurable: true,
	writable: true,
	enumerable: true
})

Object.defineProperty(myObject, 11, {
  value: 'b',
	configurable: true,
	writable: true,
	enumerable: false
})

Object.defineProperty(myObject, 2, {
  value: 'c',
	configurable: true,
	writable: true,
	enumerable: true
})
console.log(myObject); // [ 'a', , 'c', , , , , , , , , [11]: 'b' ]
for(var obj in myObject) {
  console.log(obj) // 0 2
}

However, you can also add string like this '11' or '2' but you cannot add strings which cannot be converted to number like 'key1' or 'key2'.

Writable
myObject[2] = 'Boo'
console.log(myObject[2]) // Output: Boo

Now, this time change value of myObject[2]'s property writable to false.

myObject[2] = 'Boo'
console.log(myObject[2]) // Output: b

Writable false makes it constant.

Configurable
console.log(delete myObject[0]); // Will Delete Element on index 0

OR

console.log(delete myObject.property1) // Will Delete property1 of the Element

&

Object.defineProperty(myObject, 0, {
  value: 'a',
	configurable: true,
	writable: true,
	enumerable: **false**
})

If you redefine same property or index, it will replace old one with new property value of enumerable, writeable or simply pu t it, it will allow to replace and delete the key or index but if you make configurable to false then and you define same property, it wont allow you set.

isPrototypeOf

function A () {}
function B () {}
function C () {}

B.prototype = Object.create(A.prototype);
C.prototype = Object.create(B.prototype);

var c = new C();

console.log(C.prototype.isPrototypeOf(c)); // true
console.log(C.prototype.isPrototypeOf(c)); // true
console.log(c instanceof A); // true
console.log(B.prototype.isPrototypeOf(c)); // true
console.log(A.prototype.isPrototypeOf(c)); // true
console.log(Object.prototype.isPrototypeOf(c)); // true

hasOwnProperty

var d = {}
d.name = 'Deepen'
console.log(d.hasOwnProperty(name))

It will only check in d object and not in its prototype. For checking in prototype as well use in operator:

var e = Object.create(d)
console.log('name' in e)

Different way of defining functions

Suppose we two or more functionalities so we can nest like this,

function makeAdder(x) {
  return function(y) {
    return x + y;
  };
}

var add5 = makeAdder(5);
var add10 = makeAdder(10);

console.log(add5(2));  // 7
console.log(add10(2)); // 12

Random Use of Function

function makeSizer(size) {
  return function() {
    document.body.style.fontSize = size + 'px';
  };
}

var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);

size12, size14, and size16 are now functions which will resize the body text to 12, 14, and 16 pixels, respectively. We can attach them to buttons (in this case links) as follows:

document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;
<a href="#" id="size-12">12</a>
<a href="#" id="size-14">14</a>
<a href="#" id="size-16">16</a>

Private Method in JavaScript

var counter = (function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  };   
})();

console.log(counter.value()); // logs 0
counter.increment();
counter.increment();
console.log(counter.value()); // logs 2
counter.decrement();
console.log(counter.value()); // logs 1

Closure

function dude() {
	return function(name) {
		console.log('name');
	}
}

dude()('Deepen');
function setLang(lang) {
	return function (name) {
		if(lang == 'en') {
			return 'Hi, '+name;
		} else if(lang == 'it') {
			return 'Bonjure, '+name;
		} else {
			return 'Namaste, '+name;
		}
	}
}

var sayHi = setLang('en');
sayHi('Deepen');

Function Constructors

Constructor in Javascript

function Person(firstname, lastname) {
	this.firstname = firstname;
	this.lastname = lastname;
}

var person1 = new Person('Deepen', 'Dhamecha');
var person2 = new Person('Dilisha', 'Dhamecha');

Person.prototype.getFullName = function() {
	return this.firstname + ' ' + this.lastname;
}



var s = new String('John');
String.prototype.functionName = function() {
	return any;
}

person1.getFullName();
person2.getFullName();

Create empty Object with prototype

var person = {
	this.firstname = 'Deepen;
	this.lastname = 'Dhamecha';
};

var o = Object.create(person);

Now o is empty and its prototype(parent) is person.

Use Strict

Only apply to function

function dude() {
	'use strict';
	var person = {};
	persom.name = 'Deepen';
}

Apply to whole file

'use strict';
var person = {};
persom.name = 'Deepen';

JavaScript Inheritance

JavaScript is a prototypal language, which means that objects inherit directly from other objects.

Actually, JavaScript is conflicted about its prototypal nature. Instead of having objects inherit directly from other objects, an unnecessary level of indirection is inserted such that objects are produced by constructor functions.

When a function object is created, the Function constructor that produces the function object runs some code like this:

this.prototype = {constructor: this};

The new function object is given a prototype property whose value is an object containing a constructor property whose value is the new function object. Every function gets a prototype object because the language does not provide a way of determining which functions are intended to be used as constructors.

JavaScript Modules

This is using default

x.js

export default function xx() {
    return "Hello World!";
}

main.js

import anyName from './x';

console.log(anyName());

When you dont have to use default export, x.js

export function xx() {
    return "Hello World!";
}

main.js

import { anyName } from './x';
console.log(anyName);

As if you are importing one by one.


When you have multiple functions to export,

y.js

export function y1() {
    return "Y1";
}

export function y2() {
    return "Y2";
}

// You can rename anything you would like to rename as the key of this object
export default {
    y5: y1,
    y6: y2
};

main.js

import obj from './y.js';

console.log(obj.y1());
console.log(obj.y2());

Now using es2015 style using require, z.js

function dude() {
    return "Dude";
}

module.exports = dude;

main.js

var d = require('./z');
console.log(d.dude1());

Now using es2015 style using require for multiple modules,

z.js

function dude() {
    return "Dude";
}

function dudex() {
    return "Yo Dude";
}

module.exports = {
    dude1: dude,
    dude2: dudex
}

main.js

var d = require('./z');
console.log(d.dude1());

ES6 Features

Destructing Object

Before ES6

var user = {name: 'Deepen', age: 26};
var name = user.name; // 'Deepen'
var age: user.age; // 26

Using ES6

var { name, age } = {name: 'Deepen', age: 26};
console.log(name); // 'Deepen'
console.log(age); // 26

Before ES6

var user = {name: 'Deepen', age: 26};
var nameX = user.name;
var ageX = user.age;

Using ES6

var user = {name: 'Deepen', age: 26};
var { name:nameX, age:ageX } = user;

If not present then provide default like this:

var user = {name: 'Deepen', age: 26};
var {name:nameX='', age:ageX=1};

Destructing Arrays (Spread Operator)

var dudes = ['John', 'Smith', 'Deepen'];
var [d1, d2] = dudes;
console.log(d1); // 'John'
console.log(d2); // 'Smith'

Provide default value

var dudes = ['John'];
var [d1="Deepen", d2="Smith"] = dudes;
console.log(d1); // 'John'
console.log(d2); // 'Smith'

Swapping Array Values (Useless)

var a = 1;
var b = 3;

[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1

Pick values from array (Yuck, they could have made it better by specifying indexes either)

var dudes = [1,2,3,4,5];
var [,,d1, ,d2] = dudes;
console.log(d1); // 3
console.log(d2); // 5

When destructuring an array, you can unpack and assign the remaining part of it to a variable using the rest pattern (In short, pick value and assign rest):

var [a, ...b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // [2, 3]

var [a, b, ...c] = [1, 2, 3];
console.log(a); // 1
console.log(b); // 2
console.log(c); // [3]

Unpacking values from a regular expression match,

function parseProtocol(url) { 
  var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
  if (!parsedURL) {
    return false;
  }
  console.log(parsedURL); // ["https://developer.mozilla.org/en-US/Web/JavaScript", "https", "developer.mozilla.org", "en-US/Web/JavaScript"]

  var [, protocol, fullhost, fullpath] = parsedURL;
  return protocol;
}

console.log(parseProtocol('https://developer.mozilla.org/en-US/Web/JavaScript')); // "https"

Spread Operator (Object)

var o = {x:1};
var p = {y:2, ...o};	// Output: {x:1, y:2}
var q = {o, ...y:2}	// Output: {o: {x:1}, y:2}

Block-Scoped Functions

{
    function foo () { return 1 }
    console.log("foo() === 1: ", foo() === 1)
    {
        function foo () { return 2 }
        console.log("foo() === 2: ", foo() === 2);
    }
    console.log("foo() === 1: ", foo() === 1);
}

Output:

foo() === 1:  true
foo() === 2:  true
foo() === 1:  true

Arrow Functions

  1. In arrow functions you cannot bind this. By Default it points to itself and this cannot be reassigned with call nor apply.
  2. Arrow functions does not have prototype property.
function fn1() {}
const fn2 = () => {}

console.log(fn1.prototype); // {fn1()}
console.log(fn2.prototype); // undefined
  1. You cannot call new on Arrow function to create an object.
const UserDetails = (name) => {
  this.name = name;
}

const user1 = new UserDetails(); // Uncaught TypeError: UserDetails is not a constructor

Variadic Functions (Varargs)

function dude(x, y, ...z) {
	console.log(x, y, z);
}
dude(1,2,3,4,5)

Output:

1, 2, [3,4,5]

New Type of String parameter method call

function getName(str) {
	console.log(str);
}

getName`Deepen`

However, its value is pretty weird, ["Deepen", raw: ["Deepen", ......]]

But this doesnt work

var first = 'Deepen';

getName`${first}`

This is only acceptable for one string value

In short: waste of time, effort of developing this. Dont know who in the world would use this?

Javascript: Understand the Weird Parts

Objects and Functions

Namespaces

A container for variables and functions.

Functions are objects

function greet() {
  console.log('Hello');
}

greet.language='english';
console.log('Greet: ', greet);

First Class Functions

Functions which can be passed around to a variable and created on the fly.

console.log(function() {return "dude";});
function logit(a) {
  return a;
}

console.log(logit(function(){return "dude"}));

this

var o = {
    a: () => {
        console.log(this);

        var some = () => {
            console.log("some: ", this);
        }

        var someone = function() {
            console.log("someone: ", this);
        }

        function sometwo() {
            console.log("sometwo: ", this);
        }
        some();someone();sometwo();

        return () => {console.log("return: ", this);};
    },
    b: function() {
        console.log(this);
    }
}

var

Consider this code.

function dude() {
    var x =1;
    console.log(dude);
}
dude();

Closure

function some(name) {
  return () => {console.log(name);}
}

var someOne = some('Deepen');
someOne(); // Output: Deepen

Here Deepen is printed as outer context is destroyed when someOne() is ran.

Its not only for parameterized variables but also for local variables created inside a function.

function what() {
    var x = 'What Function';

    return () => {console.log(x)};
}

var whatever = what();
whatever(); // Output: What Function

Lets consider another example:

function buildFunctions() {
    var arr = [];

    for(var i=0;i<3;i++) {
        arr.push(
            function() {
                console.log(i);
            }
        );
    }

    return arr;
}

var fs = buildFunctions();

fs[0]();
fs[1]();
fs[2]();

/* Output:
3
3
3
*/

To make it 1,2,3 by creating another execution context inside that function.

function buildFunctions() {
    let arr = [];

    for(var i=0;i<3;i++) {
        arr.push(
            (function(j) {
                return function() {
                    console.log(j);
                }
            })(i)
        );
    }

    return arr;
}

var fs = buildFunctions();

fs[0]();
fs[1]();
fs[2]();

You can also it just with let. It will create 3 different references in closure.

function buildFunctions() {
    var arr = [];

    for(let i=0;i<3;i++) {
        arr.push(
            function() {
                console.log(i);
            }
        );
    }

    return arr;
}

var fs = buildFunctions();

fs[0]();
fs[1]();
fs[2]();

/* Output:
1
2
3
*/

Inheritance, proto and Prototype

Every Object has a property called __proto__ which makes inheritance possible in javascript. Consider following example:

var person = {
    firstname: 'Default',
    lastname: 'Default',
    getFullName: function() {
        return this.firstname + ' ' + this.lastname;
    }
}

var john = {
    firstname: 'John', lastname: 'Doe'
}

// Link to a parent
john.__proto__ = person;

console.log(john.__proto__.firstname) // Default
console.log(john.getFullName()) // John Doe

var jane = {
  firstname: 'Jane'
};

jane.__proto__ = person;

console.log(jane.__proto__.firstname) // Default
console.log(jane.getFullName()) // Jane Default

You should access __proto__ directly, rather use this encapsulated way:

Object.getPrototypeOf(john);
Object.getPrototypeOf(jane);

It will return the object which __proto__ is referring to.

Prototype

On the other hand, prototype is a property on function object. Consider, prototype as the blueprint or class of the object, for example.

function Dog() {}
var dog1 = new Dog();
console.log(dog1.prototype); // {Dog()} <-- this points to blueprint or prototype(english) of the object.

for in loop with Prototype

var Person = {
  firstname: 'Default',
  lastname: 'Default',
  getFullName() {
    return this.firstname+' '+this.lastname
  }
};

var fullname = {
    firstname: 'Deepen',
    middlename: 'Naresh',
    lastname: 'Dhamecha'
}

fullname.__proto__ = Person;

for(var key in fullname) {
    console.log("Key: ", key);
    console.log("Value: ", fullname[key]);
}

It will also print getFullName(). As it is attached to its prototype. To consider only its own properties.

for(var key in fullname) {
    if(fullname.hasOwnProperty(key)) {
      console.log("Key: ", key);
      console.log("Value: ", fullname[key]);
    }
}

Object and new

function Person() {
  this.firstname = 'Deepen';
  this.lastname = 'Dhamecha';
}

If you do this, then it will assign properties and methods on global/window and p1 will be undefined since its just a normal function without returning anything.

var p1 = Person();

But with new keyword,

var p2 = new Person(); // Output: Person {firstname: 'Deepen', lastname: 'Dhamecha'}

This will create a new empty object and assign those properties and methods to it.

If you want to return new object altogether then return from function.

function Person2() {
  this.firstname = 'Deepen';
  this.lastname = 'Dhamecha';

  return {greetings: 'Hello';}
}

var p3 = new Person2();
console.log(p3);

So you can make it like this,

function Person(firstname, lastname) {
  this.firstname = firstname;
  this.lastname = lastname;
}

var john = new Person('John', 'Doe');
console.log(john);

var jane = new Person('Jane', 'Doe');
console.log(jane);

Prototype

When you do new Person(), it creates a function object.

Consider this example,

function Dog() {}

Dog.prototype.breed = 'BullDog';

var dog1 = new Dog();

console.log(dog1.prototype); // undefined

console.log(Dog.prototype); // {breed: 'BullDog', constructor: f}

prototype property is bound to functions and not its object. prototype is used when creating objects. Above showcases on Dog function object but what about object.

Consider this,

console.log(dog1); // Dog {}
console.log(dog1.__proto__); // {breed: 'BullDog', constructor: f}
console.log(dog1.__proto__.__proto__); // {constructor: f, class: Object}
console.log(dog1.__proto__.__proto__.__proto__); // null
console.log(dog1.hasOwnProperty('breed')); // false

So, if you check dog1 object, then breed is not on the object itself but rather on its parent object. So, what prototype does is, when new is invoked on a function, it checks for any prototype assigned. If assigned, then it creates an object of type Dog, assigns prototype attributes to it and links it to __proto__ of the object.

Module imports in NodeJS

You can write

import { dude } from 'filename';

But for this to work, you need to specify one of the 3 things:

  1. File extension as .mjs.
  2. "type":"module" in package.json at the root.
  3. node --input-type=module

Differences between ES modules and CommonJS

No require, exports, or module.exports In most cases, the ES module import can be used to load CommonJS modules.

If needed, a require function can be constructed within an ES module using module.createRequire().

No __filename or __dirname These CommonJS variables are not available in ES modules.

__filename and __dirname use cases can be replicated via import.meta.url.

No Addon Loading Addons are not currently supported with ES module imports.

They can instead be loaded with module.createRequire() or process.dlopen.

No require.resolve Relative resolution can be handled via new URL('./local', import.meta.url).

For a complete require.resolve replacement, there is a flagged experimental import.meta.resolve API.

Alternatively module.createRequire() can be used.

No NODE_PATH NODE_PATH is not part of resolving import specifiers. Please use symlinks if this behavior is desired.

No require.extensions require.extensions is not used by import. The expectation is that loader hooks can provide this workflow in the future.

No require.cache require.cache is not used by import as the ES module loader has its own separate cache.

Map, Set, WeakSet and WeakMap

Set Unique values

var arr = [1,2,3,4];
let mySet = new Set(arr);
console.log(mySet);
for(let s of mySet) {
  console.log(s);
}

Map Key => Value pair

let myMap = new Map([['a1', 'Deepen'], ['a2','Dhamecha']]);

for(let [key, value] of myMap) {
    console.log(`key: ${key}, value: ${value}`);
}

WeakSet and WeakMap are same except that it cannot be iterated.

Event Bubbling and Event Capturing

Event bubbling is event propogating from child to parent.

<!DOCTYPE html>
<html lang="en">
    <head>

      </head>
      <body>
        <div style="padding: 10px;background-color:red;">
          <button>Click me</button>
        </div>

        <script>
          var div = document.querySelector('div');
          var btn = document.querySelector('button');
      
          div.addEventListener("click", function() {
            console.log('div');
          });
      
          btn.addEventListener("click", function() {
            console.log('button');
          });
        </script>
      </body>
</html>
Output:
button
div

Event Capturing is very rare where event is propagating from parent to child.

<!DOCTYPE html>
<html lang="en">
    <head>

      </head>
      <body>
        <div style="padding: 10px;background-color:red;">
          <button>Click me</button>
        </div>

        <script>
          var div = document.querySelector('div');
          var btn = document.querySelector('button');
      
          div.addEventListener("click", function() {
            console.log('div');
          }, true);
      
          btn.addEventListener("click", function() {
            console.log('button');
          }, true);
        </script>
      </body>
</html>

Set true after listener, which reverses event bubbling.

stopPropagation, stopImmediatePropagation and preventDefault

When you modify the above code

btn.addEventListener("click", function(event) {
  console.log('button');
  event.stopPropagation();
});

It prints:

Output:
button

stopPropagation() stops the propagation to its parent. Remember, parent and above and not same sibling or same element.

btn.addEventListener("click", function(event) {
  console.log('button');
  event.stopPropagation();
});

btn.addEventListener("click", function(event) {
  console.log('button 2');
});

Here, button and button2 will be printed.

Functions

Function has a length property which has value of number of parameters.

You cannot this attached with bind to an arrow function.

Currying

This is also known as partial application feature.

let sum = (x,y) => x+y;

let succ = sum.bind(null, 1);

console.log(succ(2)); // Output: 3;
function f(y,z) { return this.x + y + z;}
let g = f.bind({x:1}, 2);

console.log(g(3)); // Output: 6

Function() Constructor

Because functions are objects, there is Function() constructor that can be used to create new functions:

const f = new Function("x", "y", "return x*y");

This line of code creates a new function that is more or less equivalent to a function defined with familiar syntax:

const f = function(x,y) {return x*y};

There are a few points that are important to understand about the Function() constructor:

  1. The Function() constructor allows JavaScript functions to be dynamically created and compiled at runtime.
  2. The Function() constructor parses the function body and creates a new function object each time it is called. If the call to the constructor appears within a loop or within a frequently called function, this process can be inefficient. By contrast, nested functions and function expressions that appear within loops are not recompiled each time they are encountered.
  3. A last, very important point about the Function() constructor is that the functions it creates do not use lexical scoping; instead, they are always compiled as if they were top level functions, as the following code demonstrates:
let scope = "global";
function constructFunction() {
  let scope = "local";
  return new Function("return scope"); // Doesn't capture local scope!
}
// This line returns "global" because the function returned by the
// Function() constructor does not use
// the local scope.
constructFunction()() // => "global"

The Function() constructor is best thought of as a globally scoped version of eval() that defines new variables and functions in its own private scope.

Higher-order functions

A higher-order function is a function that operates on functions, taking one or more functions as arguments and returning a function. Check below,

function not(f) {
  return function(...args) {
    const result = f.apply(this, args);
    return !result;
  }
}

const even = x => x % 2 === 0;

const odd = not(even);

[1,1,3,5,5].every(odd);

This not() function is a higher-order function because it takes a function argument and returns a new function.

Unique elements from Array

let a = ["1", "1", "2", "3", "3", "1"];
let a = ["1", "1", "2", "3", "3", "1"];
let unique = a.filter((item, i, ar) => ar.indexOf(item) === i);
console.log(unique);

In Operator

Consider this object.

const pet = {name: "Kitty", age: 20};
const dog = {name: "Babubhai"};
dog.__proto__ = pet;

console.log(dog.hasOwnProperty('name')); // true
console.log(dog.hasOwnProperty('age')); // false

// But with in operator

console.log('name' in dog); // true
console.log('age' in dog); // true

It checks in parent object as well.

Javascript Classes

If two objects inherit from the same prototype, this typically (but not necessarily) means that they were created and initialized by the same constructor function or factory function.

JavaScript has always allowed the definition of classes. ES6 introduced a brand-new syntax (including a class keyword) that makes it even easier to create classes.

New Javascript classes work in the same way that old-style classes.

Callback Hell

Everything about Promise

To avoid callback hell, we use Promise model. To make it clean. Now, on the event loop side, it works pretty different when comparing callback execution vs callback of promise.

To make a Promise,

var flag = true;
var p = new Promise((resolve, reject) => {
  if(flag) {
    resolve('Successfully executed.');
  } else {
    reject('Something went wrong.');
  }
})

A Promise is in one of these states:

  • pending: initial state, neither fulfilled nor rejected.
  • fulfilled: meaning that the operation was completed successfully.
  • rejected: meaning that the operation failed.

then()

catch()

Promise.all()

The Promise.all() static method takes an iterable of promises as input and returns a single Promise. This returned promise fulfills when all of the input's promises fulfill (including when an empty iterable is passed), with an array of the fulfillment values. It rejects when any of the input's promises rejects, with this first rejection reason.

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});
// Expected output: Array [3, 42, "foo"]

Promise.allSettled()

The Promise.allSettled() static method takes an iterable of promises as input and returns a single Promise. This returned promise fulfills when all of the input's promises settle (including when an empty iterable is passed), with an array of objects that describe the outcome of each promise.

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) =>
  setTimeout(reject, 100, 'foo'),
);
const promises = [promise1, promise2];

Promise.allSettled(promises).then((results) =>
  results.forEach((result) => console.log(result.status)),
);

// Expected output:
// "fulfilled"
// "rejected"

Promise.any()

Promise.race()

NodeJS Event Loop

Nodejs handles async events with event lyouoop model or you can also think of it as different queues in NodeJS. So, it handles event in this order:

  1. Timers - setTimeout(), setInterval()
  2. IO - Network & Disk child process
  3. Pool - More explanation needed.
  4. Check - setImmediate() callbacks are invoked here.
  5. Close - Closing callbacks eg. socket.on('close', ...)

Remember, process.nextTick() immediately executes where as setImmediate() executes on next tick. Strange!!!


There are 6 different queues in every loop, each holding one or more callback functions that need to be executed on the call stack eventually.

Note: that microtask queue is not a part of libuv.

[Image]

  1. Order will be nextTick queue following promise queue.
  2. All callbacks within the timer queue are executed.
  3. Callbacks in the microtask queue(if present) are executed after every callback in the timer queue.
  4. All callbacks within the I/O queue are executed.
  5. Callbacks in the microtask queue(if present) are executed after every callback in the I/O queue.
  6. All callbacks in the check queue are executed.
  7. Callbacks in the microtask queues(if present) are executed after every callback in the check queue.
  8. All callbacks in the close queue are executed.
  9. For one final time in the same loop, the microtask queues are executed after each callback.x

NextTick and Promise

Note that nextTick is only available in Node runtime and not the browser. nextTick callbacks in the nextTick queue are always executed before promise callbacks in the queue.

Lets consider a very simple example.

Promise.resolve().then(() => {console.log("This is a Promise")})
process.nextTick(() => {console.log("This is nextTick")});

nextTick is always given priority over promise. But if callbacks in the nextTick are empty and event loop moves onto executing Promise callbacks in the promise queue, then it will not come back to execute the nextTick just because of the priority of nextTick from promise queue

// index.js
process.nextTick(() => console.log("this is process.nextTick 1"));
setTimeout(() => {console.log("This is setTimeout");});
process.nextTick(() => {
  console.log("this is process.nextTick 2");
  process.nextTick(() =>
    console.log("this is the inner next tick inside next tick")
  );
});
process.nextTick(() => console.log("this is process.nextTick 3"));

Promise.resolve().then(() => console.log("this is Promise.resolve 1"));
Promise.resolve().then(() => {
  console.log("this is Promise.resolve 2");
  process.nextTick(() =>
    console.log("this is the inner next tick inside Promise then block")
  );
});
Promise.resolve().then(() => console.log("this is Promise.resolve 3"));

Output

this is process.nextTick 1
this is process.nextTick 2
this is process.nextTick 3
this is the inner next tick inside next tick
this is Promise.resolve 1
this is Promise.resolve 2
this is Promise.resolve 3
this is the inner next tick inside Promise then block
This is setTimeout

Timer Queue

Let's mix Timer Queue callbacks with nextTick and Promise.

// index.js
setTimeout(() => console.log("this is setTimeout 1"), 0);
setTimeout(() => {
  console.log("this is setTimeout 2");
  process.nextTick(() =>
    console.log("this is inner nextTick inside setTimeout")
  );
}, 0);
setTimeout(() => console.log("this is setTimeout 3"), 0);

process.nextTick(() => console.log("this is process.nextTick 1"));
process.nextTick(() => {
  console.log("this is process.nextTick 2");
  process.nextTick(() =>
    console.log("this is the inner next tick inside next tick")
  );
});
process.nextTick(() => console.log("this is process.nextTick 3"));

Promise.resolve().then(() => console.log("this is Promise.resolve 1"));
Promise.resolve().then(() => {
  console.log("this is Promise.resolve 2");
  process.nextTick(() =>
    console.log("this is the inner next tick inside Promise then block")
  );
});
Promise.resolve().then(() => console.log("this is Promise.resolve 3"));

Output

this is process.nextTick 1
this is process.nextTick 2
this is process.nextTick 3
this is the inner next tick inside next tick
this is Promise.resolve 1
this is Promise.resolve 2
this is Promise.resolve 3
this is the inner next tick inside Promise then block
this is setTimeout 1
this is setTimeout 2
this is inner nextTick inside setTimeout
this is setTimeout 3

Now, why it did execute innerNextTick in setTimeout? As mentioned above in the explanation points that after every Timer Queue callback, it will execute microtask queue(nextTick and Promise).

I/O Queue

Let's consider following example.

// index.js
const fs = require("fs");

setTimeout(() => console.log("this is setTimeout 1"), 0);

fs.readFile(__filename, () => {
  console.log("this is readFile 1");
});

Here, the output should be very simple, but that isnt the case. Sometimes it will output readFile first instead of setTimeout.

Why because a queue waits for 1ms time for a callback, if it doesnt come, it will move on to next queue. Even though setTimeout is timed at 0ms, putting the callback into the queue will also delay with 1ms which will allow event loop to move onto next queue.

I/O Polling

Now, lets mix above queues and check queue so, cause I/O queue will be only completely understood if you deal with check queue(poll queue).

Let's consider below example,

// index.js
const fs = require("fs");

fs.readFile(__filename, () => {
  console.log("this is readFile 1");
});

process.nextTick(() => console.log("this is process.nextTick 1"));
Promise.resolve().then(() => console.log("this is Promise.resolve 1"));
setTimeout(() => console.log("this is setTimeout 1"), 0);
setImmediate(() => console.log("this is setImmediate 1"));

for (let i = 0; i < 2000000000; i++) {}

Now, the output is very straight forward but thats not the case. Output this is process.nextTick 1 this is Promise.resolve 1 this is setTimeout 1 this is setImmediate 1 this is readFile 1

I/O events are polled and callback functions are added to the I/O queue only after the I/O is complete

Since, it already moved ahead of IO queue, it executed check queue first, then it went to I/O queue callback.

Check Queue

If you want setImmediate() to be called later after I/O poll, then put it inside readFile().

Let's consider different example now, lets mix, nextTick and Promise.

// index.js
const fs = require("fs");

fs.readFile(__filename, () => {
  console.log("this is readFile 1");
  setImmediate(() => console.log("this is setImmediate 1"));
});

process.nextTick(() => console.log("this is process.nextTick 1"));
Promise.resolve().then(() => console.log("this is Promise.resolve 1"));
setTimeout(() => console.log("this is setTimeout 1"), 0);

for (let i = 0; i < 2000000000; i++) {}

Output

this is process.nextTick 1
this is Promise.resolve 1
this is setTimeout 1
this is readFile 1
this is inner process.nextTick inside readFile
this is inner Promise.resolve inside readFile
this is setImmediate 1

Let's consider different example now,

//index.js
setImmediate(() => console.log("this is setImmediate 1"));
setImmediate(() => {
  console.log("this is setImmediate 2");
  process.nextTick(() => console.log("this is process.nextTick 1"));
  Promise.resolve().then(() => console.log("this is Promise.resolve 1"));
});
setImmediate(() => console.log("this is setImmediate 3"));

Output

this is setImmediate 1
this is setImmediate 2
this is process.nextTick 1
this is Promise.resolve 1
this is setImmediate 3

setTimeout and setImmediate

// index.js
setTimeout(() => console.log("this is setTimeout 1"), 0);
setImmediate(() => console.log("this is setImmediate 1"));

If you run the code multiple times, you will notice that the order of execution is not consistent.

Note: The order of execution can never be guaranteed when running setTimeout() with a delay of 0ms and the setImmediate() method.

Close Queue

These are always called after all queues execution.

Object Destructuring

var a = {x:1, y:2};
var key = 'z';
var b = {...a, [key]: 3};

+ Operator to convert to valid number

var a = 3.0449494+e2;
var b = {...a, [key]: a};

Try using <input type="number" />, you will get it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment