Javascript Note
Javascript Note
☠️☠️ 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
}
{
// 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
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
<script src="index.js" type="module"></script>
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
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
Every variable in JavaScript (within global / block / or function) has a reference to an object-
like data called Lexical enviroment. This object (kind of object) serves as the basis of search
for value of variable.
null
[outer]
LexicalEnviroment
name: 'john'
name
function sayHi(){
let greet = "hi"
console.log(greet)
}
sayHi()
console.log(name, sayHi)
Lexical Enviroment (functions)
null
[outer]
LexicalEnviroment1
name: 'john',
sayHi: function
[outer]
LexicalEnviroment2
name sayHi
greet: 'hi'
greet
function sayHi(){
let greet = "hi"
console.log(name)
}
sayHi()
Lexical Enviroment (functions)
null
[outer]
LexicalEnviroment1
name: 'john',
sayHi: function
[outer]
LexicalEnviroment2
greet: 'hi'
name
Hoisting
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.
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
function init() {
let name = 'john';
function greet() {
console.log(name)
}
return greet;
}
let sayHi = init();
sayHi();
null
[outer]
LexicalEnviroment1
sayHi: ----
init: function
[outer]
LexicalEnviroment2
init sayHi
name: 'john'
greet: function
[outer]
LexicalEnviroment3
--empty--
name
<button onclick="counter1()">1</button>
<p id="btnCount1"></p>
<button onclick="counter2()">2</button>
<p id="btnCount2"></p>
(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
logNow('warning')('temp high')
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
let person = {name:'john'} // Object1
person = {name:'wick'}; // Object2
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()
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)
2. structuredClone : Browser API which work even for circular references (but functions not
supported)
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
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
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
// get symbol by name
let sym = Symbol.for("name");
let sym2 = Symbol.for("id");
for..in loop ignore Symbols. Also methods like Object.keys() ignore these properties.
3. Functions
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 can be called as constructor
function Person(name){
this.name = name
}
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();
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
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
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.
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.
let count = 1;
function showCount() {
count++;
console.log({ count });
}
function sayHi(){console.log('hi')}
document.addEventListener('scroll',throttle(sayHi,1000))
Arrow functions
Differences
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)
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.
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
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
weakMap.set(person, {....});
Generators
function* generatorFunction(){
yield 1;
yield 2;
yield 3
}
Infinite iterator
function* generator() {
let i = 0;
while (true) {
yield i;
i++;
}
}
const gen = generator();
function createID(it) {
return it.next().value;
}
createID(gen);
createID(gen);
createID(gen);
createID(gen);
createID(gen);
function* generatorFunction(){
yield 1;
yield 2;
yield 3
}
let range = {
start: 0,
end: 5,
for(let r of range){
console.log(r)
}
Better version - with function
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)
}
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
}
let generator = generatorFunction();
generator.next() // {value:1, done:false}
generator.next() // {value:2, done:false}
generator.next() // {value:3, done:true} **
Generator - composition
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
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);
}
})();
(async function () {
let orgs = []
for await (let f of getData()) {
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]]
Prototype Inheritance
prototypeObject
[[prototype]]
object
Prototype example
animal dog is
animal is prototype of dog prototypically inherited
eats
from animal
[[prototype]]
dog
barks
let animal = { eats: true };
let dog = { barks: true };
dog.__proto__ = animal;
dog.barks // true
dog.eats // true
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
Prototype chain can be longer and longer
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
Prototype end at "null"
null
Object_prototype
animal
eats
walks()
[[prototype]]
dog
barks
[[prototype]]
myDog
name
__proto__
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
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
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.
.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
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
let obj = {}
toString()
isPrototypeOf()
toLocaleString()
Array.prototype
let arr = []
push()
pop()
slice()
splice()
reverse()
....and many more
Function.prototype
function Fx(){
Date.prototype
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.
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
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
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;
}
}
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.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);
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)
// }
.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;
}
}
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
}
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
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
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;
}
}
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
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;
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
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
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
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=>{
Promise.race
Parallel execution of async functions - works when any one of promises are fullfiled or rejected
Promise.race([
asyncFx(1,2),
asyncFx(2,3),
asyncFx(5,6)
]).then(results=>{
console.log(results) // value of first settled (resolved/rejected) p
})
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
Async/Await
sayHi().then(result=>console.log(result)) // hi
function sum(a, b) {
if (a > 0 && b > 0) {
return [null, a + b];
} else {
return ['input not correct', null];
}
}
init();
init();
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.
function myStrictFunction() {
// Function-level strict mode syntax
"use strict";
variable = 10
const o1 = {};
o1.constructor === Object; // true
const a1 = [];
a1.constructor === Array; // true
3. Object.prototype.__proto__ : .
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);
},
},
});
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
7. Object.defineProperty(): defines a new property or modifies old one ,directly on object, return
the object
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.
// 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
11. Object.getOwnPropertyDescriptor() : return configuration object of a specific property. that
object is mutable but won't affect the original configurations
Object.getOwnPropertyDescriptors() - is similar to this but return configuration of all
properties at once.
const object1 = {
property1: 42
};
console.log(descriptor1.configurable);
// Expected output: true
console.log(descriptor1.value);
// Expected output: 42
console.log(nonenumOnly);
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
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() :
const obj = {};
const parent = { foo: 'bar' };
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"