Scope and Closure
Scope and Closure
☠️☠️ var is the old one, and should not be used now in any case. As it has many issues
with creating scopes
Also there are 4 kinds of scope in Javascript - Block Scope, Global Scope, Function Scope,
Module Scope
The scope is the current context of execution in which values and expressions are "visible" MDN
Global Scope : Any variable/expression which is written outside - i.e. not inside any functions,
blocks etc. This is shared across files.
let
{ // block scope
let x = 0;
let y = 0;
console.log(x); // 0
let x = 1; // Error
}
{
let x = 1;
let y = 1;
x = 2;
console.log(x);// 2
}
Temporal Dead Zone(TDZ) : the area in which a variable is not accessible. Temporal because it
depends on time of excution not position
https://coderdost.github.io 1/72
1/18/24, 11:15 PM 1. Scope and Closure
{
// TDZ starts
const say = () => console.log(msg); // hi
const
{
const x; //Error
const y=0;
}
{
const x=1;
x=2 // Error
}
console.log(x); // Error
Variable Shadowing
var
https://coderdost.github.io 2/72
1/18/24, 11:15 PM 1. Scope and Closure
var x = 1;
var x = 2; // valid
console.log(y) // valid
var y = 3
z=4
console.log(z) // valid
var z;
for(let i=0;i<5;i++){
setTimeout(
()=>console.log(i),
1000)
} // prints 0,1,2,3,4
for(var i=0;i<5;i++){
setTimeout(
()=>console.log(i),
1000)
} // prints 5,5,5,5,5
Module scope
In modern javascript, a file can be considered as module, where we use export and import syntax
to use variable across files. We
global Object
The global Object is the variable window in case of browser. This helps you to use
variables across the scopes. Also, it is the this value for global functions
https://coderdost.github.io 3/72
1/18/24, 11:15 PM 1. Scope and Closure
window.alert
window.Promise
In non-browser environment, window doesn't exist. but other global objects exist.
var affects this global obejct, also function declarations.
function sayHi(){
console.log(this) // this will refer to window
}
function sayHi(){
console.log(window) // this is a better way of code
}
function scope
function sayHi(name){
return name;
}
Lexical Environment
https://coderdost.github.io 4/72
1/18/24, 11:15 PM 1. Scope and Closure
null
[outer]
LexicalEnviroment
name: 'john'
name
function sayHi(){
let greet = "hi"
console.log(greet)
}
sayHi()
console.log(name, sayHi)
https://coderdost.github.io 5/72
1/18/24, 11:15 PM 1. Scope and Closure
null
[outer]
LexicalEnviroment1
name: 'john',
sayHi: function
[outer]
LexicalEnviroment2
name sayHi
greet: 'hi'
greet
function sayHi(){
let greet = "hi"
console.log(name)
}
sayHi()
https://coderdost.github.io 6/72
1/18/24, 11:15 PM 1. Scope and Closure
null
[outer]
LexicalEnviroment1
name: 'john',
sayHi: function
[outer]
LexicalEnviroment2
greet: 'hi'
name
Hoisting
https://coderdost.github.io 7/72
1/18/24, 11:15 PM 1. Scope and Closure
sayHi() // valid
function sayHi(){
let greet = "hi"
console.log(name)
}
sayHello() // error
let sayHello = function(){
console.log(name)
}
let x = 1;
{
console.log(x) // Reference error
let x = 2;
}
Closures
function createUser(name){
let greeting = 'Hi '
function greet(){
return greeting + name + ' is Created';
}
return greet()
}
Now more useful work is if we can return the greet function itself.
https://coderdost.github.io 8/72
1/18/24, 11:15 PM 1. Scope and Closure
function createUser(name){
let greeting = 'Hi '
function greet(){
return greeting + name + ' is Created';
}
return greet // returned just definition of function
}
This is Closure
welcomeJohn function definition has access
to outer params ( name ) which came for createUser function
also any other "variables" declared inside createUser will also be accessible to
this welcomeJohn
Example
function initCounter() {
let count = 0;
return function () {
count++;
};
}
NOTE : so whenever you have a function which wants to preserve a value over many calls - it's a
time for closure.
Lexical Environment
https://coderdost.github.io 9/72
1/18/24, 11:15 PM 1. Scope and Closure
function init() {
let name = 'john';
function greet() {
console.log(name)
}
return greet;
}
sayHi();
https://coderdost.github.io 10/72
1/18/24, 11:15 PM 1. Scope and Closure
null
[outer]
LexicalEnviroment1
sayHi: ----
init: function
[outer]
LexicalEnviroment2
init sayHi
name: 'john'
greet: function
[outer]
LexicalEnviroment3
--empty--
name
https://coderdost.github.io 11/72
1/18/24, 11:15 PM 1. Scope and Closure
function initCounter(id) {
let count = 0;
return function () {
count++;
document.getElementById(id).innerText = count;
};
}
let count = 10;
let counter1 = initCounter('btnCount1');
let counter2 = initCounter('btnCount2');
<button onclick="counter1()">1</button>
<p id="btnCount1"></p>
<button onclick="counter2()">2</button>
<p id="btnCount2"></p>
https://coderdost.github.io 12/72
1/18/24, 11:15 PM 1. Scope and Closure
(function(a){
var x = a; // this var is now protected
})(2)
Currying
function sum(a){
return function(b){
return function(c){
console.log(a,b,c)
return a+b+c
}
}
}
let log = time => type => msg => `At ${time.toLocaleString()}: severity ${ty
logNow('warning')('temp high')
logErrorNow('unknown error')
https://coderdost.github.io 13/72
1/18/24, 11:15 PM 1. Scope and Closure
function op(operation) {
return function (a) {
return function (b) {
return operation === 'add' ? a + b : a - b;
};
};
}
add3(6);
sub3(6);
add(1)(2);
2. Objects
Basic behaviours
Reference Copying
person
Object
human
https://coderdost.github.io 14/72
1/18/24, 11:15 PM 1. Scope and Closure
Object1
person
Object2
it a better to use const always, and whenever you must need to re-assign change it ot let
Nested Objects
let person = {
name: 'John',
address: { city: 'delhi', state: 'delhi' },
};
person Object
Object_address addressObject
let person = {
name: 'John',
address: addressObject
};
Copying objects
Shallow Copy
1. Object.assign()
https://coderdost.github.io 15/72
1/18/24, 11:15 PM 1. Scope and Closure
2. Spread Operator[...]
But problem which these is they just create a copy of properties of that object , but not creating a
copy of their references also.
let person = {
name: 'John',
address: addressObject
};
Deep Copy
This is a hard problem to solve in past as there can be multiple level of nested objects and there
can be references to functions etc also. few methods which are there:
1. JSON.stringify and JSON.parse : this method utilizes the fact that every JSON can be
converted to a string value (exception of methods/functions)
let person = {
name: 'John',
address: addressObject
};
2. structuredClone : Browser API which work even for circular references (but functions not
supported)
https://coderdost.github.io 16/72
1/18/24, 11:15 PM 1. Scope and Closure
let person = {
name: 'John',
address: addressObject,
};
person.me = person
we can also defined function as value to properties of objecy. these will be called methods.
Methods are just functions but, it means they have been called in "reference" on an
Object.
let person = {
name:'john',
sayHi: function(){
return "hi";
}
}
person.sayHi() // hi
methods can also access the properties and other methods of same object. To do this we
use this
let person = {
name:'john',
sayHi: function(){
return "hi "+ this.name;
}
}
person.sayHi() // hi john
we can also have used person instead of this but has you know references can be changed.
so that could have created a problem
https://coderdost.github.io 17/72
1/18/24, 11:15 PM 1. Scope and Closure
let person = {
name:'john',
sayHi: function(){
return "hi "+ this.name;
}
}
person.sayHi() // hi john
function sayHi(){
return "hi "+ this.name;
}
sayHi() // Error
// here this will "undefined" in Strict mode
let obj1 = {name: 'john'}
let obj2 = {name: 'wick'}
obj1.say = sayHi;
obj2.say = sayHi;
obj1.say() // hi john
obj2.say() // hi wick
let person = {
name:'john',
sayHi: ()=> {
return "hi "+ this.name;
}
}
person.sayHi() // Error
Symbol
JavaScript also has a Symbol data type. This data type is used as property name in Objects.
Object can only have 2 types of properties - String and Symbol. If you put any other data
type they will convert to String
https://coderdost.github.io 18/72
1/18/24, 11:15 PM 1. Scope and Closure
let person = {
0:'john',
sayHi: ()=> {
return "hi "+ this.name;
}
}
let person = {
name:'john',
[id]:1
}
person[id] // 1
Symbol are always unique - so there is no chance of collision. Even with same "descriptor"
they will be uniquely initialized.
You can get Symbol for some descriptor or key using some methods
for..in loop ignore Symbols. Also methods like Object.keys() ignore these properties.
3. Functions
https://coderdost.github.io 19/72
1/18/24, 11:15 PM 1. Scope and Closure
function sayHi(greet){
return greet
}
sayHi.name // name of function
sayHi.length // length of arguments
sayHi() // works
function sayHi(greet){
return greet
}
sayHello() // Error
let sayHello = function(){ // functional expression
sayHello.name // sayHello
function Person(name){
this.name = name
}
https://coderdost.github.io 20/72
1/18/24, 11:15 PM 1. Scope and Closure
if(user){
return "hello " + user
} else {
return fx('anonymous')
}
}
Decorator (Wrappers)
It's a design pattern in which you modify the functionality of a function by covering it
inside a wrapper.
Memoization (Caching)
function heavy(x) {
console.log(x + ':heavy');
return x + ':heavy';
}
function memoized(fx) {
let map = new Map();
https://coderdost.github.io 21/72
1/18/24, 11:15 PM 1. Scope and Closure
Another Problem
if you try to use this on a method of object, this approach can fail
let task = {
name: 'demo',
heavy(x) {
console.log(x + ':heavy:' + this.name);
return x + ':heavy' + this.name;
},
};
function memoized(fx) {
let map = new Map();
return function (x) {
if (map.has(x)) {
return map.get(x);
} else {
let memoValue = fx(x);
map.set(x, memoValue);
return memoValue;
}
};
}
task.memoizedHeavy = memoized(task.heavy)
task.memoizedHeavy(1) // 1:heavyundefined
changing 'this'
Call
person = {
name: 'demo',
age: 12,
location: 'delhi',
};
function checkName(a) {
return !!this.name;
}
checkName() // Error
checkName.call(person)
checkName.call(person, 1) // a = 1
apply
https://coderdost.github.io 22/72
1/18/24, 11:15 PM 1. Scope and Closure
person = {
name: 'demo',
age: 12,
location: 'delhi',
};
function checkName(a) {
return !!this.name;
}
checkName() // Error
checkName.apply(person)
checkName.apply(person, [1]) // a = 1
bind
person = {
name: 'demo',
age: 12,
location: 'delhi',
};
function checkName(a) {
return !!this.name;
}
checkName() // Error
let boundCheckName = checkName.bind(person)
boundCheckName();
Solution
https://coderdost.github.io 23/72
1/18/24, 11:15 PM 1. Scope and Closure
let task = {
name: 'demo',
heavy(x) {
console.log(x + ':heavy:' + this.name);
return x + ':heavy' + this.name;
},
};
function memoized(fx) {
let map = new Map();
return function (x) {
if (map.has(x)) {
return map.get(x);
} else {
let memoValue = fx.call(this,x);
map.set(x, memoValue);
return memoValue;
}
};
}
task.memoizedHeavy = memoized(task.heavy)
task.memoizedHeavy(1) // 1:heavydemo
Debounce
Run a function only when - if it has not been called again for a fixed period
Suppose you are typing and take a pause of 1 second. Only then that function should be
called.
https://coderdost.github.io 24/72
1/18/24, 11:15 PM 1. Scope and Closure
let count = 1;
function showCount() {
count++;
console.log({ count });
}
Real Example
const el = document.getElementById('text1');
const logo = document.getElementById('text-output1');
el.addEventListener(
'keyup',
debounce(function (e) {
logo.innerText = e.target.value;
}, 1000)
);
Throttle
when you have to only allow 1 execution of a function within a period of time
for example you are scrolling fast but only 1 scroll per 100 millisecond is considered.
https://coderdost.github.io 25/72
1/18/24, 11:15 PM 1. Scope and Closure
let count = 1;
function showCount() {
count++;
console.log({ count });
}
Real Example
function sayHi(){console.log('hi')}
document.addEventListener('scroll',throttle(sayHi,1000))
Arrow functions
Differences
https://coderdost.github.io 26/72
1/18/24, 11:15 PM 1. Scope and Closure
Similarities
4. Iterables, Generators
Iterable (protocol)
Iterables are objects in which we can make array like iteration (Example using for..of loop of
spread operators)
Iterator (protocol)
https://coderdost.github.io 27/72
1/18/24, 11:15 PM 1. Scope and Closure
let iterator = {
i: 0,
next: function () {
return { value: this.i, done: this.i++ > 5 };
},
};
let iterable = {
name: 'john',
age: 34,
[Symbol.iterator]() {
return iterator;
},
};
Example - Range :
let range = {
start: 0,
end: 5,
[Symbol.iterator]() {
let that = this; // this line is very important
let i = this.start;
return { // iterator object
next: function () {
return { value: i, done: i++ > that.end };
}
};
},
};
Array
Infinite iterators
As we can see that we can control, how to control the next() function. In few cases, it will
be useful to have iterators which can need to generate the next value infinitely
If you use such iterators in a loop etc. it can be dangerous as can create infinite loop. But
can be controlled by break etc.
we will cover all this in generators.
https://coderdost.github.io 28/72
1/18/24, 11:15 PM 1. Scope and Closure
Iterables vs Array-like
An object can be
Iterable + Array-like
Iterable only
Array-like only
None of them (not Iterable nor Array-like )
Example :
// iterable + array-like
let arr = [1,2,3]
// only iterable
let range = {
start: 0,
end: 5,
[Symbol.iterator]() {
let that = this; // this line is very important
let i = this.start;
return {
next: function () {
return { value: i, done: i++ > that.end };
},
};
},
};
// only array-like
let array = {
0: 1,
1: 5,
length:2
};
// none
let obj = {
name:'john'
}
Conversions
Array-like to Array
let arrayLike = {
0: 0,
1: 5,
length: 2
};
Map
map.get(1) // 'num1'
map.get('1') // 'str1'
map.get(person) // { balance : 5000 }
map.size // 4
https://coderdost.github.io 30/72
1/18/24, 11:15 PM 1. Scope and Closure
Set
set.add(obj1);
set.add(obj2);
set.add(obj3);
set.add(obj2);
set.add(obj3);
duplicated values in values(), entries() etc are maintained to match Map compatibility
These are 2 alternative way of creating Map or Set like data types - when only object keys
are considered.
They have very limited operations and doesn't support all functionality
Main purpose is that when keys are marked as null they are garbage collected. So this
helps in better memory management
https://coderdost.github.io 31/72
1/18/24, 11:15 PM 1. Scope and Closure
weakMap.set(person, {....});
Generators
function* generatorFunction(){
yield 1;
yield 2;
yield 3
}
Infinite iterator
function* generator() {
let i = 0;
while (true) {
yield i;
i++;
}
}
function createID(it) {
return it.next().value;
}
createID(gen);
createID(gen);
createID(gen);
createID(gen);
createID(gen);
https://coderdost.github.io 32/72
1/18/24, 11:15 PM 1. Scope and Closure
function* generatorFunction(){
yield 1;
yield 2;
yield 3
}
let range = {
start: 0,
end: 5,
for(let r of range){
console.log(r)
}
function range(start,end){
return {
*[Symbol.iterator]() {
for(let value = start; value <= end; value++) {
yield value;
}
}
}
};
for(let r of range(1,5)){
console.log(r)
}
https://coderdost.github.io 33/72
1/18/24, 11:15 PM 1. Scope and Closure
function* range(start,end){
for(let value = start; value <= end; value++) {
yield value;
}
};
console.log([...generator]) // [1,2,3,4,5]
return
function* generatorFunction(){
yield 1;
yield 2;
return 3
}
Generator - composition
using generator inside another generator is easy
https://coderdost.github.io 34/72
1/18/24, 11:15 PM 1. Scope and Closure
function* range(start,end){
for(let value = start; value <= end; value++) {
yield value;
}
};
function* multiRange(){
yield* range(0,5),
yield* range(100,105)
yield* range(200,205)
}
next() method can also take arguments which act as return value of previous yield
statement
function* generatorFunction(){
let result = yield 1;
console.log(result)
let result2 = yield 2;
console.log(result2)
let result3 = yield 3
console.log(result3)
without generators
https://coderdost.github.io 35/72
1/18/24, 11:15 PM 1. Scope and Closure
let range = {
start: 0,
end: 5,
[Symbol.asyncIterator]() {
let that = this; // this line is very important
let i = this.start;
return {
next: async function () {
await new Promise((resolve) => setTimeout(resolve, 1000));
return { value: i, done: i++ > that.end };
},
};
},
};
(async function () {
for await (let f of range) {
console.log(f);
}
})();
with generators
let range = {
start: 0,
end: 5,
async *[Symbol.asyncIterator]() {
for(let i = this.start; i <= this.end; i++) {
await new Promise((resolve) => setTimeout(resolve, 1000));
yield i
};
},
};
(async function () {
for await (let f of range) {
console.log(f);
}
})();
https://coderdost.github.io 36/72
1/18/24, 11:15 PM 1. Scope and Closure
(async function () {
let orgs = []
for await (let f of getData()) {
orgs.push(f);
}
console.log(orgs); // List of all organization in API
})();
5. ProtoTypes
Prototypical Inheritance
Objects are extended from other Objects. And we can re-use their properties and methods.
Object are chained in prototypical inheritance
Objects have a hidden property called [[Prototype]]
https://coderdost.github.io 37/72
1/18/24, 11:15 PM 1. Scope and Closure
Prototype Inheritance
prototypeObject
[[prototype]]
object
Prototype example
animal dog is
animal is prototype of dog prototypically inherited
eats
from animal
[[prototype]]
dog
barks
dog.barks // true
dog.eats // true
https://coderdost.github.io 38/72
1/18/24, 11:15 PM 1. Scope and Closure
Prototype chaining
animal
eats
walks()
[[prototype]]
dog
barks
let animal = {
eats: true,
walks: function () {
return 'walks';
},
};
let dog = { barks: true };
dog.__proto__ = animal;
dog.walks() // walks
https://coderdost.github.io 39/72
1/18/24, 11:15 PM 1. Scope and Closure
animal
eats
walks()
[[prototype]]
dog
barks
[[prototype]]
myDog
name
let animal = {
eats: true,
walks: function () {
return 'walks';
},
};
let dog = { barks: true };
let myDog = { name: 'sifu' };
dog.__proto__ = animal;
myDog.__proto__ = dog;
myDog.name // sifu
myDog.barks // true
myDog.walks() // walks
https://coderdost.github.io 40/72
1/18/24, 11:15 PM 1. Scope and Closure
null
Object_prototype
animal
eats
walks()
[[prototype]]
dog
barks
[[prototype]]
myDog
name
__proto__
https://coderdost.github.io 41/72
1/18/24, 11:15 PM 1. Scope and Closure
let animal = {
eats: true,
walks: function () {
return 'walks';
},
};
let dog = { barks: true };
let myDog = { name: 'sifu' };
dog.__proto__ = animal;
myDog.__proto__ = dog;
myDog.walks = function(){
return 'walks slowly'; // this will not affect prototype
}
for..in loop works on all properties which are enumerable - inherited or own
if you want to avoid looping on inherited ones use Object.hasOwn or
Object.prototype.hasOwnProperty
Object.keys() and Object.value() these will avoid inherited properties.
properties
https://coderdost.github.io 42/72
1/18/24, 11:15 PM 1. Scope and Closure
let usr = {
name : 'john'
}
function User(name){
this.name = name
}
console.log(user)
// User{ name : 'john'}
console.log(usr)
// {name : 'john'}
Step 1 : .prototype proptery is automatically created (on User) and is assigned an object
(empty Object)
function User(name){
this.name = name
}
Step 2 :constructor method is assigned to this prototype, and that is User function itself.
// User.prototype.constructor = User
// user.__proto__ = User.prototype
// this above assignment is done by the constructor call itself
https://coderdost.github.io 43/72
1/18/24, 11:15 PM 1. Scope and Closure
.prototype property
User User_prototype
prototype constructor
[[prototype]]
user
name
methods
function User(name){
this.name = name
}
User.prototype.sayHi = function () {
return this.name;
};
user.sayHi()
// 'john'
user1.sayHi();
// 'wick'
this the main benefit of prototypes. you can have inherited methods.
https://coderdost.github.io 44/72
1/18/24, 11:15 PM 1. Scope and Closure
.prototype property
User_prototype
User
constructor
prototype
sayHi
[[prototype]]
user
name
methods
function User(name){
this.name = name
}
User.prototype.reverseName = function () {
return this.name.split('').reverse().join('');
};
user.reverseName()
// 'nhoj'
user1.reverseName();
// 'kicw'
remember prototype based methods are directly available on their created object instances.
you can also change the prototype completely, not recommended though
https://coderdost.github.io 45/72
1/18/24, 11:15 PM 1. Scope and Closure
let animal = {
eats: true,
walks: function () {
return 'walks';
},
};
function Dog(){
this.barks = true
}
Dog.prototype = animal;
dog.walks()
// walks
.prototype property
animal
Dog
eats
prototype
walks()
[[prototype]]
dog
barks
Native Prototypes
Object.prototype
Array.prototype
Function.prototype
Object.prototype
https://coderdost.github.io 46/72
1/18/24, 11:15 PM 1. Scope and Closure
let obj = {}
toString()
isPrototypeOf()
toLocaleString()
Array.prototype
let arr = []
push()
pop()
slice()
splice()
reverse()
....and many more
Function.prototype
function Fx(){
call()
apply()
bind()
arguments
caller
length
Date.prototype
https://coderdost.github.io 47/72
1/18/24, 11:15 PM 1. Scope and Closure
getTime()
getDay()
getDate()
.... more
Primitives
Primitive types also get wrapped into a Object when used as an Object
String.prototype
"hello".toString()
Number.prototype
10.1111.toFixed(2)
Boolean.prototype
Polyfills
if(!Array.prototype.contains){
Array.prototype.contains = function(searchElement) {
return this.indexOf(searchElement)>=0 ? true : false
}
}
// similar to includes()
NOTE : Shims are piece of code to correct some existing behaviour, while Polyfills are new
API/ behaviours.
https://coderdost.github.io 48/72
1/18/24, 11:15 PM 1. Scope and Closure
Some properties and methods are directly created on these Native constructors.
Object.create()
Object.keys()
Object.values()
Object.hasOwn()
Array.from()
Date.now()
These are not available on instances, and only available on Native contructors
6. Class
Classes are easier way to implement inheritance in JavaScript.
Syntactic Sugar
It's a syntactic sugar to Protypical Inheritance BUT more functionalities than it.
ProtoType Version
function User(name){
this.name = name
}
User.prototype.sayHi = function () {
return this.name;
};
Class Version
https://coderdost.github.io 49/72
1/18/24, 11:15 PM 1. Scope and Closure
class User {
constructor(name) {
this.name = name;
}
sayHi() {
return this.name;
}
}
Similarities:
1. Same kind of prototype property with constructor method is added when called with
new;
2. you can use prototype also on class based things
class User {
constructor(name) {
this.name = name;
}
sayHi() {
return this.name;
}
}
User.prototype.sayHello = function(){
return "hello "+this.name;
}
Differences:
getter/setters
https://coderdost.github.io 50/72
1/18/24, 11:15 PM 1. Scope and Closure
class User {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
get fullName(){
return this.firstName + ' ' + this.lastName;
}
set fullName(_fullName){
this.firstName = _fullName.split(' ')[0];
this.lastName = _fullName.split(' ')[1];
}
}
user.firstName // john
user.lastName // cena
[variableName]() {
return this.name;
}
}
https://coderdost.github.io 51/72
1/18/24, 11:15 PM 1. Scope and Closure
class Button {
constructor(value) {
this.value = value;
}
click() {
return this.value;
}
}
button.click() // play
setTimeout(button.click, 1000);
// this has issue - this has changed here
2 Solution exists :
setTimeout(()=>button.click(), 1000);
setTimeout(button.click.bind(button), 1000);
Also you can add this arrow style function in class definition - which will act as class field
class Button {
constructor(value) {
this.value = value;
}
button.click() // play
setTimeout(button.click, 1000);
https://coderdost.github.io 52/72
1/18/24, 11:15 PM 1. Scope and Closure
Inheritance
We can inherit Parent Class properties and metods in a Child Class. using extends keyword
class Shape {
constructor(name) {
this.name = name;
}
displayShape() {
return 'Shape ' + this.name;
}
}
// constructor(...args){
// super(..args)
// }
https://coderdost.github.io 53/72
1/18/24, 11:15 PM 1. Scope and Closure
.prototype property
Shape_prototype
Shape Rectangle
constructor
prototype name prototype
displayName
[[prototype]]
Rectangle_prototype
constructor
[[prototype]]
rect1
Now adding more properties to constructor of Rectangle. You have to call super
constructor - which will call Shape constructor.
class Shape {
constructor(name) {
this.name = name;
}
displayShape() {
return 'Shape ' + this.name;
}
}
https://coderdost.github.io 54/72
1/18/24, 11:15 PM 1. Scope and Closure
Static Methods
class Shape {
constructor(name,area) {
this.name = name;
this.area = area;
}
static areEqual(shape1, shape2){
return shape1.name === shape2.name && shape1.area === shape2.area
}
Shape.areEqual(s1,s2) // true
static property are also available as a new feature, but rarely used.
class User {
type = "admin"
constructor(name) {
this.name = name;
}
}
properties type and name both are accessible - so they are called public
Protected
https://coderdost.github.io 55/72
1/18/24, 11:15 PM 1. Scope and Closure
this is something not provided by javascript but by convention and get/set method we can
create it
you have to use convention of _ in front of property name - making is known to developer
that this property is not directly accessible and used only via get/set accessors.
class User {
_type = "admin"
constructor(name) {
this.name = name;
}
get type(){
return this._type
}
set type(type){
this._type = type;
}
}
class User {
_type = "admin"
constructor(name) {
this.name = name;
}
get type(){
return this._type
}
set type(type){
if(type==('normal' || 'admin')){
this._type = type;
} else {
throw Error('admin / normal ?')
}
}
}
Private
https://coderdost.github.io 56/72
1/18/24, 11:15 PM 1. Scope and Closure
class User {
#type = "admin"
constructor(name) {
this.name = name;
}
get type(){
return this.#type
}
set type(type){
if(type==('normal' || 'admin')){
this.#type = type;
} else {
throw Error('admin / normal ?')
}
}
}
instanceOf
class Shape {
constructor(name) {
this.name = name;
}
displayShape() {
return 'Shape ' + this.name;
}
}
https://coderdost.github.io 57/72
1/18/24, 11:15 PM 1. Scope and Closure
7. Async JavaScript
Asynchronous APIs
JavaScript itself is not asynchronous langauge it uses some API from browser or
enviroment to achieve this behaviour
console.log(1)
setTimeout(console.log,1000,3); // Timer API
console.log(2)
Now suppose, we have a function which does something meaningful and return a value -
but asynchronously .
function sum(a, b) {
return a + b
}
Callbacks
function sum(a, b) {
return a + b
}
Errors
https://coderdost.github.io 58/72
1/18/24, 11:15 PM 1. Scope and Closure
function sum(a, b) {
if(a>0 && b>0){
return [null,a + b]
} else{
return ['input', null]
}
}
Multiple callbacks
function sum(a, b) {
if(a>0 && b>0){
return [null,a + b]
} else{
return ['input', null]
}
}
let x = 4;
let y = 5;
Promise
https://coderdost.github.io 59/72
1/18/24, 11:15 PM 1. Scope and Closure
event subscriber1
publisher
event subscriber2
subscribers are people who are subscribed to channel (with bell icon)
publisher is video uploader channel
When the release event happens, automatically people are notified about the released
video.
Promise constructor
Pending
resolve(data) reject(error)
fullfilled rejected
Promise Consumers
https://coderdost.github.io 60/72
1/18/24, 11:15 PM 1. Scope and Closure
promise.then(successCallback).catch(errorCallback)
then-catch subscribers
resolve then
promise
reject catch
Callback version
function sum(a, b) {
if(a>0 && b>0){
return [null,a + b]
} else{
return ['input', null]
}
}
Promise version
https://coderdost.github.io 61/72
1/18/24, 11:15 PM 1. Scope and Closure
function sum(a, b) {
if (a > 0 && b > 0) {
return [null, a + b];
} else {
return ['input not correct', null];
}
}
asyncFx(-2,4)
.then(data=>console.log(data))
.catch(err=>console.log(err))
Promise chain
asyncFx(1, 4)
.then((data) => {
console.log(data);
return asyncFx(1, 4);
})
.then((data) => {
console.log(data);
return asyncFx(3, 6);
})
.then((data) => {
console.log(data);
})
.catch((err) => console.log(err));
Note : catch is only one it catches for all above then. Also note that catch works for reject and
also any error throw by code.
finally
https://coderdost.github.io 62/72
1/18/24, 11:15 PM 1. Scope and Closure
asyncFx(1, 4)
.then((data) => {
console.log(data);
return asyncFx(1, 4);
})
.then((data) => {
console.log(data);
return asyncFx(3, 6);
})
.then((data) => {
console.log(data);
})
.catch((err) => console.log(err));
finally(()=>{
doSomething() // after everything is completed
})
Promise API
Promise.all
Parallel execution of async functions - only work when all promises are fullfiled
Promise.all([
asyncFx(1,2),
asyncFx(2,3),
asyncFx(5,6)
]).then(results=>{
console.log(results) // array of resolved value, same order
})
Promise.allSettled
Parallel execution of async functions - only work when all promises are fullfiled or rejected
Promise.allSettled([
asyncFx(1,2),
asyncFx(2,3),
asyncFx(5,6)
]).then(results=>{
console.log(results) // array of resolved/reject objects, same order
})
Promise.race
Parallel execution of async functions - works when any one of promises are fullfiled or rejected
https://coderdost.github.io 63/72
1/18/24, 11:15 PM 1. Scope and Closure
Promise.race([
asyncFx(1,2),
asyncFx(2,3),
asyncFx(5,6)
]).then(results=>{
console.log(results) // value of first settled (resolved/rejected) promi
})
Promise.any
Parallel execution of async functions - works when any one of promises are fullfiled
Promise.race([
asyncFx(1,2),
asyncFx(2,3),
asyncFx(5,6)
]).then(results=>{
console.log(results) // value of first fullfilled promise
})
Promise.reject
Promise.resolve
created already promise which gets resolved just after creation
Async/Await
sayHi().then(result=>console.log(result)) // hi
https://coderdost.github.io 64/72
1/18/24, 11:15 PM 1. Scope and Closure
function sum(a, b) {
if (a > 0 && b > 0) {
return [null, a + b];
} else {
return ['input not correct', null];
}
}
init();
init();
https://coderdost.github.io 65/72
1/18/24, 11:15 PM 1. Scope and Closure
Property of Object
1. own or inherited
2. enumerable or non-enumerable
3. String or Symbol
Property configurations
1. writeable - true/false
2. configurable - true/false
3. enumberable - true/false
4. value : value of property
object1 = {property1:42}
Object.defineProperties(object1, {
property1: {
value: 42,
writable: true,
enumerable: true,
configurable: true
},
property2: {}
});
Strict Mode
It shows up many slient errors in JavaScript.
https://coderdost.github.io 66/72
1/18/24, 11:15 PM 1. Scope and Closure
function myStrictFunction() {
// Function-level strict mode syntax
"use strict";
variable = 10
const o1 = {};
o1.constructor === Object; // true
const a1 = [];
a1.constructor === Array; // true
const n = 3;
n.constructor === Number; // true
3. Object.prototype.__proto__ : .
https://coderdost.github.io 67/72
1/18/24, 11:15 PM 1. Scope and Closure
4. Object.assign() : used to copy all the property from source object (objects) to a target
object.
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
console.log(target);
// Expected output: Object { a: 1, b: 4, c: 5 }
o = {};
// Is equivalent to:
o = Object.create(Object.prototype);
o = Object.create(Object.prototype, {
// foo is a regular data property
foo: {
writable: true,
configurable: true,
value: "hello",
enumerable: true,
},
// bar is an accessor property
bar: {
configurable: false,
get() {
return 10;
},
set(value) {
console.log("Setting `o.bar` to", value);
},
},
});
https://coderdost.github.io 68/72
1/18/24, 11:15 PM 1. Scope and Closure
o = Object.create(null);
// Is equivalent to:
o = { __proto__: null };
function Constructor() {}
o = new Constructor();
// Is equivalent to:
o = Object.create(Constructor.prototype);
Object.defineProperties(object1, {
property1: {
value: 42,
writable: true,
enumerable: true,
configurable: true
},
property2: {}
});
console.log(object1.property1);
// Expected output: 42
Object.defineProperty(object1, 'property1', {
value: 42,
writable: false
});
object1.property1 = 77;
// Throws an error in strict mode
console.log(object1.property1);
// Expected output: 42
10. Object.fromEntries() : key-value pairs (inside an iterable, array or Map) are converted in
object.
https://coderdost.github.io 69/72
1/18/24, 11:15 PM 1. Scope and Closure
// Map to Object
const map = new Map([
["foo", "bar"],
["baz", 42],
]);
const obj = Object.fromEntries(map);
console.log(obj); // { foo: "bar", baz: 42 }
// Transform object
const object1 = { a: 1, b: 2, c: 3 };
console.log(object2);
// { a: 2, b: 4, c: 6
const object1 = {
property1: 42
};
console.log(descriptor1.configurable);
// Expected output: true
console.log(descriptor1.value);
// Expected output: 42
https://coderdost.github.io 70/72
1/18/24, 11:15 PM 1. Scope and Closure
console.log(nonenumOnly);
const object1 = {
prop: 'exists'
};
console.log(Object.hasOwn(object1, 'prop'));
// Expected output: true
console.log(Object.hasOwn(object1, 'toString'));
// Expected output: false
console.log(Object.hasOwn(object1, 'undeclaredPropertyValue'));
// Expected output: false
Its almost same as === but it also differentiate +0 and -0 and NaN
function Foo() {}
function Bar() {}
Bar.prototype = Object.create(Foo.prototype);
console.log(Foo.prototype.isPrototypeOf(bar));
// Expected output: true
console.log(Bar.prototype.isPrototypeOf(bar));
// Expected output: true
https://coderdost.github.io 71/72
1/18/24, 11:15 PM 1. Scope and Closure
21. Object.seal() : seals objects for further addition of new properties, and also make
configurable: false for all properties. but allow old property value modifications.
22. Object.setPrototypeOf() :
console.log(obj.foo);
// Expected output: undefined
Object.setPrototypeOf(obj, parent);
console.log(obj.foo);
// Expected output: "bar"
23. **Object.prototype.LocaleString() :
console.log(date1.toLocaleString('ar-EG'));
// Expected output: " ص٤:٠٠:٠٠ ٢٠١٢/١٢/٢٠"
console.log(number1.toLocaleString('de-DE'));
// Expected output: "123.456,789"
https://coderdost.github.io 72/72