Search This Blog

2024/03/30

Javascript Algorithm:Fibonacci Sequence

Fibonacci Sequence:
The Fibonacci sequence is a sequence in which each number is the sum of the
two preceding ones. Numbers that are part of the Fibonacci sequence are known
as Fibonacci numbers, commonly denoted Fn .

The sequence commonly starts from 0 and 1.the sequence is as below

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,..

How to generate fibonanci Sequence in Javascript:

Each function below prints all fibonancci numbers less than 10.

Solution 1:
function fibonacciSequence(max) {
let startPoint = 0;
let current = 1;
let arr = [0, 1];

let next = startPoint + current;
while (next < max) {
arr.push(next);
startPoint = current;
current = next;
next = startPoint + current;
}
return arr;
}

var resultArray = fibonacciSequence(10);
console.log(resultArray);

Output:
[
0, 1, 1, 2,
3, 5, 8
]

Solution 2:

function fibonacciSequence(max) {
let startPoint = 0;
let current = 1;

console.log(startPoint)
console.log(current)

let next = startPoint + current;
while (next < max) {
console.log(next)
startPoint = current;
current = next;
next = startPoint + current;
}
}

fibonacciSequence(10);

Output:
0
1
1
2
3
5
8


Solution2: Using generator function.

function* fibonacciSequenceGenerator(max) {
let startPoint = 0;
let current = 1;

yield startPoint
yield current

let next = startPoint + current;
while (next < max) {
yield next
startPoint = current;
current = next;
next = startPoint + current;
}
}

let iterator = fibonacciSequenceGenerator(10)
for(let val of iterator){
console.log(val)
}

Output:
0
1
1
2
3
5
8


Solution3:Using Recursion.

function fibonacciSequenceRecursive(index) {
switch (index) {
case 0:
return 0;
case 1:
case 2:
return 1;
default:
return (
fibonacciSequenceRecursive(index - 1) +
fibonacciSequenceRecursive(index - 2)
);
}
}

for (let i = 0; fibonacciSequenceRecursive(i) < 10; i++) {
let si = fibonacciSequenceRecursive(i);
console.log(si);
}

Output:
0
1
1
2
3
5
8


Solution 4: Using generator function
function* fibonacciSequenceGenerator(max) {
let result = 0;
let index = 1;

let obj = {};

while (result < max) {
yield result;
if (index == 1 || index == 2) {
result = 1;
obj[index] = result;
} else {
result = obj[index - 1] + obj[index - 2];
obj[index] = result;
}
index++;
}
}

let iterator = fibonacciSequenceGenerator(10);
for (let val of iterator) {
console.log(val);
}

Output:
0
1
1
2
3
5
8

Solution 5: Using two generator functions:
function* fibonacciGenerator() {
let prev = 0;
let curr = 1;

while (true) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}

function* firstNFibonacci(max) {
const fibonacci = fibonacciGenerator();
let result = fibonacci.next().value;

while (result < max) {
yield result;
result = fibonacci.next().value;
}
}

// Create a generator instance for the first 3 Fibonacci numbers
const iterator = firstNFibonacci(10);

// Generate and print the first 3 Fibonacci numbers
for (const val of iterator) {
console.log(val);
}

Output:
0
1
1
2
3
5
8

Javascript: Generator Functions


What is generator function?

A generator function is a special type of function in JavaScript
that allows pausing and resuming its execution during runtime.
Unlike regular functions, which run to completion, generator functions
can be paused and resumed multiple times, making them particularly useful
for dealing with asynchronous operations, handling large datasets,
and writing custom iterators.

Generator functions are defined using the function* syntax, and they
use the yield keyword to pause the function's execution and produce a
value. When a generator function is called, it returns an iterator object,
which can be used to control the function's execution.

Syntax Of Generator Function:

The syntax of generator function is:

Syntax:
function* generatorFunction() {
// Generator function body
yield value1;
yield value2;
// ...
}

Explanation:
The function* keyword indicates that this is a generator function.
Inside the generator function body, the yield keyword is used to
pause the function and produce a value to the caller.

Iterators and generators in javascript:

Iterators and generators are related concepts in JavaScript, often used
together to create iterable objects that produce a sequence of values.
Here's an overview of each concept:

Iterator:
1) An iterator is an object that provides a way to access the elements
of a collection one at a time,typically in a sequential manner.

2) Iterators have a next() method that returns an object with two
properties: value (the next value in the sequence) and done (a boolean
indicating whether the end of the sequence has been reached).

3) You can manually iterate over an iterator using a loop or consume its
values using other methods like for...of loop, Array.from, or
destructuring assignment.

4) Iterators are commonly used with iterable objects such as arrays,
strings, maps, sets, etc., to provide a standardized way of accessing
their elements.

Generator:
1) A generator is a special type of iterator that can be defined using a
function with an asterisk (function*). Generators allow you to define an
iterative algorithm by writing code that looks like a standard function
but behaves like an iterator.

2) Generators use the yield keyword to yield values one at a time. When a
generator function is called, it returns an iterator object that can be
used to iterate over the values generated by the generator.

3) Unlike regular functions, generator functions can maintain their state
between successive calls. They pause their execution at each yield
statement and resume it when the generator's next() method is called again.

4) Generators are often used to create sequences of values lazily or
on-demand, making them useful for scenarios where you need to generate a
large or potentially infinite sequence of values without consuming
excessive memory.

Return value of generator function:
Return value of generator function is in following format.

{ value: value, done: true | false}

Explanation:
The object has two properties value and done . The value contains
the value to be yielded. Done consists of a Boolean (true|false)
which tells the generator if .next() will yield a value or undefined.

Examples of generator Function:

Example 1:
function* evenNumberGenerator(max) {
let first = 0;
while (first < max) {
first = first + 2;
yield first;
}
}

//looping using for of loop
for (let val of evenNumberGenerator(10)) {
console.log(val);
}

//looping using classic for loop
const iteratorThree = evenNumberGenerator(10);
for (let resultThree = iteratorThree.next();
!resultThree.done; resultThree = iteratorThree.next()) {
console.log(resultThree.value);
}

//looping using while with assumption that done is
// true when function reaches end
const iteratorTypeOne = evenNumberGenerator(10);
let resultTypeOne = iteratorTypeOne.next();
while (!resultTypeOne.done) {
console.log(resultTypeOne.value);
resultTypeOne = iteratorTypeOne.next();
}

//looping using while with assumption that value is undefined when
//function reaches end
const iteratorTwo = evenNumberGenerator(10);
let resultTypeTwo = iteratorTwo.next();
while (resultTypeTwo.value) {
console.log(resultTypeTwo.value);
resultTypeTwo = iteratorTwo.next();
}
Explantion:
Output of all these four loop is same.For each loop output is

Output for each loop:
2
4
6
8
10

The return() Method:
The return() method allows us to force a generator to complete before it
reaches the end. It can take an optional argument that will be returned
as the final value of the generator.

We will try to reuse above code here
Code:
function* evenNumberGenerator(max) {
let first = 0;
while (first < max) {
first = first + 2;
yield first;
}
}

const iteratorTypeOne = evenNumberGenerator(10);
let resultTypeOne = iteratorTypeOne.next();
while (resultTypeOne.value) {
console.log(resultTypeOne);
if (resultTypeOne.value == 6) {
resultTypeOne = iteratorTypeOne.return("Finished!");
} else {
resultTypeOne = iteratorTypeOne.next();
}
}
console.log(resultTypeOne);

Output:
{ value: 2, done: false }
{ value: 4, done: false }
{ value: 6, done: false }
{ value: 'Finished!', done: true }
{ value: undefined, done: true }
Explanation:
The statement resultTypeOne = iteratorTypeOne.return("Finished!");
passed
value as finished & done as true so on nect iteration get that value
i.e.
{ value: 'Finished!', done: true }
it forces the interation to end in sense next value will be undefined &
done as true.
i.e.
{ value: undefined, done: true }



We Can't foresee that next iteration value:
when working with generators, you typically won't know beforehand
if the next iteration will be the last one (i.e., if done will be
true or false) until you actually call next() on the iterator.

Throwing exception:
Consider code below:
Code:
function* generate() {
try {
yield "2 + 2 = ?"; // Error in this line
yield "4 + 4 = ?";
console.log("The execution does not reach here,
because the exception is thrown above");
}
catch (exp) {
console.log(exp); // shows the error
}
}

let generator = generate();

let question = generator.next();
console.log("Question:", question);

try {
generator.throw(new Error("The answer is not found in my database"));
} catch (e) {
console.log(e); // shows the error
}
let another = generator.next();
console.log("another:", another);

Output:
Question: { value: '2 + 2 = ?', done: false }
Error: The answer is not found in my database
another: { value: undefined, done: true }
Explanation:
The code after try catch complete is
let another = generator.next()
console.log("another:", another)
it runs & print another: { value: undefined, done: true }
saying end is reached.

To pass an error into a yield, we should call generator.throw(err).
In that case, the err is thrown in the line with that yield on which
current control lies.
Here the yield of "2 + 2 = ?" leads to an error.

Psudo Random Generator:
One of them is testing. We may need random data: text, numbers, etc.
to test things out well.In JavaScript, we could use Math.random().
But if something goes wrong, we’d like to be able to repeat the test,
using exactly the same data.For that, so called “seeded pseudo-random
generators” are used. They take a “seed”, the first value, and then
generate the next ones using a formula so that the same seed yields
the same sequence, and hence the whole flow is easily reproducible.
We only need to remember the seed to repeat it.

An example of such formula, that generates somewhat uniformly
distributed values is
next = previous * 16807 % 2147483647

If we use 1 as the seed, the values will be:

16807
282475249
1622650073
…and so on…

Code (Using normal function):
function pseudoRandom(seed) {
let value = seed;
return function () {
value = (value * 16807) % 2147483647;
return value;
};
}
let generator = pseudoRandom(1);

console.log(generator()); // 16807
console.log(generator()); // 282475249
console.log(generator()); // 1622650073


Code (Using Generator Function):
function* pseudoRandom(seed) {
let prevVal = seed;
while (true) {
prevVal = (prevVal * 16807) % 2147483647;
yield prevVal;
}
}

var iterator = pseudoRandom(1);
console.log(iterator.next());// 16807
console.log(iterator.next());// 282475249
console.log(iterator.next());// 1622650073
Output:
{ value: 16807, done: false }
{ value: 282475249, done: false }
{ value: 1622650073, done: false }



Passing value in next() call:

Consider code below:
Code:
function* foo(x) {
var y = 2 * (yield x + 1);
console.log(y)
var z = yield y / 3;
console.log(z)
return x + y + z;
}

//calling code
var it = foo(5);// x becomes 5 in foo function

// note: not sending anything into `next()` here
console.log(it.next()); // { value:6, done:false }

console.log(it.next(12)); // { value:8, done:false }
console.log(it.next(13)); // { value:42, done:true }
Output:
{ value: 6, done: false }
y: 24
{ value: 8, done: false }
z: 13
{ value: 42, done: true }
Explanation:
1) In calling code the first line is
var it = foo(5);
which make value of x as 5.
2) The second line in calling code is
console.log(it.next()).
Here we are not passing any value to next() call as in first call even
if it is passed it get ignored.
The first line in generator function code is
var y = 2 * (yield x + 1);
thing that is on right side of yield is evaluated and returned ,so x+1
becomes 6 & 6 is returned to calling code.
control still remain on 1st line of generator function code i.e.
var y = 2 * (yield x + 1);
3) The third line in calling code is
console.log(it.next(12));
As we are passing value 12 in next() call.As control is still on first
line
var y = 2 * (yield x + 1);
12 passed will replace (yield x + 1) & y becomes 24.yield on this
line already ran so it moves further
prints y as per its value in console.log statement.moves further as no
yield encountered yet.next line is
var z = yield y / 3;
Expression on right side of yield is evaluated y/13 is effectively
24/3 so it becomes 8 and its returned to calling code.
Control is still on 3rd line o generator function code i.e.
var z = yield y / 3;
4) The forth line in calling code is
console.log(it.next(13));
Here we are passing value 13 in next() call.As control is still on
line
var z = yield y / 3;
the yield y/3 becomes 13,so z becomes 13.As No yield statement found
control moves to next line.
print 13 the value of z in console.log statement.It moves on next line
but x is 5,y is 24 & z become 13.
so the line
return x + y + z;
will return 5+24+13 meaning 42.but this is last line so done become
true.

An async generator function:
An async generator function is declared using async function* syntax. Inside,
the yield keyword can be combined with await to handle asynchronous operations
gracefully. This means we can yield promises, fetch data and seamlessly
integrate
it into our data stream.

Async Generators can be iterated using a for-await-of loop.

Code:
// Async function that returns a promise,delay can be added with settimeout
async function fetchData(id) {
return new Promise(async (resolve, reject) => {
const data = await fetch(`https://reqres.in/api/users/${id}`);
resolve(data.json());
});
}

// Async generator function to yield data based on IDs
async function* asyncDataGenerator(ids) {
for (const id of ids) {
// Wait for the promise to resolve
const data = await fetchData(id);
yield data;
}
}

// Array of IDs for fetching data
const ids = [1, 2, 3, 4, 5];

// Iterate over the async data generator using for-await-of
(async () => {
try {
for await (const item of asyncDataGenerator(ids)) {
console.log(item);
}
} catch (e) {
console.error(e);
}
})();


Code:
// Async generator function to yield data based on IDs
async function* asyncDataGenerator(ids) {
for (const id of ids) {
const data = fetch(`https://reqres.in/api/users/${id}`)
.then((res) => {
return res.json();
});
yield data;
}
}

// Array of IDs for fetching data
const ids = [1, 2, 3, 4, 5];

// Iterate over the async data generator using for-await-of
(async () => {
try {
for await (const item of asyncDataGenerator(ids)) {
console.log(item);
}
} catch (e) {
console.error(e);
}
})();

output of Both Code is same.

Output:
{
data: {
id: 1,
email: 'george.bluth@reqres.in',
first_name: 'George',
last_name: 'Bluth',
avatar: 'https://reqres.in/img/faces/1-image.jpg'
},
support: {
url: 'https://reqres.in/#support-heading',
text: 'To keep ReqRes free, contributions towards server costs are
appreciated!'
}
}
{
data: {
id: 2,
email: 'janet.weaver@reqres.in',
first_name: 'Janet',
last_name: 'Weaver',
avatar: 'https://reqres.in/img/faces/2-image.jpg'
},
support: {
url: 'https://reqres.in/#support-heading',
text: 'To keep ReqRes free, contributions towards server costs are
appreciated!'
}
}
{
data: {
id: 3,
email: 'emma.wong@reqres.in',
first_name: 'Emma',
last_name: 'Wong',
avatar: 'https://reqres.in/img/faces/3-image.jpg'
},
support: {
url: 'https://reqres.in/#support-heading',
text: 'To keep ReqRes free, contributions towards server costs are
appreciated!'
}
}
{
data: {
id: 4,
email: 'eve.holt@reqres.in',
first_name: 'Eve',
last_name: 'Holt',
avatar: 'https://reqres.in/img/faces/4-image.jpg'
},
support: {
url: 'https://reqres.in/#support-heading',
text: 'To keep ReqRes free, contributions towards server costs are
appreciated!'
}
}
{
data: {
id: 5,
email: 'charles.morris@reqres.in',
first_name: 'Charles',
last_name: 'Morris',
avatar: 'https://reqres.in/img/faces/5-image.jpg'
},
support: {
url: 'https://reqres.in/#support-heading',
text: 'To keep ReqRes free, contributions towards server costs are
appreciated!'
}
}

Asynchronous Operations with Generator Functions:

Traditionally, asynchronous tasks in JavaScript were managed using callbacks
or promises, which could lead to callback hell or complex promise chains.
Generator functions, in combination with yield and next(), offer a more
intuitive way to write asynchronous code.

Code:
function fetchData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = fetch(url).then((res) => {
return res.json();
});
resolve(data);
}, 2000);
});
}

function* fetchDataGenerator() {
const data1 = yield fetchData("https://reqres.in/api/users/1");
console.log(data1);

const data2 = yield fetchData("https://reqres.in/api/users/2");
console.log(data2);

const data3 = yield fetchData("https://reqres.in/api/users/3");
console.log(data3);
}

const iterator = fetchDataGenerator();
const promise = iterator.next().value;
promise.then((data) => {
iterator.next(data).value.then((data1) => {
iterator.next(data1).value.then((data2) => {
iterator.next(data2);
});
});
});

Output:
{
data: {
id: 1,
email: 'george.bluth@reqres.in',
first_name: 'George',
last_name: 'Bluth',
avatar: 'https://reqres.in/img/faces/1-image.jpg'
},
support: {
url: 'https://reqres.in/#support-heading',
text: 'To keep ReqRes free, contributions towards server costs are
appreciated!'
}
}
{
data: {
id: 2,
email: 'janet.weaver@reqres.in',
first_name: 'Janet',
last_name: 'Weaver',
avatar: 'https://reqres.in/img/faces/2-image.jpg'
},
support: {
url: 'https://reqres.in/#support-heading',
text: 'To keep ReqRes free, contributions towards server costs are
appreciated!'
}
}
{
data: {
id: 3,
email: 'emma.wong@reqres.in',
first_name: 'Emma',
last_name: 'Wong',
avatar: 'https://reqres.in/img/faces/3-image.jpg'
},
support: {
url: 'https://reqres.in/#support-heading',
text: 'To keep ReqRes free, contributions towards server costs are
appreciated!'
}
}

Explanation:
In the above example, we have a generator function fetchDataGenerator()
that yields promises obtained from the fetchData() function. Each yielded
promise is resolved inside a then() block, and the resulting data is passed
back to the generator function using next().

Benefits of Generator Functions
1) Simpler Asynchronous Code: Generator functions provide a cleaner and more
sequential way to handle asynchronous operations compared to a traditional
callback or promise-based approaches.

2) Lazy Evaluation: Generator functions allow for lazy evaluation of data
streams. They produce values on demand, reducing memory usage and improving
performance when dealing with large datasets.

3) Custom Iterators: Generator functions simplify the creation of custom
iterators, making it easier to iterate over custom data structures or
implement unique traversal patterns.

4) Stateful Execution: Generator functions retain their state
between invocations, allowing for resumable computation and maintaining
context across multiple function calls.

Node.js:NPM dependency with common packages

Question:
If in node.js application we install 2 packages.both packages have a
common dependency but different versions.how npm will manage this
situation?

Answer:
if in node.js application we install 2 packages.both packages have a
common dependency but different versions.npm follows Semantic Versioning
(SEMVER) rules for version selection.If the dependency versions are
compatible according to SEMVER (i.e., satisfy the specified version range),
npm installs the version that satisfies the requirements of all packages.
If the dependency versions are incompatible according to SEMVER (i.e.,
do not satisfy the specified version range), npm attempts to resolve
the conflict by choosing a compatible version or raising a dependency
resolution error if no compatible version can be found.

In case where one version can not solve dependency tree it will install
multiple version of same package.

Question:
if in node.js application we install 2 packages.both packages have a
common dependency utill vertsion.how npm keep common dependency once
on disk?

Answer:
When you install multiple npm packages that have a common dependency up to
the same version, npm takes advantage of its dependency resolution
mechanism to ensure that the common dependency is kept once on disk.
This behavior is part of npm's approach to managing dependencies
efficiently and reducing duplication.

Shared Dependency Management:

npm maintains a centralized node_modules directory structure where all
installed packages and their dependencies are stored.If multiple packages
require the same version of a dependency, npm installs that dependency in
the node_modules directory once and creates symbolic links or references
from the respective package directories to the shared dependency.This
approach reduces disk space usage and ensures that common dependencies are
effectively shared among packages without duplication.

Question:
If in node.js application we install 1 package which has a certain
dependency ,if I want to use that package which is installed as dependency
do i need to install it seperately again ?

Answer:
If you have installed a package in your Node.js application and it has a
certain dependency, and you want to use that package installed as
dependency of another package within your application code, you typically
don't need to install that dependency separately. When you install a
package using npm, it automatically installs all its dependencies,
including any transitive dependencies (dependencies of dependencies).
But if that main package got updated & its dependency too then chances
are we have broken code that why it is better to install again that
package.

2024/03/29

Javascript Interview Question:Reverse Number

Given a signed 32-bit integer x, return x with its digits reversed. If reversing
x causes the value to go outside the signed 32-bit integer range
[-231, 231 - 1], then return 0.

Assume the environment does not allow you to store 64-bit integers
(signed or unsigned).


Example 1:

Input: x = 123
Output: 321
Example 2:

Input: x = -123
Output: -321
Example 3:

Input: x = 120
Output: 21

Constraints:
-2**31 <= x <= 2**31 - 1

Solution(converting number to string then reverse):
let x = -123;
var reverse = function (x) {
let reversedAbs= Math.sign(x) * parseInt(Math.abs(x).toString().split('').reverse().join(''))
return ( -1 * 2 ** 31 > reversedAbs || 2 ** 31 - 1 < reversedAbs) ? 0:reversedAbs
};
let reversedAbs = reverse(x);
console.log(reversedAbs);
Output:
-321

Solution(using maths modulo operator):
let x = -123;

var reverse = function (x) {
let y = Math.abs(x);
let reversedAbs = 0;
let lowerBound = -1 * 2 ** 31;
let upperBound = 2 ** 31 - 1;

while (y > 0) {
reversedAbs = reversedAbs * 10 + (y % 10);
if (lowerBound > reversedAbs || upperBound < reversedAbs) {
return 0;
}
y = Math.floor(y / 10);
}
reversedAbs = Math.sign(x) * reversedAbs;

if (lowerBound > reversedAbs || upperBound < reversedAbs) {
return 0;
} else {
return reversedAbs;
}
};
let reversedAbs = reverse(x);
console.log(reversedAbs);
Output:
-321

2024/03/28

JavaScript:Rest vs Spread Operator

JavaScript uses three dots (...) for both the rest and spread operators.
But these two operators are not the same.

what is differtence ?
Rest operator puts the rest of some specific user-supplied values into a
JavaScript array. But the spread syntax expands iterables into individual
elements.

Using rest operator with function parameter.
Code:
function usingRestOperator(firstName, lastName, ...otherInfo) {
return otherInfo;
}
var result = usingRestOperator("santosh", "gawade", "98654534512",
"researcher", "Male");
console.log(result)
Output:
[ '98654534512', 'researcher', 'Male' ]

Explanation:
In above snippet, we used the ...otherInfo rest parameter to put
"98654534512", "researcher", and "Male" into an array.
Note:
we cannot use the “use strict” directive inside any function containing
a rest parameter, default parameter, or destructuring parameter.

Using Rest with Object:
Code:
var userObject = {
firstName: "sangram",
lastName: "desai",
city: "kankavali",
pin: "416602",
};
var {firstName,lastName,...rest} = userObject
console.log(rest)
Output:
{ city: 'kankavali', pin: '416602' }

Using Rest with Array:
Code:
var [firstName,lastName,...otherInfo]=["sangram","desai",
"9890868345","researcher","Male"]
console.log(otherInfo)

Output:
[ '9890868345', 'researcher', 'Male' ]
Spread Operator with function:
Code:
function usingSpreadOperator(firstName, lastName, company) {
return `${firstName} ${lastName} runs ${company}`;
}
// spread operator expands an array items into individual arguments:
usingSpreadOperator(...["sangram", "desai", "kankavali"]);
Explanation:
Here we are pssing array ["sangram", "desai", "kankavali"] as argument
preceeded by '...' i.e. spread operator. Effect of using spread
operator is it convert our array into individual elements.

so usingSpreadOperator(...["sangram", "desai", "kankavali"]) is
effectively same as
usingSpreadOperator("sangram", "desai", "kankavali")
argument object of function and rest operator:

With Normal Function:
Code:
function usingRestOperator(...otherInfo) {
console.log("Arguments:",arguments)
console.log("OtherInfo:",otherInfo)
}
var result = usingRestOperator(
"santosh",
"gawade",
"98654534512",
"researcher",
"Male"
);
Output:
Arguments: [Arguments] {
'0': 'santosh',
'1': 'gawade',
'2': '98654534512',
'3': 'researcher',
'4': 'Male'
}
OtherInfo: [ 'santosh', 'gawade', '98654534512', 'researcher', 'Male' ]

Explanation:
Here rest operator otherInfo & argument have same data though it is
saved bit differently.

Note:
arguments object is not a real array. Instead, it is an array-like
object that does not have the comprehensive features of a regular
JavaScript array.
With Arrow Function:
Code:
let usingRestOperator = (...otherInfo) => {
console.log("Arguments:", arguments);
console.log("OtherInfo:", otherInfo);
};
var result = usingRestOperator(
"santosh",
"gawade",
"98654534512",
"researcher",
"Male"
);

Output:
Arguments: [Arguments] {
//contain some data which not useful here
}
OtherInfo: [ 'santosh', 'gawade', '98654534512', 'researcher', 'Male' ]

Explanation:
The arguments object is not available within an arrow function,
so you can’t use it there. But you can use the rest parameter within
all functions — including the arrow function.



Javascript Interview Question:Find all subsets of an array of specific length

Problem Statement:
For given one dimesional array of numbers find all possible subsets
of that array with specific length.
e.g.
For Array [1,2,3]

If we want to find all subsets of length 2 then
Output should be
[
[1,2],
[1,3],
[2,3]
]

Solution:
function getAllSubsetsOfSpecificLength(array,length) {
const subsets = [[]];
const subsetsOfSpecificLength = [];

for (const el of array) {
const last = subsets.length - 1;
for (let i = 0; i <= last; i++) {
let set = [...subsets[i], el];
subsets.push(set);

if(set.length == length){
subsetsOfSpecificLength.push(set)
}

if(set.length > length){
break;
}
}
}

return subsetsOfSpecificLength;
}
let array = [1, 2, 3];
let result = getAllSubsetsOfSpecificLength(array,2);
console.log(result);

Output:
[ [ 1, 2 ], [ 1, 3 ], [ 2, 3 ] ]

Javascript Interview Question:Convert Array (key,value)of Object to Object

Sample Input:
var input = [
{ key: "foo", val: "bar" },
{ key: "hello", val: "world" },
];

Sample Output:
var output = { foo: 'bar', hello: 'world' }

Solution(1st way):
var arr = [
{ key: "foo", val: "bar" },
{ key: "hello", val: "world" },
];

var result = arr.reduce(function (acc, obj) {
acc[obj.key] = obj.val;
return acc;
}, {});
console.log(result)

Output:
{ foo: 'bar', hello: 'world' }

Solution(2nd Way):
var keyValueObjectArray = [
{ key: "foo", val: "bar" },
{ key: "hello", val: "world" },
];

//array
var keyValueArray = keyValueObjectArray.map((elm) => [elm.key, elm.val]);

//array to map
var keyValueMap = new Map(keyValueArray);

//map to object
var result = {}
for (const [key, value] of keyValueMap) {
result[key] = value
}
console.log(result)

Output:
{ foo: 'bar', hello: 'world' }

Javascript:Convert Array to Object

Sample Input:

var sampleOutput= [
["name",[
["firstName","sangram"],
["midddleName","shivaji"],
["lastName","Desai"]
]
],
["address",[
["street","Naradawe Road"],
["line1","near railway station"],
["line2","behind annapurna hotel"],
["city","kankavali"],
["pin","416602"]
]
]
]

Sample Output:

var sampleInput={
name: {
firstName: "sangram",
midddleName: "shivaji",
lastName: "Desai",
},
address: {
street: "Naradawe Road",
line1: "near railway station",
line2: "behind annapurna hotel",
city: "kankavali",
pin: "416602",
},
};





Solution:
const person = [
[
"name",
[
["firstName", "sangram"],
["midddleName", "shivaji"],
["lastName", "Desai"],
],
],
[
"address",
[
["street", "Naradawe Road"],
["line1", "near railway station"],
["line2", "behind annapurna hotel"],
["city", "kankavali"],
["pin", "416602"],
],
],
];

function convertArrayToObject(person) {
let resultObject = {};
for (let element of person) {
if (Array.isArray(element[1])) {
resultObject[element[0]] = convertArrayToObject(element[1]);
} else {
resultObject[element[0]] = element[1]
}
}
return resultObject;
}

//find result & print
let resultObject = convertArrayToObject(person);
console.log(resultObject);


Output:
{
name: { firstName: 'sangram', midddleName: 'shivaji', lastName: 'Desai' },
address: {
street: 'Naradawe Road',
line1: 'near railway station',
line2: 'behind annapurna hotel',
city: 'kankavali',
pin: '416602'
}
}

Javascript:Convert nexted Object to an array

Sample Input:

var sampleInput={
name: {
firstName: "sangram",
midddleName: "shivaji",
lastName: "Desai",
},
address: {
street: "Naradawe Road",
line1: "near railway station",
line2: "behind annapurna hotel",
city: "kankavali",
pin: "416602",
},
};

Sample Output:
var sampleOutput= [
["name",[
["firstName","sangram"],
["midddleName","shivaji"],
["lastName","Desai"]
]
],
["address",[
["street","Naradawe Road"],
["line1","near railway station"],
["line2","behind annapurna hotel"],
["city","kankavali"],
["pin","416602"]
]
]
]

Solution:
const person = {
name: {
firstName: "sangram",
midddleName: "shivaji",
lastName: "Desai",
},
address: {
street: "Naradawe Road",
line1: "near railway station",
line2: "behind annapurna hotel",
city: "kankavali",
pin: "416602",
},
};
function convertObjectTwoArray(person) {
let resultArray = [];
for (let key in person) {
if ((typeof person[key]).toString() === "object") {
resultArray.push([key, convertObjectTwoArray(person[key])]);
} else {
resultArray.push([key, person[key]]);
}
}
return resultArray;
}
//find result & print
let resultArray = convertObjectTwoArray(person);
console.log( JSON.stringify(resultArray));
Output:

[
["name",[
["firstName","sangram"],
["midddleName","shivaji"],
["lastName","Desai"]
]
],
["address",[
["street","Naradawe Road"],
["line1","near railway station"],
["line2","behind annapurna hotel"],
["city","kankavali"],
["pin","416602"]
]
]
]

Javascript:Omit specific Object properties

How to selecting required properties from object.

Consider following code snippet.Here s contain additional
property,city location that we want to remove.

Solution 1:
Code:
var s = {
name: "sangram",
age: 56,
city:"kankavali",
location: "mumbai",
};

var subset = function ({ name, age }) {
return { name, age };
};

var x = subset(s);
console.log(x);
Output:
{ name: 'sangram', age: 56 }
Explanation:
Here we are passing all properties we want in our derived
object so excluding location & city while pssing remaining
properties name & age.we get a object derived from original
object with only properties that we passed to to function
subset.

Solution 2:

Code:
const foo={
"bar":"sangram",
"baz":"sagar",
"mux":"sachin",
"fch":"swapnil"

}
const { bar,baz, ...qux } = foo
console.log(qux)

Output:
{ mux: 'sachin', fch: 'swapnil' }
Explanation:
Here we are using rest operator as const { bar,baz, ...qux } = foo
we want to omit properties bar & baz so we passed it first then ...qux.
Now qux will get an object derived from foo with all properties except
bar & baz.

2024/03/27

Javascript:Symbol Introduction

The JavaScript ES6 introduced a new primitive data type called Symbol.
Symbols are immutable (cannot be changed) and are unique.

Code:
// two symbols with the same description

const value1 = Symbol('hello');
const value2 = Symbol('hello');
console.log(value1 === value2); // false

Creating Symbol:
Symbol() function is used to create a Symbol.

Code:
// creating symbol
const x = Symbol()
typeof x; // symbol

An optional string can be passed as its description in to Symbol() function:

Code:
const x = Symbol('hey');
console.log(x); // Symbol(hey)

Access Symbol Description:
To access the description of a symbol, we use the . operator.

Code:
const x = Symbol('hey');
console.log(x.description); // hey

Using Symbol as Object Key:
You can add symbols as a key in an object using square brackets [].

Code:
let id = Symbol("id");
let person = {
name: "Jack",

// adding symbol as a key
[id]: 123 // not "id": 123
};
console.log(person); // {name: "Jack", Symbol(id): 123}

Symbolic Properties of object are not iterable:

Code;
let id = Symbol("id");
let person = {
name: "Jack",
age: 25,
[id]: 12
};
// using for...in
for (let key in person) {
console.log(key);
}
Output:
name
age

Mixing Symbol & string of same name in object key:

Code:
let person = {
name: "Jack",
};

// creating Symbol
let id = Symbol("id");

// adding symbol as a key
person[id] = 12;
person["id"] = 786;

console.log(person[id])
console.log(person['id'])
Output:
12
786

Symbol Methods:
There are various methods available with Symbol.

Below is list of common symbol methods.
1) for():Searches for existing symbols
2) keyFor():Returns a shared symbol key from the global symbol registry.
3) toSource():Returns a string containing the source of the Symbol object
4) toString():Returns a string containing the description of the Symbol
5) valueOf():Returns the primitive value of the Symbol object.


Code:
// get symbol by name
let sym = Symbol.for('hello');
let sym1 = Symbol.for('id');

// get name by symbol
console.log( Symbol.keyFor(sym) ); // hello
console.log( Symbol.keyFor(sym1) ); // id

Symbol Properties:
Here is list of common symbol properties & there description.

1) asyncIterator:Returns the default AsyncIterator for an object
2) hasInstance:Determines if a constructor object recognizes an object as
its instance
3) isConcatSpreadable:Indicates if an object should be flattened to its
array elements
4) iterator:Returns the default iterator for an object
5) match:Matches against a string
6) matchAll:Returns an iterator that yields matches of the regular
expression against a string
7) replace:Replaces matched substrings of a string
8) search:Returns the index within a string that matches the regular
expression
9) split:Splits a string at the indices that match a regular expression
10) species:Creates derived objects
11) toPrimitive:Converts an object to a primitive value
12) toStringTag:Gives the default description of an object
13) description:Returns a string containing the description of the symbol

Code:
const x = Symbol('hey');

// description property
console.log(x.description); // hey

const stringArray = ['a', 'b', 'c'];
const numberArray = [1, 2, 3];

// isConcatSpreadable property
numberArray[Symbol.isConcatSpreadable] = false;

let result = stringArray.concat(numberArray);
console.log(result); // ["a", "b", "c", [1, 2, 3]]

Javascript : Object.groupBy & Object.groupByMap

Object.groupBy():
The Object.groupBy() static method groups the elements of a given
iterable according to the string values returned by a provided callback
function.

The returned object has separate properties for each group, containing
arrays with the elements in the group.

Code:
require("core-js");

const inventory = [
{ name: "asparagus", type: "vegetables", quantity: 5 },
{ name: "raddish", type: "vegetables", quantity: 5 },
{ name: "bananas", type: "fruit", quantity: 0 },
{ name: "goat", type: "meat", quantity: 23 },
{ name: "cherries", type: "fruit", quantity: 5 },
{ name: "fish", type: "meat", quantity: 22 },
];

//TypeError: Object.groupBy is not a function if core-js not included
//in Node-v20.5.1

//group inventory elements based on type
var result = Object.groupBy(inventory, (item) => {
return item.type;
});
console.log(result);

Output:
[Object: null prototype] {
vegetables: [
{ name: 'asparagus', type: 'vegetables', quantity: 5 },
{ name: 'raddish', type: 'vegetables', quantity: 5 }
],
fruit: [
{ name: 'bananas', type: 'fruit', quantity: 0 },
{ name: 'cherries', type: 'fruit', quantity: 5 }
],
meat: [
{ name: 'goat', type: 'meat', quantity: 23 },
{ name: 'fish', type: 'meat', quantity: 22 }
]
}
Explanation:
Object.groupBy() return a null-prototype object with properties for
all groups, each assigned to an array containing the elements of the
associated group.Almost all objects in JavaScript ultimately inherit
from Object.prototype. However, you may create null-prototype
objects.
With array.groupBy you can create groups using arbitrary keys. The result is
an regular JavaScript object:

Code:
require("core-js");

const inventory = [
{ name: "asparagus", type: "vegetables", quantity: 5 },
{ name: "raddish", type: "vegetables", quantity: 5 },
{ name: "bananas", type: "fruit", quantity: 0 },
{ name: "goat", type: "meat", quantity: 23 },
{ name: "cherries", type: "fruit", quantity: 5 },
{ name: "fish", type: "meat", quantity: 22 },
];

//group inventory element based on if it is veg or non-veg
const result2 = inventory.groupBy((item) => {
return item.type == "meat" ? "Non-Veg" : "Veg";
});
console.log(result2);
console.log(result2["Veg"]);
Output:
[Object: null prototype] {
Veg: [
{ name: 'asparagus', type: 'vegetables', quantity: 5 },
{ name: 'raddish', type: 'vegetables', quantity: 5 },
{ name: 'bananas', type: 'fruit', quantity: 0 },
{ name: 'cherries', type: 'fruit', quantity: 5 }
],
'Non-Veg': [
{ name: 'goat', type: 'meat', quantity: 23 },
{ name: 'fish', type: 'meat', quantity: 22 }
]
}
[
{ name: 'asparagus', type: 'vegetables', quantity: 5 },
{ name: 'raddish', type: 'vegetables', quantity: 5 },
{ name: 'bananas', type: 'fruit', quantity: 0 },
{ name: 'cherries', type: 'fruit', quantity: 5 }
]

Note:
The array.groupByToMap method also let us create groups using arbitrary
keys,but it allows you to use complex types (i.e. objects) as keys.
The result is a Map:

Using Object destructing with groupBy:
Code:
require("core-js");

const inventory = [
{ name: "asparagus", type: "vegetables", quantity: 5 },
{ name: "raddish", type: "vegetables", quantity: 5 },
{ name: "bananas", type: "fruit", quantity: 0 },
{ name: "goat", type: "meat", quantity: 23 },
{ name: "cherries", type: "fruit", quantity: 5 },
{ name: "fish", type: "meat", quantity: 22 },
];

//group inventory element based on if it is veg or non-veg
const {Veg,NonVeg} = inventory.groupBy((item) => {
return item.type == "meat" ? "NonVeg" : "Veg";
});
console.log(Veg)
Output:
[
{ name: 'asparagus', type: 'vegetables', quantity: 5 },
{ name: 'raddish', type: 'vegetables', quantity: 5 },
{ name: 'bananas', type: 'fruit', quantity: 0 },
{ name: 'cherries', type: 'fruit', quantity: 5 }
]

Object.groupByToMap():
Object.groupByToMap() static method groups the elements in an array using the
values returned by its callback function. It returns a Map with the unique
values from the callback function as keys, which can be used to access the
array of elements in each group.

Complex types, such as objects, can be used as keys with the groupToMap()
method.

Code:
require("core-js");

const ATHLETES = [
{
name: "Blessing Ogabere",
nationality: "Nigerian",
age: 26,
height: "78ft",
},
{
name: "Usain Bolt",
nationality: "Jamican",
age: 29,
height: "82ft",
},
{
name: "Fred KERLEY",
nationality: "USA",
age: 16,
height: "82ft",
},
{
name: "Oblique SEVILLE",
nationality: "Jamican",
age: 17,
height: "82ft",
},
];
const eligible = { eligible: true };
const ineligible = { ineligible: true };

const eligibilityResult = ATHLETES.groupByToMap((athlete, index, array) => {
return athlete.age > 18 ? eligible : ineligible;
});

console.log(eligibilityResult);
console.log(eligibilityResult.get(eligible));

Output:
Map(2) {
{ eligible: true } => [
{
name: 'Blessing Ogabere',
nationality: 'Nigerian',
age: 26,
height: '78ft'
},
{
name: 'Usain Bolt',
nationality: 'Jamican',
age: 29,
height: '82ft'
}
],
{ ineligible: true } => [
{
name: 'Fred KERLEY',
nationality: 'USA',
age: 16,
height: '82ft'
},
{
name: 'Oblique SEVILLE',
nationality: 'Jamican',
age: 17,
height: '82ft'
}
]
}
[
{
name: 'Blessing Ogabere',
nationality: 'Nigerian',
age: 26,
height: '78ft'
},
{
name: 'Usain Bolt',
nationality: 'Jamican',
age: 29,
height: '82ft'
}
]
Explanation:
The code above uses groupToMap() with an arrow function that returns the
object keys named eligible or ineligible, depending on whether the element
has an age greater than 18. The returned result object is a Map.

In order to obtain an array from a Map we need to call get() with the key to
obtain the array:

Finding number of occurences of word in sentence using groupToMap():
Code:
require("core-js");
const text = "knock knock chop chop buffalo buffalo buffalo";
const words = text.split(" ");

//groupMap variable is map object it groups words
const groupMap = words.groupToMap((word) => word);

//create an array from map object
const wordArray = Array.from(groupMap);

//find count of each word
const wordCount = wordArray.map((m) => {
return [m[0], m[1].length];
});
let wordMap = new Map(wordCount)

//get how many time word "knock" occured.
console.log(wordMap.get("knock"))
Output:
2


Differences between the groupBy and groupToMap methods:

groupBy groupToMap
This returns a new object where each
key is the different keys you sorted with
This returns a Map with the unique
values from the callback function as keys,
which can be used to access the array of elements
in each group
The results returned can be accessed using
the different values that have now been set as keys,
just like in a regular object
The results returned can be accessed using
the get method available in Maps
The values of the key specified for the sorting
are used to
group the array
The custom value you have created is used to group
the array
This does not require a conditional to sort the array This requires a conditional to group the array


Javascript Regular Expression:Named Capturing Group

Numbered capture groups allow one to refer to certain portions of a string
that a regular expression matches. Each capture group is assigned a unique
number and can be referenced using that number, but this can make a regular
expression hard to grasp and refactor.

For example, given /(\d{4})-(\d{2})-(\d{2})/ that matches a date, one cannot
be sure which group corresponds to the month and which one is the day without
examining the surrounding code. Also, if one wants to swap the order of the
month and the day, the group references should also be updated.

Code:
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
let result = re.exec("2015-01-02");
console.log(result);

//accesing by name
console.log("year:" + result.groups.year);
console.log("month:" + result.groups.month);
console.log("day:" + result.groups.day);

//accesing by numberic index
console.log("year:" + result[1]);
console.log("month:" + result[2]);
console.log("day:" + result[3]);
Output:
[
'2015-01-02',
'2015',
'01',
'02',
index: 0,
input: '2015-01-02',
groups: [Object: null prototype] {
                    year: '2015',
                    month: '01',
                    day: '02'
                }
]
year:2015
month:01
day:02
year:2015
month:01
day:02


Explanation:
Named groups can be accessed from properties of a groups property of
the regular expression result. Numbered references to the groups are
also created, just as for non-named groups.

Note:
/u in the pattern at the end enable full Unicode matching.It's
important to note that the \u escape sequence is specific to
JavaScript regular expressions and is not part of the broader regular
expression syntax used in other programming languages or tools.

Named Group & Replacement Target:
Named groups can be referenced from the replacement value passed to
String.prototype.replace too. If the value is a string, named groups
can be accessed using the $<name> syntax.

Code:
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
let result = '2015-01-02'.replace(re, '$<day>/$<month>/$<year>');
console.log(result)
Output:
02/01/2015

Named Capturing Group & Back Reference:
A named group can be accessed within a regular expression via the \k<name>
construct.
For example

Code:
let duplicate = /^(?<half>.*).\k<half>$/u;
console.log(duplicate.test('a*b')); // false
console.log(duplicate.test('a*a')); // true
console.log(duplicate.test('abc*abc')); // true
console.log(duplicate.test('abc=abc')); // true
console.log(duplicate.test('abc==abc')); // false
console.log(duplicate.test('abc:=abc')); // false
console.log(duplicate.test('aaaaaaa')); // true
Output:
false
true
true
true
false
false
true
Note:
Basically regular expression /^(?<half>.*).\k<half>$/u; stands for
1) Any character any number of time e.g. say 'abc'
2) Followed by any character e.g. say '='
3) Followed by same sequence of charcters in 1st condition.then it
should be same as 1st condition so 'abc' again

so final string will be abc=abc


Back Reference with Named Capturing Group & Numbered References:
Named references can also be used simultaneously with numbered references.

Code:
let triplicate = /^(?<part>.*).\k<part>.\1$/u;
       // all three parts should be same hence true
console.log(triplicate.test('a*a*a'));
// all three parts are not same hence false
console.log(triplicate.test('a*a*b'));

//here seperator is same char and all three parts are same abc
console.log(triplicate.test('abc*abc*abc'));

/*no need to have same seperator char but all
three parts need to be same abc*/
console.log(triplicate.test('abc*abc#abc'));
Output:
true
false
true
true


Javascript Regular Expression : Positive Look Ahead

 


JavaScript allows you to specify that a portion of a regular expression matches
only if it is or is not followed by a particular subexpression. The (?=) syntax
specifies a positive lookahead; it only matches the previous item if the item
is followed immediately by the expression contained in (?=). The lookahead
expression is not included in the match.


lets suppose you want to match all those USD characters which are
followed by some digits. Simply you want to match all those USD
characters which are immediately followed by numbers for example
you want to match

Code:
//positive look ahead
var line ="USD 100 USD 350 USD 345.56 USD currency USD rate"
var pattern=/USD(?=\s\d+\.{0,}\d+)/gm

var result = line.match(pattern)
console.log(result)

var lastIndex
while ((match = pattern.exec(line))) {
lastIndex = match.index;
console.log("Occurance At:" + lastIndex)
}

Output:
[ 'USD', 'USD', 'USD' ]
Occurance At:0
Occurance At:8
Occurance At:16

Explanation:
Here first the engine will search for U after finding U upper case the
engine will look for S if it finds it will see if it is immediately
followed by D.

In case of a USD match the engine will enter lookahead and finds that it
is a positive lookahead and in this look ahead there is a space followed
by an optional number one or more quantifier then an optional dot and
after dot there is one or more digits.

This regex will match all USD words followed by a number of one or more
digits.

2024/03/26

Javascript : null & undefined

In JavaScript, null is a value that represents the intentional absence of any
object value. It is technically a primitive type, although in some cases
it behaves as an object.

undefined means the variable has not been assigned a value yet.

Checking for null:
You can check whether a value is null using the === operator:
Code:
var s= null;
if(s===null){
console.log('s is null')
}
Output:
s is null

If variable 's' is null or undefined then == return true.
Code:
if(s==null){
console.log('s is null or undefined')
}
Output:
s is null or undefined

null vs undefined:
undefined means the variable has not been assigned a value yet,
whereas null means the variable has been explicitly defined as null

null & undefined together termed as nullish value.

Nullish value vs Non-nullish value:
Nullish values are different from non-nullish values in that
nullish values throw a TypeError when you try to access one of
their properties, whereas non-nullish values do not.

Code:
let v = 42;
console.log(v.test); // undefined

v = null;
v.test; // Throws `TypeError: Cannot read property 'test' of null`

v = undefined;
v.test; // Throws `TypeError: Cannot read property 'test' of undefined`

Arithmetic Operations on null:
During mathematical operation javaScript converts null to 0.

consider following code.
Code:
console.log(2 + null); // 2
console.log(null + 2); // 2

console.log(2 - null); // 2
console.log(null - 2); // -2

console.log(2 * null); // 0
console.log(null * 2); // 0

console.log(2 ** null); // 1
console.log(0 ** 2); // 0

console.log(null / 2); // 0
Output:
2
2
2
-2
0
0
1
0
0

Arithmetic Operation on undefined:
Result of any arithmetic operation on undefined is always NaN.
Code:
console.log(2 + undefined); // NaN
console.log(2 * undefined); // NaN
console.log(2 - undefined); // NaN
console.log(2 ** undefined); // NaN
console.log(2 / undefined); // NaN

console.log(undefined + 2); // NaN
console.log(undefined - 2); // NaN
console.log(undefined * 2); // NaN
console.log(undefined / 2); // NaN
console.log(undefined ** 2); // NaN
Output:
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN

Applying typeof operator on null
Code:
var s = null
console.log(typeof s)
Output:
object

Why typeof null is an object?
It was a historial mistake.In the early versions of JavaScript, the
language used a 32-bit system to store values. These bits were divided
into two parts: the type tag and the data value.The type tag for objects
was 000, which corresponds to the binary value 000 in the least significant
bits.The type tag for null was also 000,leading to the confusion and the
typeof null returning "object".

Checking if variable is not null but object:
Code:
function isObject(v) {
return typeof v === "object" && v !== null;
}

var t = {
name: "sangram",
};

if(isObject(t)){
console.log('t is object')
}

var s = null
if(!isObject(s)){
console.log('s is not an object')
}

Output:
t is object
s is not an object
Explanation:
1)isObject() function return true if passed variable has not null value &
it's type is object.

2)isObject() function return false if passed variable has null value or
it's type not object.

Applying typeof operator on null
Code:
var t = undefined
console.log(typeof t)
Output:
undefined

Concatenation:

when we concat a variable with null value or variable with undefined value,
first toString() method is called on this variables.toString() for variable
with null value is 'null' string.toString() for variable with undefined
value is 'undefined' string.

string concatenation on null:
Code:
var s = null
console.log(s+ 'some value')
console.log('some value' + s)
Output:
nullsome value
some valuenull

string concatenation on undefined:
Code:
var s = undefined
console.log('some value' + s)
console.log(s + 'some value')
Output:
some valueundefined
undefinedsome value

Comparing two null variables:
Code:
var s =null;
var t =null;
if(s===t){
console.log("Equal")
}else{
console.log("Not Equal")
}
Output:
Equal

Comparing two undefined variables:
Code:
var s =undefined;
var t =undefined;
if(s===t){
console.log("Equal")
}else{
console.log("Not Equal")
}
Output:
Equal

Javascript : Constructor Function

Constructor Function:
In JavaScript, a constructor function is a special type of
function that is used to create and initialize objects.

Constructor functions are primarily used in conjunction with
the new keyword to create instances of a particular type of
object, often referred to as instances of a class

Lets see by Examples:

Code:

function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
this.start = function() {
console.log(`${this.make} ${this.model} (${this.year})
is starting.`);
};
}
const myCar = new Car('Toyota', 'Camry', 2020);
console.log(myCar.make); // Output: Toyota
myCar.start();

Explanation:

A constructor function is defined using the function keyword followed by a
name typically starting with a capital letter to distinguish it from regular
functions. Inside the constructor function, properties and methods can be
defined using this.

In above code it is done as follows.

function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
this.start = function() {
console.log(`${this.make} ${this.model} (${this.year}) is
starting.`);
};
}


Instances (objects) of a constructor function are created using the
new keyword followed by the constructor function name and arguments
(if any).In above code it is done as follows

const myCar = new Car('Toyota', 'Camry', 2020);

Each instance created from a constructor function has its own set of
properties and methods defined within the constructor function. These
properties and methods are accessible using dot notation.

In above code it is done as follows

console.log(myCar.make); // Output: Toyota
myCar.start();

Here myCar.start() is method while myCar.make is property.

Using prototype to add property or method:
JavaScript constructor functions also have a prototype property, which can
be used to add methods or properties that are shared among all instances
created from the constructor.Method added using prototype use its own instance
properties when running itself.

It is done as follows.
Car.prototype.stop = function() {
console.log(`${this.make} ${this.model} (${this.year}) is stopping.`);
};

Now to call the property just added above we call can call it on any instance
of object.

like below.

myCar.stop(); // Output: Toyota Camry (2020) is stopping.

Constructor Function are often used to create reusable templates for
creating multiple objects with similar properties and behaviors.


Create Objects: Constructor Function Vs Object Literal:
Object Literal is generally used to create a single object.
The constructor function is useful if you want to create
multiple objects. For example,

using object literal:
Code :
let person = {
name: 'Sam'
}
let student = person;
// changes the property of an object
student.name = 'John';

// changes the origins object property
console.log(person.name); // John
Output:
John

Explanation:
if an object is created with an object literal, and if a variable is
defined with that object value, any changes in variable value will
change the original object.

using constructor function
Code:
function Person () {
this.name = 'Sam'
}
let person1 = new Person();
let person2 = new Person();

// adding new property to person1
person1.age = 20;
console.log(person1.age)
console.log(person2.age)
Output:
20
undefined

Explanation:
Each object created from the constructor function is unique.
You can have the same properties as the constructor function
or add a new property to one particular object.
age property is unique to person1 object and is not available to
person2.

Replacing Constructor function by factory function:

Below Car function is a factory function rather than a constructor
function.

Consider Code below:

Code:
function Car(make, model, year) {
let propertyBag = {};
propertyBag.make = make;
propertyBag.model = model;
propertyBag.year = year;
propertyBag.start = function () {
console.log(`${propertyBag.make} ${propertyBag.model}
(${propertyBag.year}) is starting.`);
}
return propertyBag;
}
const myCar =Car("Toyota", "Camry", 2020);
console.log(myCar.make); // Output: Toyota
myCar.start();

const myIndianCar = Car("Mahindra", "Thar", 2024);
console.log(myIndianCar.make); // Output: Toyota
myIndianCar.start();
Output:
Toyota
Toyota Camry (2020) is starting.
Mahindra
Mahindra Thar (2024) is starting.

Note:
we are not using this in Car function,nor does we are using new to create
Object of Car.Attempt to add another function to Car after creation of
function doesn't work.

What is been tried?
Car.prototype.stop = function () {
console.log(`${this.make} ${this.model} (${this.year}) is
stopping.`);
};
myIndianCar.stop();

we get error that myIndianCar.stop is not a function.


Scenario where we want a clean slate without any inherited properties or
methods:

we can go like this
Code:
const obj = Object.create(null); // Create an object with null prototype
console.log(obj); // Output: [Object: null prototype] {}

Explanation:
In this example, we create an object obj using Object.create(null). By
passing null to Object.create, we explicitly set the prototype of obj to
null, resulting in an object with no prototype chain.

However, keep in mind that objects with null prototypes don't have access
to standard prototype methods or properties like toString, hasOwnProperty,
etc., because they don't inherit from Object.prototype.

If you need to create objects with custom prototypes or inherit from
built-in prototypes, you would typically use constructor functions or
object literals with prototype inheritance.

JavaScript Built-in Constructors:
JavaScript also has built-in constructors. Some of them are:

let a = new Object(); // A new Object object
let b = new String(); // A new String object
let c = new Number(); // A new Number object
let d = new Boolean(); // A new Boolean object


e.g.
const name = new String ('John');
console.log(name); // "John"

const number = new Number (57);
console.log(number); // 57

const count = new Boolean(true);
console.log(count); // true

let a = new Object({
"firstName":"sangram",
"lastName":"desai"
});
console.log(a)//{ firstName: 'sangram', lastName: 'desai' }