Javascript
Javascript
Ans: To know the type of a JavaScript variable, we can use the typeof operator.
Primitive types
String - It represents a series of characters and is written with quotes. A string
can be represented using a single or a double quote.
Example :
var str = "Vivek Singh Bisht"; //using double quotes
var str2 = 'John Doe'; //using single quotes
BigInt - This data type is used to store numbers which are above the limitation of
the Number data type. It can store large integers
and is represented by adding “n” to an integer literal.A BigInt value, also
sometimes just called a BigInt, is a bigint primitive, created by appending n to
the end of an integer literal, or by calling the BigInt() constructor (but without
the new operator) and giving it an integer value or string value.
Example :
var bigInteger = 234567890123456789012345678901234567890n;
const previouslyMaxSafeInteger = 9007199254740991n;
const alsoHuge = BigInt(9007199254740991);
typeof 1n === 'bigint' // true
typeof BigInt('1') === 'bigint' // true
A BigInt value can also be wrapped in an Object:
typeof Object(1n) === 'object' // true
Boolean - It represents a logical entity and can have only two values : true or
false. Booleans are generally used for conditional testing.
Example :
var a = 2;
var b = 3;
var c = 2;
(a == b) // returns false
(a == c) //returns true
Undefined - When a variable is declared but not assigned, it has the value of
undefined and it’s type is also undefined.
Example :
var x; // value of x is undefined
typeof x; //undefined;
var y = undefined; // we can also set the value of a variable as undefined
typeof y; //undefined;
Non-primitive types
Primitive data types can store only a single value. To store multiple and complex
values, non-primitive data types are used.
Object - Used to store collection of data.
Example:
// Collection of data in key-value pairs
var obj1 = {
x: 43,
y: "Hello world!",
z: function(){
return this.x;
}
}
// Collection of data as an ordered list
var array1 = [5, "Hello", true, 4.1];
*Note- It is important to remember that any data type that is not primitive data
type, is of Object type in javascript.
Example 1:
hoistedVariable = 3;
console.log(hoistedVariable); // outputs 3 even when the variable is declared after
it is initialized
var hoistedVariable;
Example 2:
hoistedFunction(); // Outputs " Hello world! " even when the function is declared
after calling
function hoistedFunction(){
console.log(" Hello world! ");
}
Example 3:
// Hoisting takes place in the local scope as well
function doSomething(){
x = 33;
console.log(x);
var x;
}
doSomething(); // Outputs 33 since the local variable “x” is hoisted inside the
local scope
**Note - Variable initializations are not hoisted, only variable declarations are
hoisted:
var x;
console.log(x); // Outputs "undefined" since the initialization of "x" is not
hoisted
x = 23;
**Note - To avoid hoisting, you can run javascript in strict mode by using “use
strict” on top of the code:
"use strict";
x = 23; // Gives an error since 'x' is not declared
var x;
String coercion
String coercion takes place while using the ‘ + ‘ operator. When a number is added
to a string, the number type is always
converted to the string type.
Example 1:
var x = 3;
var y = "3";
x + y // Returns "33"
Example 2:
var x = 24;
var y = "Hello";
x + y // Returns "24Hello";
**Note - ‘ + ‘ operator when used to add two numbers, outputs a number. The same ‘
+ ‘ operator when used to add two strings,
outputs the concatenated string:
var name = "Vivek";
var surname = " Bisht";
Let’s understand both the examples where we have added a number to a string,
When JavaScript sees that the operands of the expression x + y are of different
types ( one being a number type and the other
being a string type ) , it converts the number type to the string type and then
performs the operation. Since after conversion,
both the variables are of string type, the ‘ + ‘ operator outputs the concatenated
string “33” in the first example and “24Hello”
in the second example.
**Note - Type coercion also takes place when using the ‘ - ‘ operator, but the
difference while using ‘ - ‘ operator is that,
a string is converted to a number and then subtraction takes place.
var x = 3;
Var y = "3";
x - y //Returns 0 since the variable y (string type) is converted to a number
type
Boolean Coercion
Boolean coercion takes place when using logical operators, ternary operators, if
statements and loop checks. To understand
boolean coercion in if statements and operators, we need to understand truthy and
falsy values.
Truthy values are those which will be converted (coerced) to true . Falsy values
are those which will be converted to false.
All values except 0, 0n, -0, “”, null, undefined and NaN are truthy values.
If statements:
Example:
var x = 0;
var y = 23;
if(x) { console.log(x) } // The code inside this block will not run since the
value of x is 0(Falsy)
if(y) { console.log(y) } // The code inside this block will run since the value
of y is 23 (Truthy)
Logical operators:
Logical operators in javascript, unlike operators in other programming languages,
do not return true or false.
They always return one of the operands.
OR ( | | ) operator - If the first value is truthy, then the first value is
returned. Otherwise, always the second value gets returned.
AND ( && ) operator - If both the values are truthy, always the second value is
returned. If the first value is falsy
then the first value is returned or if the second value is falsy then the second
value is returned.
Example:
var x = 220;
var y = "Hello";
var z = undefined;
x | | y // Returns 220 since the first value is truthy
x | | z // Returns 220 since the first value is truthy
x && y // Returns "Hello" since both the values are truthy
y && z // Returns undefined since the second value is falsy
if( x && y ){
console.log("Code runs" ); // This block runs because x && y returns "Hello"
(Truthy)
}
if( x || z ){
console.log("Code runs"); // This block runs because x || y returns 220(Truthy)
}
Equality Coercion
Equality coercion takes place when using ‘ == ‘ operator. As we have stated before
The ‘ == ‘ operator compares values and not types.
While the above statement is a simple way to explain == operator, it’s not
completely true
The reality is that while using the ‘==’ operator, coercion takes place.
The ‘==’ operator, converts both the operands to the same type and then compares
them.
Example:
var a = 12;
var b = "12";
a == b // Returns true because both 'a' and 'b' are converted to the same type and
then compared. Hence the operands are equal.
Coercion does not take place when using the ‘===’ operator. Both operands are not
converted to the same type in the case of ‘===’ operator.
Example:
var a = 226;
var b = "226";
a === b // Returns false because coercion does not take place and the operands are
of different types. Hence they are not equal.
Assign operator behaves differently when dealing with primitive and non primitive
data types,
var y = 234;
var z = y;
In the above example, assign operator knows that the value assigned to y is a
primitive type (number type in this case), so when the
second line code executes, where the value of y is assigned to z, the assign
operator takes the value of y (234) and allocates a new
space in the memory and returns the address. Therefore, variable z is not pointing
to the location of variable y, instead it is
pointing to a new location in the memory.
From the above example, we can see that primitive data types when passed to another
variable, are passed by value. Instead of just
assigning the same address to another variable, the value is passed and new space
of memory is created.
In the above example, the assign operator, directly passes the location of the
variable obj to the variable obj2. In other words,
the reference of the variable obj is passed to the variable obj2.
var obj = #8711; // obj pointing to address of { name: "Vivek", surname: "Bisht" }
var obj2 = obj;
var obj2 = #8711; // obj2 pointing to the same address
// changing the value of obj1
obj1.name = "Akki";
console.log(obj2);
// Returns {name:"Akki", surname:"Bisht"} since both the variables are pointing to
the same address.
From the above example, we can see that while passing non-primitive data types, the
assign operator directly passes the address (reference).
Therefore, non-primitive data types are always passed by reference.
To understand IIFE, we need to understand the two sets of parentheses which are
added while creating an IIFE :
First set of parenthesis:
(function (){
//Do something;
})
While executing javascript code, whenever the compiler sees the word “function”, it
assumes that we are declaring a function in the code.
Therefore, if we do not use the first set of parentheses, the compiler throws an
error because it thinks we are declaring a function,
and by the syntax of declaring a function, a function should always have a name.
function() {
//Do something;
}
// Compiler gives an error since the syntax of declaring a function is wrong in the
code above.
To remove this error, we add the first set of parenthesis that tells the compiler
that the function is not a function declaration,
instead, it’s a function expression.
From the definition of an IIFE, we know that our code should run as soon as it is
defined. A function runs only when it is invoked.
If we do not invoke the function, the function declaration is returned:
(function (){
// Do something;
})
// Returns the function declaration
Therefore to invoke the function, we use the second set of parenthesis.
Ques: Explain Higher Order Functions in javascript.
Functions that operate on other functions, either by taking them as arguments or by
returning them, are called higher-order functions.
function higherOrder2() {
return function() {
return "Do something";
}
}
var x = higherOrder2();
x() // Returns "Do something"
myObject.myMethod([1, 2, 3]);
Ex: 2
'use strict';
doSomething();
What do you think the output of the above code will be?
Therefore, the output of the above code will be the global object. Since we ran the
above code inside the browser,
the global object is the window object.
Example 2:
var obj = {
name: "vivek",
getName: function(){
console.log(this.name);
}
}
obj.getName();
In the above code, at the time of invocation, the getName function is a property of
the object obj , therefore, the
this keyword will refer to the object obj , and hence the output will be “vivek”.
Example 3:
var obj = {
name: "vivek",
getName: function(){
console.log(this.name);
}
Although the getName function is declared inside the object obj , at the time of
invocation, getName() is a property of obj2 ,
therefore the “this” keyword will refer to obj2 .
The silly way to understanding the this keyword is, whenever the function is
invoked, check the object before the dot .
The value of this . keyword will always be the object before the dot .
If there is no object before the dot like in example1, the value of this keyword
will be the global object.
Example 4:
var obj1 = {
address : "Mumbai,India",
getAddress: function(){
console.log(this.address);
}
}
call() method allows an object to use the method (function) of another object.
Example 2:
var person = {
age: 23,
getAge: function(){
return this.age;
}
}
function saySomething(message){
return this.name + " is " + message;
}
saySomething.call(person4, "awesome");
// Returns "John is awesome"
apply()
The apply method is similar to the call() method. The only difference is that,
call() method takes arguments separately whereas, apply() method takes arguments as
an array.
function saySomething(message){
return this.name + " is " + message;
}
var person4 = {name: "John"};
saySomething.apply(person4, ["awesome"]);
bind()
This method returns a new function, where the value of “this” skeyword will be
bound to the owner object, which is provided as a parameter.
Example with arguments:
var bikeDetails = {
displayDetails: function(registrationNumber,brandName){
return this.name+ " , "+ "bike details: "+ registrationNumber + " , " +
brandName;
}
}
detailsOfPerson1();
// Returns Vivek, bike details: TS0452, Thunderbird
For Example, if we have a function f(a,b) , then the function after currying, will
be transformed to f(a)(b).
function multiply(a,b){
return a*b;
}
function currying(fn){
return function(a){
return function(b){
return fn(a,b);
}
}
}
Global Scope
Local or Function Scope
Block Scope
Global Scope
Variables or functions declared in the global namespace have global scope, which
means all the variables and functions having global
scope can be accessed from anywhere inside the code
Function Scope
function awesomeFunction(){
var a = 2;
Block Scope
Block scope is related to the variables declared using let and const. Variables
declared with var do not have block scope.
Block scope tells us that any variable declared inside a block { }, can be accessed
only inside that block and cannot be accessed outside of it.
{
let x = 45;
}
Scope Chain
JavaScript engine also uses Scope to find variables.
Let’s understand that using an example:
var y = 24;
function favFunction(){
var x = 667;
var anotherFavFunction = function(){
console.log(x); // Does not find x inside anotherFavFunction, so looks for
variable inside favFunction, outputs 667
}
var yetAnotherFavFunction = function(){
console.log(y); // Does not find y inside yetAnotherFavFunction, so looks for
variable inside favFunction and does not find it,
so looks for variable in global scope, finds it and outputs 24
}
anotherFavFunction();
yetAnotherFavFunction();
}
favFunction();
As you can see in the code above, if the javascript engine does not find the
variable in local scope, it tries to check
for the variable in the outer scope.
If the variable does not exist in the outer scope, it tries to find the variable in
the global scope.
If the variable is not found in the global space as well, reference error is
thrown.
obj = function();
obj.getA(); //print 2
obj.setA(10); //set value 10
obj.getA(); //print 10
Closure is having the capability to have some data which will be closed inside the
function, it will be closed in a way
that only references that you are creating will be able to operate on the data
inside the function.
This can be related with private variable concept of java or c++.
Other explanation:
function randomFunc(){
var obj1 = {name:"Vivian", age:45};
return function(){
console.log(obj1.name + " is "+ "awesome"); // Has access to obj1 even when the
randomFunc function is executed
}
}
initialiseClosure();
The function randomFunc() gets executed and returns a function when we assign it to
a variable:
initialiseClosure();
The line of code above outputs “Vivian is awesome” and this is possible because of
closure.
When the function randomFunc() runs, it sees that the returning function is using
the variable obj1 inside it:
This ability of a function to store a variable for further reference even after it
is executed, is called Closure.
For example,
Date objects inherit properties from the Date prototype
Math objects inherit properties from the Math prototype
Array objects inherit properties from the Array prototype.
On top of the chain is Object.prototype. Every prototype inherits properties and
methods from the Object.prototype.
A prototype is a blueprint of an object. Prototype allows us to use properties and
methods on an object even if the properties and methods
do not exist on the current object.
In the code above, as one can see, we have not defined any property or method
called push on the array “arr”
but the javascript engine does not throw an error.
The reason being the use of prototypes. As we discussed before, Array objects
inherit properties from the Array prototype.
The javascript engine sees that the method push does not exist on the current array
object and therefore,
looks for the method push inside the Array prototype and it finds the method.
Whenever the property or method is not found on the current object, the javascript
engine will always try to look in its prototype
and if it still does not exist, it looks inside the prototype's prototype and so
on.
var c = {
y: 30,
__proto__: a
}
console.log(b);
console.log(a);
console.log(p);
console.log(q);
//inherited property of x
Foo.prototype.x = 10;
);
If a prototype is not specified for an object explicitly, then the default value
for __proto__ is taken — Object.prototype.
Object Object.prototype itself also has a __proto__, which is the final link of a
chain and is set to null.
This figure again shows that every object has a prototype. Constructor function Foo
also has its own __proto__ which is Function.prototype,
and which in turn also references via its __proto__ property again to the
Object.prototype. Thus, repeat, Foo.prototype is just an explicit
property of Foo which refers to the prototype of b and c objects.
Functions that are used as an argument to another function are called callback
functions.
Example:
function divideByHalf(sum){
console.log(Math.floor(sum / 2));
}
function multiplyBy2(sum){
console.log(sum * 2);
}
function operationOnSum(num1,num2,operation){
var sum = num1 + num2;
operation(sum);
}
Ques:What is memoization?
Memoization is a form of caching where the return value of a function is cached
based on its parameters. If the parameter of that
function is not changed, the cached version of the function is returned.
**Note- Memoization is used for expensive function calls but in the following
example, we are considering a simple function for
understanding the concept of memoization better.
function addTo256(num){
return num + 256;
}
In the code above, we have written a function that adds the parameter to 256 and
returns it.
When we are calling the function addTo256 again with the same parameter (“20” in
the case above), we are computing the result
again for the same parameter.
Computing the result with the same parameter again and again is not a big deal in
the above case, but imagine if the function does
some heavy duty work, then, computing the result again and again with the same
parameter will lead to wastage of time.
This is where memoization comes in, by using memoization we can store(cache) the
computed results based on the parameters. If the
same parameter is used again while invoking the function, instead of computing the
result, we directly return the stored (cached) value.
function memoizedAddTo256(){
var cache = {};
return function(num){
if(num in cache){
console.log("cached value");
return cache[num]
}
else{
cache[num] = num + 256;
return cache[num];
}
}
}
In the code above, if we run memoizedFunc function with the same parameter, instead
of computing the result again,
it returns the cached result.
The following function calculates the sum of all the elements in an array by using
recursion:
function computeSum(arr){
if(arr.length === 1){
return arr[0];
}
else{
return arr.pop() + computeSum(arr);
}
}
computeSum([7, 8, 9, 99]); // Returns 123
Example:
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
When the browser tries to render a HTML document, it creates an object based on the
HTML document called DOM. Using this DOM,
we can manipulate or change various elements inside the HTML document.
Arrow functions are declared without the function keyword. If there is only one
returning expression then we don’t need to use the
return keyword as well in an arrow function as shown in the example above. Also,
for functions having just one line of code,
curly braces { } can be omitted.
If the function takes in only one argument, then the parenthesis () around the
parameter can be omitted as shown in the code above.
var obj1 = {
valueOfThis: function(){
return this;
}
}
var obj2 = {
valueOfThis: ()=>{
return this;
}
}
The biggest difference between the traditional function expression and the arrow
function, is the handling of the this keyword.
By general definition, the this keyword always refers to the object that is calling
the function.
As you can see in the code above, obj1.valueOfThis() returns obj1, since this
keyword refers to the object calling the function.
In the arrow functions, there is no binding of the this keyword.
The this keyword inside an arrow function, does not refer to the object calling it.
It rather inherits its value from the
parent scope which is the window object in this case.
With the ES6 Version, keywords let and const were introduced to declare variables.
function catchValues(){
console.log(variable1);
console.log(variable2);
// Both the variables can be accessed anywhere since they are declared in the
global scope
}
The variables declared with the let keyword in the global scope behave just
like the variable declared with the var keyword in the global scope.
Variables declared in the global scope with var and let keywords can be accessed
from anywhere in the code.
Variables that are declared with the var keyword in the global scope are added to
the window/global object.
Therefore, they can be accessed using window.variableName.
Whereas, the variables declared with the let keyword are not added to the global
object, therefore, trying to access
such variables using window.variableName results in an error.
function varVsLetFunction(){
let awesomeCar1 = "Audi";
var awesomeCar2 = "Mercedes";
}
Variables declared in a functional/local scope using var and let keywords behave
exactly the same, meaning ,
they cannot be accessed from outside of the scope.
{
var variable3 = [1, 2, 3, 4];
}
{
let variable4 = [6, 55, -1, 2];
}
In javascript, a block means the code written inside the curly braces {} .
Variables declared with var keyword do not have block scope. It means a variable
declared in block scope {} with the
var keyword is the same as declaring the variable in the global scope.
Variables declared with let keyword inside the block scope cannot be accessed from
outside of the block.
Const keyword
Variables with the const keyword behave exactly like a variable declared with the
let keyword with only one difference,
any variable declared with the const keyword cannot be reassigned.
Example:
const x = {name:"Vivek"};
const y = 23;
In the code above, although we can change the value of a property inside the
variable declared with const keyword,
we cannot completely reassign the variable itself.
Rest parameter ( … )
Using the rest parameter syntax, we can create functions that can take a variable
number of arguments.
Any number of arguments will be converted into an array using the rest parameter.
Rest parameter can be used by applying three dots (...) before the parameters.
function extractingArgs(...args){
return args[1];
}
// extractingArgs(8,9,1); // Returns 9
function addAllArgs(...args){
let sumOfArgs = 0;
let i = 0;
while(i < args.length){
sumOfArgs += args[i];
i++;
}
return sumOfArgs;
}
**Note- Rest parameter should always be used at the last parameter of a function:
Although the syntax of spread operator is exactly the same as the rest parameter,
spread operator is used to spread an array,
and object literals. We also use spread operators where one or more arguments are
expected in a function call.
function addFourNumbers(num1,num2,num3,num4){
return num1 + num2 + num3 + num4;
}
addFourNumbers(...fourNumbers);
// Spreads [5,6,7,8] as 5,6,7,8
Before promises, callbacks were used to handle asynchronous operations. But due to
limited functionality of callback, using multiple
callbacks to handle asynchronous code can lead to unmanageable code.
Pending - Initial state of promise. This state represents that the promise has
neither been fulfilled nor been rejected, it is in the pending state.
Fulfilled - This state represents that the promise has been fulfilled, meaning the
async operation is completed.
Rejected - This state represents that the promise has been rejected for some
reason, meaning the async operation has failed.
Settled - This state represents that the promise has been either rejected or
fulfilled.
resolve is a function that will be called, when the async operation has been
successfully completed.
reject is a function that will be called, when the async operation fails or if some
error occurs.
Example of a promise:
Promises are used to handle asynchronous operations like server requests, for the
ease of understanding, we are using an operation to
calculate the sum of three elements.
function sumOfThreeElements(...elements){
return new Promise((resolve,reject)=>{
if(elements.length > 3 ){
reject("Only three elements or less are allowed");
}
else{
let sum = 0;
let i = 0;
while(i < elements.length){
sum += elements[i];
i++;
}
resolve("Sum has been calculated: "+sum);
}
})
}
In the code above, we are calculating the sum of three elements, if the length of
elements array is more than 3, promise is rejected,
else the promise is resolved and the sum is returned.
We can consume any promise by attaching then() and catch() methods to the consumer.
then() method is used to access the result when the promise is fulfilled.
catch() method is used to access the result/error when the promise is rejected.
sumOfThreeElements(4, 5, 6)
.then(result=> console.log(result))
.catch(error=> console.log(error));
// In the code above, the promise is fulfilled so the then() method gets executed
Below are the examples of how classes are declared and used:
Unlike functions, classes are not hoisted. A class cannot be used before it is
declared.
A class can inherit properties and methods from other classes by using the extend
keyword.
All the syntaxes inside the class must follow the strict mode(‘use strict’) of
javascript.
Error will be thrown if the strict mode rules are not followed.
function* genFunc(){
// Perform operation
}
In normal functions, we use the return keyword to return a value and as soon as the
return statement gets executed,
the function execution stops:
function normalFunc(){
return 22;
console.log(2); // This line of code does not get executed
}
In the case of generator functions, when called, they do not execute the code,
instead they return a generator object .
This generator object handles the execution.
function* genFunc(){
yield 3;
yield 4;
}
genFunc(); // Returns Object [Generator] {}
The generator object consists of a method called next() , this method when called,
executes the code until the nearest yield statement,
and returns the yield value.
As one can see the next method returns an object consisting of value and done
properties.
Value property represents the yielded value.
Done property tells us whether the function code is finished or not. (Returns true
if finished)
Generator functions are used to return iterators. Let’s see an example where an
iterator is returned:
function* iteratorFunc() {
let count = 0;
for (let i = 0; i < 2; i++) {
count++;
yield i;
}
return count;
}
As you can see in the code above, the last line returns done:true , since the code
reaches the return statement.
Object destructuring:
const classDetails = {
strength: 78,
benches: 39,
blackBoard:1
}
const classDetails = {
strength: 78,
benches: 39,
blackBoard:1
}
console.log(classStrength); // Outputs 78
console.log(classBenches); // Outputs 39
console.log(classBlackBoard); // Outputs 1
As one can see, using object destructuring we have extracted all the elements
inside an object in one line of code.
If we want our new variable to have the same name as the property of an object we
can remove the colon:
Array destructuring:
let message;
}
anotherRandomFunc();
In the code above, both in global scope and functional scope, we are trying to
access variables which have not been declared yet.
This is called the Temporal Dead Zone
var x = 2;
let y = 12;
}
func1();
Code 1 - Outputs 2 and 12 . Since, even though let variables are not hoisted, due
to async nature of javascript, the complete function
code runs before the setTimeout function. Therefore, it has access to both x and y.
b) // Code 2:
function func2(){
for(var i = 0; i < 3; i++){
setTimeout(()=> console.log(i),2000);
}
}
func2();
Code 2 - Outputs 3 , three times since variable declared with var keyword does not
have block scope. Also, inside the for loop,
the variable i is incremented first and then checked.
c) // Code 3:
(function(){
setTimeout(()=> console.log(1),2000);
console.log(2);
setTimeout(()=> console.log(3),0);
console.log(4);
})();
Code 3 - Output in the following order:
2
4
3
1 // After two seconds
Even though the second timeout function has a waiting time of zero seconds, the
javascript engine always evaluates the setTimeout
function using the Web API and therefore, the complete function executes before the
setTimeout function can execute.
d) // Code 1:
let x= {}, y = {name:"Ronny"},z = {name:"John"};
x[y] = {name:"Vivek"};
x[z] = {name:"Akki"};
console.log(x[y]);
Ans:
Code 1 - Output will be {name: “Akki”}.
Adding objects as properties of another object should be done carefully.
Writing x[y] = {name:”Vivek”} , is same as writing x[‘object Object’] =
{name:”Vivek”} ,
While setting a property of an object, javascript coerces the parameter into a
string.
Therefore, since y is an object, it will be converted to ‘object Object’.
e) // Code 2:
function runFunc(){
console.log("1" + 1);
console.log("A" - 1);
console.log(2 + "-2" + "2");
console.log("Hello" - "World" + 78);
console.log("Hello"+ "78");
}
runFunc();
Ans:
Code 2 - Outputs in the following order:
11
Nan
2-22
NaN
Hello78
f) // Code 3:
let a = 0;
let b = false;
console.log((a == b));
console.log((a === b));
Code 3 - Output in the following order due to equality coercion:
true
false
g) //code 4
var x = 23;
(function(){
var x = 43;
(function random(){
x++;
console.log(x);
var x = 21;
})();
})();
Answer:
Output is NaN .
random() function has functional scope, since x is declared and hoisted in the
functional scope.
Rewriting the random function will give a better idea about the output:
function random(){
var x; // x is hoisted
x++; // x is not a number since it is not initialized yet
console.log(x); // Outputs NaN
x = 21; // Initialization of x
}
let hero = {
powerLevel: 99,
getPower(){
return this.powerLevel;
}
}
// Code 2
const a = function(){
console.log(this);
const b = {
func1: function(){
console.log(this);
}
}
const c = {
func2: ()=>{
console.log(this);
}
}
b.func1();
c.func2();
}
a();
// Code 3
const b = {
name:"Vivek",
f: function(){
var self = this;
console.log(this.name);
(function(){
console.log(this.name);
console.log(self.name);
})();
}
}
b.f();
undefined
42
Reason - The first output is undefined since when the function is invoked, it is
invoked referencing the global object:
window.getPower() = getPower();
global/window object
object "b"
global/window object
Since we are using arrow function inside func2, this keyword refers to the global
object.
"Vivek"
undefined
"Vivek"
Only in the IIFE inside the function f , the this keyword refers to the
global/window object.
// Code 2
// Each time bigFunc is called, an array of size 700 is being created,
// Modify the code so that we don't create the same array again and again
function bigFunc(element){
let newArray = new Array(700).fill('♥');
return newArray[element];
}
// Code 3
// The following code outputs 2 and 2 after waiting for one second
// Modify the code to output 0 and 1 after one second.
function randomFunc(){
for(var i = 0; i < 2; i++){
setTimeout(()=> console.log(i),1000);
}
}
randomFunc();
Answers -
Code 1 - Outputs 45 .
Even though a is defined in the outer function, due to closure the inner functions
have access to it.
function bigFunc(){
let newArray = new Array(700).fill('♥');
return (element) => newArray[element];
}
function randomFunc(){
for(let i = 0; i < 2; i++){
setTimeout(()=> console.log(i),1000);
}
}
randomFunc();
Using closure:
function randomFunc(){
for(var i = 0; i < 2; i++){
(function(i){
setTimeout(()=>console.log(i),1000);
})(i);
}
}
randomFunc();
function binarySearch(arr,value,startPos,endPos){
if(startPos > endPos) return -1;
Ques: Implement a function that returns an updated array with r right rotations on
an array of integers a .
Example:
Given the following array:
[2,3,4,5,7]
Perform 3 right rotations:
First rotation : [7,2,3,4,5] , Second rotation : [5,7,2,3,4] and, Third rotation:
[4,5,7,2,3]
return [4,5,7,2,3]
Answer:
function rotateRight(arr,rotations){
if(rotations == 0) return arr;
for(let i = 0; i < rotations;i++){
let element = arr.pop();
arr.unshift(element);
}
return arr;
}
rotateRight([2, 3, 4, 5, 7], 3); // Return [4,5,7,2,3]
rotateRight([44, 1, 22, 111], 5); // Returns [111,44,1,22]
#########################Edureka##################################33
Ques: What is the difference between Local storage & Session storage?
Ans: Local Storage – The data is not sent back to the server for every HTTP request
(HTML, images, JavaScript, CSS, etc) –
reducing the amount of traffic between client and server. It will stay until it is
manually cleared through settings or program.
Session Storage – It is similar to local storage; the only difference is while data
stored in local storage has no expiration time,
data stored in session storage gets cleared when the page session ends. Session
Storage will leave when the browser is closed.
Ques: How can you convert the string of any base to integer in JavaScript?
Ans: The parseInt() function is used to convert numbers between different bases. It
takes the string to be converted as its first parameter,
and the second parameter is the base of the given string.
For example- parseInt("4F", 16)
Async utility has a number of control flows. Let’s discuss the most popular ones
and their use cases:
1. Parallel
When we have to run multiple tasks independent of each other without waiting until
the previous task has completed, parallel comes into the picture.
async.parallel(tasks, callback)
view rawparallel.js hosted with ❤ by GitHub
Tasks: A collection of functions to run. It can be an array, an object or any
iterable.
Callback: This is the callback where all the task results are passed and is
executed once all the task execution has completed.
async.parallel([
function(callback) {
setTimeout(function() {
console.log('Task One');
callback(null, 1);
}, 200);
},
function(callback) {
setTimeout(function() {
console.log('Task Two');
callback(null, 2);
}, 100);
}
],
function(err, results) {
console.log(results);
// the results array will equal [1, 2] even though
// the second function had a shorter timeout.
});
async.series(tasks, callback)
view rawseries.js hosted with ❤ by GitHub
Tasks: A collection of functions to run. It can be an array, an object or any
iterable.
Callback: This is the callback where all the task results are passed and is
executed once all the task execution has completed.
Callback function receives an array of result objects when all the tasks have been
completed. If an error is encountered in any of the task, no more functions are run
but the final callback is called with the error value.
async.series([
function(callback) {
console.log('one');
callback(null, 1);
},
function(callback) {
console.log('two');
callback(null, 2);
},
function(callback) {
console.log('three');
callback(null, 3);
}
],
function(err, results) {
console.log(result);
// results is now equal to [1, 2, 3]
});
async.series({
1: function(callback) {
setTimeout(function() {
console.log('Task 1');
callback(null, 'one');
}, 200);
},
2: function(callback) {
setTimeout(function() {
console.log('Task 2');
callback(null, 'two');
}, 300);
},
3: function(callback) {
setTimeout(function() {
console.log('Task 3');
callback(null, 'three');
}, 100);
}
},
function(err, results) {
console.log(results);
// results is now equal to: { 1: 'one', 2: 'two', 3:'three' }
});
view rawasyn-series-example.js hosted with ❤ by GitHub
3. Waterfall
When we have to run multiple tasks which depend on the output of previous task,
Waterfall can be helpful.
async.waterfall(tasks, callback)
view rawwaterfall.js hosted with ❤ by GitHub
Tasks: A collection of functions to run. It can be an array, an object or any
iterable structure.
Callback: This is the callback where all the task results are passed and is
executed once all the task execution has completed.
It will run one function at a time and pass the result of the previous function to
the next one.
async.waterfall([
function(callback) {
callback(null, 'Task 1', 'Task 2');
},
function(arg1, arg2, callback) {
// arg1 now equals 'Task 1' and arg2 now equals 'Task 2'
let arg3 = arg1 + ' and ' + arg2;
callback(null, arg3);
},
function(arg1, callback) {
// arg1 now equals 'Task1 and Task2'
arg1 += ' completed';
callback(null, arg1);
}
], function(err, result) {
// result now equals to 'Task1 and Task2 completed'
console.log(result);
});
function myFirstFunction(callback) {
callback(null, 'Task 1', 'Task 2');
}
function mySecondFunction(arg1, arg2, callback) {
// arg1 now equals 'Task 1' and arg2 now equals 'Task 2'
let arg3 = arg1 + ' and ' + arg2;
callback(null, arg3);
}
function myLastFunction(arg1, callback) {
// arg1 now equals 'Task1 and Task2'
arg1 += ' completed';
callback(null, arg1);
}
view rawasync-waterfall-example.js hosted with ❤ by GitHub
4. Queue
When we need to run a set of tasks asynchronously, queue can be used. A queue
object based on an asynchronous function can be created which is passed as worker.
async.queue(task, concurrency)
view rawqueue.js hosted with ❤ by GitHub
Task: Here, it takes two parameters, first - the task to be performed and second -
the callback function.
async.priorityQueue(task,concurrency)
view rawpriority_queue.js hosted with ❤ by GitHub
Task: Here, it takes three parameters:
// assign a callback
q.drain = function() {
console.log('All items have been processed');
};
// add some items to the queue (batch-wise) which will have same priority
q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], 1, function(err) {
console.log('Finished processing item');
});
view rawasync-priorityQueue-example.js hosted with ❤ by GitHub
6. Race
It runs all the tasks in parallel, but as soon as any of the function completes its
execution or passes error to its callback, the main callback is immediately called.
async.race(tasks, callback)
view rawrace.js hosted with ❤ by GitHub
Task: Here, it is a collection of functions to run. It is an array or any iterable.
Callback: The result of the first complete execution is passed. It may be the
result or error.
async.race([
function (callback) {
setTimeout(function () {
callback(null, 'one');
}, 300);
},
function (callback) {
setTimeout(function () {
callback(null, 'two');
}, 100);
},
function (callback) {
setTimeout(function () {
callback(null, 'three');
}, 200);
}
],
// main callback
function (err, result) {
// the result will be equal to 'two' as it finishes earlier than the other 2
console.log('The result is ', result);
});
view rawasync-race-example.js hosted with ❤ by GitHub
Combining Async Flows
In complex scenarios, the async flows like parallel and series can be combined and
nested. This helps in achieving the expected output with the benefits of async
utilities.
However, the only difference between Waterfall and Series async utility is that the
final callback in series receives an array of results of all the task whereas in
Waterfall, the result object of the final task is received by the final callback.
const p1 = Promise.resolve(1);
const p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 2, 'foo');
});
const p3 = 3;
const p1 = Promise.resolve(1);
const p2 = Promise.reject('foo');
const p3 = 3;
const p1 = Promise.resolve(1);
const p2 = Promise.reject('foo');
const p3 = 3;
/* [
{ status: 'fulfilled', value: 1 },
{ status: 'rejected', reason: 'foo' },
{ status: 'fulfilled', value: 3 },
] */
1.Class: Buffer The Buffer class is an inbuilt globally accessible class that means
it can be used without importing any module. The Buffer class is used to deal with
binary data. Buffer class objects are used to represent binary data as a sequence
of bytes.
const buffer = new Buffer(5,'abcde');
console.log(buffer)
O/p => Buffer 61 62 63 64 65
2.It is a global scope when declared within the browser. However, any variable
defined within a node.js file is accessible only within that file.
function printHello() {
console.log( "Hello, World!");
}
4.Class: URL The URL class instance is a global object and is implemented by the
following WHATWG URL Standard. The URL constructor creates a new URL object as
shown below. /foo is the input and https://www.helloworld.og/ is the base value.
// It prints gfg
console.log(myURL.searchParams.get('name'));
myURL.searchParams.append('name', 'xyz');
// It prints https://www.register.com/?name=gfg&name=xyz
console.log(myURL.href);
6.WebAssembly: The global object that acts as a namespace for all W3C WebAssembly
related functionality. WebAssembly is a low level Assembly-like language that can
be run on modern browsers.
The following variables might appear to be global but actually exist only within
the scope of some modules.
> require(id) method: It is used to import modules and returns an object of ‘any’
datatype.
var express = require('express')
> exports: It is used to exports modules using module.exports.
> module: It is a reference to the current module and is not global rather local to
each module. It is used to make a particular module available through require() in
the application.
> __dirname: The output throws an error which proves that __dirname is not globally
defined in node.js. It requires a script to give the desired output as __dirname is
only defined in scripts.
Create a demo.js file
Paste the following code:
console.log("__dirname : "+ __dirname);
Run the demo.js file
7.__filename: The output throws an error which proves that __dirname is not
globally defined in node.js. It requires a script to give the desired output as
__filename is only defined in scripts.
Create a demo.js file
Paste the following code:
console.log("__filename : "+ __filename);
Run the demo.js file
//some extra
Value of this in a node module:
this in NodeJS global scope is the current module.exports object, not the global
object. This is different from a browser where the global scope is the global
window object. Consider the following code executed in Node:
console.log(this); // logs {}
module.exports.foo = 5;
console.log(global);
The global object exposes a variety of useful properties about the environment.
Also this is the place where functions as setImmediate and clearTimeout are
located.
// respond with "hello world" when a GET request is made to the homepage
app.get('/', function (req, res) {
res.send('hello world')
})
Here is an example of chained route handlers that are defined by using app.route().
app.route('/book')
.get(function (req, res) {
res.send('Get a random book')
})
.post(function (req, res) {
res.send('Add a book')
})
.put(function (req, res) {
res.send('Update the book')
})
express.Router
Use the express.Router class to create modular, mountable route handlers. A Router
instance is a complete middleware and routing system; for this reason, it is often
referred to as a “mini-app”.
Create a router file named birds.js in the app directory, with the following
content:
module.exports = router
Then, load the router module in the app:
// ...
app.use('/birds', birds)
Application-level middleware
Bind application-level middleware to an instance of the app object by using the
app.use() and app.METHOD() functions, where METHOD is the HTTP method of the
request that the middleware function handles (such as GET, PUT, or POST) in
lowercase.
This example shows a middleware function with no mount path. The function is
executed every time the app receives a request.
This example shows a middleware sub-stack that handles GET requests to the
/user/:id path.
This example shows a middleware sub-stack that handles GET requests to the
/user/:id path.
This example shows an array with a middleware sub-stack that handles GET requests
to the /user/:id path
Router-level middleware
Router-level middleware works in the same way as application-level middleware,
except it is bound to an instance of express.Router().
The following example code replicates the middleware system that is shown above for
application-level middleware, by using router-level middleware:
// a middleware function with no mount path. This code is executed for every
request to the router
router.use(function (req, res, next) {
console.log('Time:', Date.now())
next()
})
// a middleware sub-stack shows request info for any type of HTTP request to the
/user/:id path
router.use('/user/:id', function (req, res, next) {
console.log('Request URL:', req.originalUrl)
next()
}, function (req, res, next) {
console.log('Request Type:', req.method)
next()
})
This example shows a middleware sub-stack that handles GET requests to the
/user/:id path.
// predicate the router with a check and bail out when needed
router.use(function (req, res, next) {
if (!req.headers['x-auth']) return next('router')
next()
})
Error-handling middleware
Error-handling middleware always takes four arguments. You must provide four
arguments to identify it as an error-handling middleware function. Even if you
don’t need to use the next object, you must specify it to maintain the signature.
Otherwise, the next object will be interpreted as regular middleware and will fail
to handle errors.
The idea is simple – emitter objects send out named events, which trigger listeners
that have already been registered. Hence, an emitter object has two key
characteristics:
Emitting name events: The signal that something has happened is called emitting an
event. A status change in the emitting object is often the cause of this condition.
Registering and unregistering listener functions: It refers to the binding and
unbinding of the callback functions with their corresponding events.
Event-Driven Programming Principles:
A suite of functions for handling the events. These can be either blocking or non-
blocking, depending on the implementation.
Binding registered functions to events.
When a registered event is received, an event loop polls for new events and calls
the matching event handler(s).
console.log("Finish");
The above code snippet binds the handler named ‘connectHandler’ with the event
‘connection’’. The callback function is triggered when the event is emitted.
node app.js
Output:
Connection established.
Data Transfer Successful.
Finish
Output log
npm
install: The npm creates massive output logs of npm commands. It is essentially a
dump of stack trace of what npm is doing.
yarn
add: The yarn output logs are clean, visually distinguishable and brief. They are
also ordered in a tree form for understandability.
npm: To install a global package, the command template for npm is:
npm install -g package_name@version_number
yarn: To install a global package, the command template for yarn is:
yarn global add package_name@version_number
License Checker
npm: npm doesn’t has a license checker that can give a handy description of all the
licenses that a project is bound with, due to installed dependencies.
yarn: Yarn has a neat license checker. To see them, run
yarn licenses list
Fetching packages
npm: npm fetches dependencies from the npm registry during every ‘npm install‘
command.
Yarn: yarn stores dependencies locally, and fetches from the disk during a ‘yarn
add‘ command (assuming the dependency(with the specific version) is present
locally).
Ques: Node.js | package.json
The package.json file is the heart of Node.js system. It is the manifest file of
any Node.js project and contains the metadata of the project. The package.json file
is the essential part to understand, learn and work with the Node.js. It is the
first step to learn about developmnent in Node.js.
npm init
2. Writing directly to file : One can directly write into file with all the
required information and can include it in the Node project.
When you install an npm package using npm install <package-name>, you are
installing it as a dependency.
When you add the -D flag, or --save-dev, you are installing it as a development
dependency, which adds it to the devDependencies list.
When you go in production, if you type npm install and the folder contains a
package.json file, they are installed, as npm assumes this is a development deploy.
You need to set the --production flag (npm install --production) to avoid
installing those development dependencies.
The following are the four different ways to create a child process in Node.js:
spawn() method
fork() method
exec() method
execFile() method
Above mentioned ways are explained below:
1) spawn() method: This method spawns a new process using the given command and the
command line arguments in args. The ChildProcess instance implements
EventEmitterAPI which enables us to register handlers for events on child object
directly. Some events that can be registered for handling with the ChildProcess are
exit, disconnect, error, close and message.
Syntax:
Example:
const { spawn } = require('child_process');
const child = spawn('dir', ['D:\Test'], {shell: true});
child.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
Syntax:
child_process.fork(modulePath[, args][, options])
Parameters:
modulePath: Accepts a string that specifies the module to run in the child.
args: List of string arguments.
options: cwd, detached, env, execPath, execArgv are some of the available options
for this method.
Return Value: Returns a ChildProcess instance.
child.on('message', function(m) {
console.log('Parent process received:', m);
});
Filename: sub.js
process.on('message', function(m) {
console.log('Child process received:', m);
});
Output:
Parent process received: { hello: 'from child process' }
Child process received: {hello: 'from parent process'}
3) exec() method: This method creates a shell first and then executes the command.
Syntax:
command: Accepts a string that specifies the command to run with space-separated
arguments.
options: Some of the options available are cwd, env, encoding, shell, timeout etc
callback: The callback function is called when process terminates. The arguments to
this function are error, stdout and stderr respectively.
Return Value: Returns an instance of ChildProcess.
Example:
const { exec } = require('child_process');
Syntax:
file: Accepts a string that specifies the name or path of the file to run.
args: List of string arguments.
options: Some of the options available are cwd, env, encoding, shell, timeout etc
callback: The callback function is called when process terminates. The arguments to
this function are error, stdout and stderr respectively.
Return Value: Returns an instance of ChildProcess.
const { execFile } = require('child_process');
Read : It reads the inputs from users and parses it into JavaScript data structure.
It is then stored to memory.
Eval : The parsed JavaScript data structure is evaluated for the results.
Print : The result is printed after the evaluation.
Loop : Loops the input command. To come out of NODE REPL, press ctrl+c twice
The combination of the asynchronous nature of Node.js plus the reduced resource
consumption of the single-threaded process leads to a significant increase in
performance. It should be noted, however, that Node.js does not excel with CPU-
intensive operations such as image processing and computationally-expensive work.
}
else if (req.url == "/student") {
}
else if (req.url == "/admin") {
}
else
res.end('Invalid Request!');
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
1) The first argument in the function is reserved for the error object. If any
error has occurred during the execution of the function, it will be returned by the
first argument.
2) The second argument of the callback function is reserved for any successful data
returned by the function. If no error occurred then the error object will be set to
null.
Below is the implementation of Error-First Callback:
Create a file with the name index.js. The file requires an fs module. We will be
implementing an error-first callback function on methods of the fs module. fs
module can be used in the program by using the below command:
const fs = require("fs");
The file can be executed by using the below command:
node index.js
We will be using fs.readFile() to show error-first callback function.
const fs = require("fs");
// function execution
// This will return
// error because file do
// not exist
fs.readFile(file, ErrorFirstCallback);
Output:
[Error: ENOENT: no such file or directory, open 'file.txt'] {
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: 'file.txt'
}
Example 2:
const fs = require("fs");
// function execution
// This will return
// data object
fs.readFile(file, ErrorFirstCallback);
Output:
Function successfully executed
This file exists already
JavaScript is a strange language. Once in a while, you have to deal with a callback
that’s in another callback that’s in yet another callback.
firstFunction(args, function() {
secondFunction(args, function() {
thirdFunction(args, function() {
// And so on…
});
});
});
How to escape from a callback hell?
JavaScript provides an easy way of escaping from a callback hell. This is done by
event queue and promises.
A promise is a returned object from any asynchronous function, to which callback
methods can be added based on the previous function’s result.
Promises use .then() method to call async callbacks. We can chain as many callbacks
as we want and the order is also strictly maintained.
Promises use .fetch() method to fetch an object from the network. It also
uses .catch() method to catch any exception when any block fails.
So these promises are put in event queue so that they don’t block subsequent JS
code. Also once the results are returned, the event queue finishes its operations.
There are also other helpful keywords and methods like async, wait, settimeout() to
simplify and make better use of callbacks.
Another:
Lets say we want to make entry in multiple tables and we have to do in some order,
so developers make insert call in callback of one table and continue like this.
expect(writeFileStub).to.be.called
writeFileStub.restore()
describe('saveUser', function () {
it('should call callback after saving',
function () {
post.restore();
sinon.assert.calledOnce(callback);
});
});
mocha.run();
output:
saveUser
we will call the callback after saving
Example:
module.exports = (x, callback) => {
if (x <= 0)
setTimeout(() =>
callback(new Error("Square dimensions
should be greater than zero: s = " + x),
null), 2000);
else
setTimeout(() =>
callback(null, {
perimeter: () => (4*(x)),
area:() => (x*x)
}), 2000);
}
What are Promises?
A promise is basically an advancement of callbacks in Node. While developing an
application you may encounter that you are using a lot of nested callback
functions.
client.close();
});
});
});
});
});
This is what happens due to the nesting of callback functions. Now imagine if you
need to perform multiple nested operations like this. That would make your code
messy and very complex. In Node.js world, this problem is called “Callback Hell”.
To resolve this issue we need to get rid of the callback functions whilst nesting.
This is where Promises come into the picture. A Promise in Node means an action
which will either be completed or rejected. In case of completion, the promise is
kept and otherwise, the promise is broken. So as the word suggests either the
promise is kept or it is broken. And unlike callbacks, promises can be chained.
Callbacks to Promises
Promises notify whether the request is fulfilled or rejected. Callbacks can be
registered with the .then() to handle fulfillment and rejection. The .then() can be
chained to handle the fulfillment and rejection whereas .catch() can be used for
handling the errors(if any).
Ex: dboper.insertDocument(db,
{ name: "Test", description: "Just a test"},
"test").then((result) => {
console.log("Insert Document:\n", result.ops);
});
Nested Promises: Often you will encounter situations where you need to make use of
nested Promises. Nested promises begin with a .then() and in each of the .then() we
have a return statement. After the return statement, .then() follows in the same
manner.
Example:
MongoClient.connect(url).then((client) => {
const db = client.db(database_name);
return db.dropCollection("test");
})
.then((result) => {
return client.close();
})
.catch((err) => alert(err));
})
.catch((err) => alert(err));
Now as compared to using the callbacks, our code looks a lot cleaner than before.
As the .then() can be chained together, therefore every Promise is easy to identify
in the code. The .catch(err) is executed if error(s) occurs.
Ques:Output
var a = 10;
console.log(a);
function task() {
var a =20;
console.log(a);
if(true) {
var a = 30; //since a has function scope, writing var is not making
difference
console.log(a);
}
console.log(a);
}
task();
console.log(a);
Ans: 10 20 30 30 10
Ques: output
console.log(typeof gm);
let gm = function(name) {
console.log('gm')
}
let ge = function(name) {
console.log('ge')
}
Output: Reference error will come
cannot access gm before initializing
Ques: output
gm('arnav');
ge('arnav');
var gm = function(name) {
console.log('gm')
}
var ge = function(name) {
console.log('ge')
}
Output: Type error will come
gm is not a function
Ques: output
function printtthis() {
console.log(this);
}
printthis();
Output: Global object get printed because node js runs in global in case of browser
window will get printed.
Object[global]...
Ques:
let obj = {
a: 10,
b: 20,
c: printthis, //here this will point to obj
d: function() {
this.c(); //object
printthis(); //global
console.log(this.c==printthis); //true
}
}
obj.c();
Output:
{a:10, b:20, c: [Function: prinththis]}
let x = obj.c;
x(); //print global object
console.log(x==printthis); //true even with ===, it make diff with primitives only
(async () => {
const a = await callMe();
console.log(a);
})();
Ques: jwt
Ans: import * as jwt from 'jsonwebtokens';
const encData = jwt.sign({name: mahesh}, process.env.SECRET);
const decData = jwt.verify(encData, process.env.SECRET);
console.log(decData);
The dynamic context means that the value of this depends on how the function is
invoked. In JavaScript, there are 4 ways you can invoke a regular function.
During a simple invocation the value of this equals to the global object (or
undefined if the function runs in strict mode):
function myFunction() {
console.log(this);
}
// Simple invocation
myFunction(); // logs global object (window)
During a method invocation the value of this is the object owning the method:
const myObject = {
method() {
console.log(this);
}
};
// Method invocation
myObject.method(); // logs myObject
During an indirect invocation using myFunc.call(thisVal, arg1, ..., argN) or
myFunc.apply(thisVal, [arg1, ..., argN]) the value of this equals to the first
argument:
function myFunction() {
console.log(this);
}
const myContext = { value: 'A' };
myFunction.call(myContext); // logs { value: 'A' }
myFunction.apply(myContext); // logs { value: 'A' }
During a constructor invocation using new keyword this equals to the newly created
instance:
function MyFunction() {
console.log(this);
}
new MyFunction(); // logs an instance of MyFunction
1.2 Arrow function
The behavior of this inside of an arrow function differs considerably from the
regular function's this behavior. The arrow function doesn't define its own
execution context.
No matter how or where being executed, this value inside of an arrow function
always equals this value from the outer function. In other words, the arrow
function resolves this lexically.
const myObject = {
myMethod(items) {
console.log(this); // logs myObject
const callback = () => {
console.log(this); // logs myObject
};
items.forEach(callback);
}
};
myObject.myMethod([1, 2, 3]);
this value inside the arrow function callback() equals to this of the outer
function myMethod().
this resolved lexically is one of the great features of arrow functions. When using
callbacks inside methods you are sure the arrow function doesn't define its own
this: no more const self = this or callback.bind(this) workarounds.
Ques: Return third highest and third lowest element in array without using index
Ques: output
for(var j=0;j<5;j++){
setTimeout(()=>console.log(j),10);
}
output:
5
5
5
5
5
firstFunction(args, function() {
secondFunction(args, function() {
thirdFunction(args, function() {
// And so on…
});
});
});
This is JavaScript for you. It’s mind-boggling to see nested callbacks, but I don’t
think it’s a “hell”. The “hell” can be manageable if you know what to do with it.
On callbacks
I assume you know what callbacks are if you’re reading this article. If you don’t,
please read this article for an introduction to callbacks before continuing. There,
we talk about what callbacks are and why you use them in JavaScript.
Write comments
Split functions into smaller functions
Using Promises
Using Async/await
Before we dive into the solutions, let’s construct a callback hell together. Why?
Because it’s too abstract to see firstFunction, secondFunction, and thirdFunction.
We want to make it concrete.
If you’re reading makeBurger for the first time, you may think “Why the hell do we
need so many callbacks to make a burger? It doesn’t make sense!”.
// Makes a burger
// makeBurger contains four steps:
// 1. Get beef
// 2. Cook the beef
// 3. Get buns for the burger
// 4. Put the cooked beef between the buns
// 5. Serve the burger (from the callback)
// We use callbacks here because each step is asynchronous.
// We have to wait for the helper to complete the one step
// before we can start the next step
Second solution to callback hell: Split the callbacks into different functions
Our callback hell example is already an example of this. Let me show you the step-
by-step imperative code and you’ll see why.
For getBeef, our first callback, we have to go to the fridge to get the beef. There
are two fridges in the kitchen. We need to go to the right fridge.
For a concrete example on splitting callbacks into smaller functions, you can read
this small section in my callback article.
Promises can make callback hell much easier to manage. Instead of the nested code
you see above, you’ll have this:
But the question is how do you convert callback-based code into promise-based code.
Wrapping up
Callback hell isn’t as hellish as you think. There are four easy ways to manage
callback hell:
Write comments
Split functions into smaller functions
Using Promises
Using Async/await
Array.prototype.map()
Javascript supports an inbuilt method map for Array which takes a callback function
& returns an array of the same length after calling the callback function for each
element of the array. Example:
const arr = [1,2,3,4,5];
function double(elem){
return elem*2;
}
const newArr = arr.map(double);
console.log(newArr);
// [2,4,6,8,10]
1. callbackFn: This function will be called for every element of the array and
returns a value which will be added to the new array. This function can again take
3 arguments.
a. element: The current element being processed in the array.
b. index (Optional): The index of the current element being processed in the array.
c. array (Optional): The array on which map was called.
2. thisArg (Optional)
Now this how I would my implementation for a basic version of Array.prototype.map()
look like:
Array.prototype.myMap = function(callbackFn){
const arr = this;
const resultArr = [];
for(let i=0; i<arr.length; i++){
const newElem = callbackFn(arr[i]);
resultArr.push(newElem);
}
return resultArr;
}
function double(elem, index, arr){
return elem*2;
}
const newArr = arr.myMap(double);
console.log(newArr);
// [2,4,6,8,10]
We can obviously add more error handling scenarios to make this method more robust
and practically useful, but from an interview's point this might be sufficient
usually.
1. thisArg: The value to be passed as the this parameter to the target function
when the bound function is called.
2. arg1, arg2, ... argN (Optional): The arguments to be passed to the actual
function.
Secondly, what is the bind supposed to return? It's supposed to return a copy of
the given function, with the specified this value, and the arguments (if passed).
Ques: We've the following function greet, we need to find out how many times this
function has been called.
function greet(){
console.log("Hello World!");
}
Ans:
Approach-1
Using a global variable to maintain a count of the number of times this function
can be called.
let count = 0;
function greet(){
count++;
console.log("Hello World");
}
greet();
greet();
greet();
console.log(count); // 3
Problem: This approach works fine, but there's an issue that, any other part in the
codebase can manipulate the count variable.
Approach-2
Using Function Closure
function getGreetings(){
let _count = 0;
function greet(){
_count++;
console.log("Hello, my name is Shivaansh");
}
function getGreetCount(){
console.log(_count);
}
return {
greet,
getGreetCount
}
}
Approach-3
Using IIFE
const {greet, getCount} = (function(){
let count = 0;
function getCount(){
return getCount;
}
function greet(){
count++;
console.log("Hello World");
}
return {
greet,
getCount
};
})();
greet();
greet();
greet();
console.log(getCount); // 3
With this approach, we can ensure that no other piece of code can change the count
variable. Here the greet function will have a closure with the count variable so
with the use of concepts like IIFE and Closures, we would be able to achieve the
requirement
Example
const arr = [1, 2, 3, 4, 5, 6];
const filtered = arr.filter((e) => e % 2 === 0);
console.log(filtered);
//[2, 4, 6]
I have checked what arguments this callback takes and found that this callback
function takes three arguments, element, index of the element, and the original
array itself.
Given an array with two entries, parent and child relation, convert the array to
relation tree object (parent -> child -> grandchild) in JavaScript.
The input array will contain relation for many ancestry in random order, We must
return the array of object tree from where the tree starts.
For example, in the below case the top most ancestor is animal.
Example
Input:
[
["lion", "cat"],
["cat", "mammal"],
["dog", "mammal"],
["mammal", "animal"],
["fish", "animal"],
["shark", "fish"],
];
Output:
//animal -> mammal -> cat -> lion
//animal -> mammal -> dog
//animal -> fish -> shark
[{
value: "animal",
type: "parent",
children: [
{
value: 'fish',
type: "child",
children: [
{
value: 'shark',
type: "child",
children: []
}
]
},
{
value: 'mammal',
type: "child",
children: [
{
value: 'cat',
type: "child",
children: [
{
value: 'lion',
type: "child",
children: []
}
]
},
{
value: 'dog',
type: "child",
children: []
}
]
}
]
}]
Ans: Convert relation array to object tree in JavaScript.
As the input is in random order, I have decided not to go with recursive solution,
because moving up and down the hierarchy will add lots of complexity.
Rather than that what I did is I used one extra variable to store the entities
reference. Now no matter at what level the entries lies, we don’t have to always
traverse to that level, all we have to do is update the value in reference and it
will be reflected in the output, because the object is passed by reference.
This way we can implement the solution in linear time and using linear space.
return a;
}, []);
};
const entities = [
["lion", "cat"],
["cat", "mammal"],
["dog", "mammal"],
["fish", "animal"],
["shark", "fish"],
["mammal", "animal"],
["flying", "bird"],
["non-flying", "bird"],
["ostrich", "non-flying"],
["eagle", "flying"],
];
console.log(relations(entities));
Output:
[
{
value: "bird",
type: "parent",
children: [
{
value: 'non-flying',
type: "child",
children: [
{
value: 'ostrich',
type: "child",
children: []
}
]
},
{
value: 'flying',
type: "child",
children: [
{
value: 'eagle',
type: "child",
children: []
}
]
}
]
},
{
value: "animal",
type: "parent",
children: [
{
value: 'fish',
type: "child",
children: [
{
value: 'shark',
type: "child",
children: []
}
]
},
{
value: 'mammal',
type: "child",
children: [
{
value: 'cat',
type: "child",
children: [
{
value: 'lion',
type: "child",
children: []
}
]
},
{
value: 'dog',
type: "child",
children: []
}
]
}
]
}
]
Example
Input:
const obj = {
a: 1,
b: {
c: "Hello World",
d: 2,
e: {
f: {
g: -4,
},
},
h: "Good Night Moon",
},
};
Output:
{
b: {
c: "Hello World",
h: "Good Night Moon",
}
};
The only clause to this function is that filtering should happen in-place, which
means we cannot create a copy of this object and then perform operation on it.
We can filter the object by removing the entries in object which fails the filter
condition. Basically we have to handle the following cases.
Iterate all the entries of the object and in each iteration check.
If the value of the current key is an object then recur and call the same function
with the current value.
Else, if the value is empty object or fails the filter condition then delete the
current object.
To check if the value is empty object or not, we will convert the value to string
using JSON.stringify() method and then compare it.
//filter's in-place
deepFilter(obj, (s) => typeof s === "string");
console.log(obj);
Output:
{
b: {
c: "Hello World",
h: "Good Night Moon",
}
};
For example
Input:
{
A: "12",
B: 23,
C: {
P: 23,
O: {
L: 56
},
Q: [1, 2]
}
}
Output:
{
"A": "12"
"B": 23,
"C.O.L": 56,
"C.P": 23,
"C.Q.0": 1,
"C.Q.1": 2,
}
Deep flatten object Javascript
In the output if you notice, when we have nested objects the key is concatenated
till there is a non-object value, similar for the array, the key is concatenated on
the index.
Given the way we want the output, there are two ways in which we can solve this
problem, one is using stack and other is using recursion.
Approach 1.
const flatten = (obj, prefix) => {
//store the result
let output = {};
//object
if(type === "[object Object]"){
//new key
const newKey = prefix ? prefix + "." + k : k;
const newObj = flatten(val, newKey);
output = {...output, ...newObj};
}
//array
else if(type === "[object Array]"){
//iterate array
for(let i = 0; i < val.length; i++){
//new key
const newKey = prefix ? prefix + "." + k + "." + i : k + "." + i;
output = {...output, [newKey]: val[i]};
}
}
// normal value
else{
//new key
const newKey = prefix ? prefix + "." + k : k;
output = {...output, [newKey]: val};
}
}
return output;
}
Input:
const nested = {
A: "12",
B: 23,
C: {
P: 23,
O: {
L: 56
},
Q: [1, 2]
}
};
console.log(flatten(nested));
Output:
{
"A": "12"
"B": 23,
"C.O.L": 56,
"C.P": 23,
"C.Q.0": 1,
"C.Q.1": 2,
}
Approach 2.
The problem in the first approach is we have to create the new key in each
condition which is not a good and it is because we are iterating the array in
between, if we could convert that array to object then we can get rid of this
problem.
Also we can use ES6 features to differentiate between object and array.
//new key
const newKey = prefix ? prefix + "." + k : k;
return output;
}
Input:
const nested = {
A: "12",
B: 23,
C: {
P: 23,
O: {
L: 56
},
Q: [1, 2]
}
};
console.log(flatten(nested));
Output:
{
"A": "12"
"B": 23,
"C.O.L": 56,
"C.P": 23,
"C.Q.0": 1,
"C.Q.1": 2,
}
For example
Input:
[[[1, [1.1]], 2, 3], [4, 5]]
Output:
[1, 1.1, 2, 3, 4, 5]
ES2019 has introduced two new array methods flat and flatMap which can be used to
flatten an array.
But as these methods are added recently they are supported only by newer versions
of browsers. Firefox 62+, Chrome 69+, Edge 76+ and Safari 12+ currently have the
support.
You can check the current browser support for it before using it.
On the other hand if you are using babel then it will backport your code to
previous version.
//map
['Prashant Yadav', 'Learners Bucket'].map(e => e.split(' '));
//[['Prashant', 'Yadav'], ['Learners', 'Bucket']];
//flatMap
['Prashant Yadav', 'Learners Bucket'].flatMap(e => e.split(' '));
//['Prashant', 'Yadav', 'Learners', 'Bucket'];
Polyfill
In case you don’t want to use any extra library for a single method. You can create
you our own custom function for array flattening.
Objects are the backbone of the javascript programming language as most of its
features are actually object, like arrays, functions, etc.
But there are scenarios where we want to restrict this modification to some limit
or completely.
Here we will see two different objects methods that can you used to achieve the
same.
For example, we should be able to modify the existing properties or methods of the
objects but cannot add a new one. Object.seal() can be used to achieve the same but
it also marks all existing properties as non-configurable like we cannot delete
them but just update their value if it is writable.
const obj = {
prop: 42
};
Object.seal(obj);
obj.prop = 33;
console.log(obj.prop);
// 33
const obj = {
prop: 42,
nested: {
a: 1,
b: 2
}
};
obj.nested.a = 2;
delete obj.nested.a;
console.log(obj.nested.a);
// undefined
However, we can create another helper function which will deep seal or seal the
nested objects as well.
function deepSeal(object) {
// Retrieve the property names defined on object
let propNames = Object.getOwnPropertyNames(object);
return Object.seal(object);
}
Now this will seal the nested objects as well.
const obj = {
prop: 42,
nested: {
a: 1,
b: 2
}
};
obj.nested.a = 2;
delete obj.nested.a;
console.log(obj.nested.a);
// 2
You can use Object.isSealed() to check if an object is sealed or not.
const obj = {
prop: 42,
nested: {
a: 1,
b: 2
}
};
console.log(Object.isSealed(obj));
//true
Using Object.freeze() to restrict modification of object properties.
Unlike Object.seal(), Object.freeze() freezes the object completely. It does not
even allow changing of object properties.
const obj = {
prop: 42
};
Object.freeze(obj);
obj.prop = 33;
// Throws an error in strict mode
console.log(obj.prop);
// 42
But this also only shallow freezes the object properties.
const obj = {
prop: 42,
nested: {
a: 1,
b: 2
}
};
Object.freeze(obj);
obj.nested.a = 33;
// Updates the value
console.log(obj.nested.a);
// 33
Like deepSeal() we can also create a deepFreeze() function that will freeze the
nested objects as well.
function deepFreeze(object) {
// Retrieve the property names defined on object
var propNames = Object.getOwnPropertyNames(object);
return Object.freeze(object);
}
const obj = {
prop: 42,
nested: {
a: 1,
b: 2
}
};
deepFreeze(obj);
obj.nested.a = 33;
// Updates the value
console.log(obj.nested.a);
// 1
You can use Object.isFrozen() to check if an object is frozen or not.
const obj = {
prop: 42,
nested: {
a: 1,
b: 2
}
};
//Seal the object
deepFreeze(obj);
console.log(Object.isFrozen(obj));
//true
Instead what they do is load images as we scroll down or the image is in the
viewport of the screen.
1. We will store the image source in a custom HTML attribute so that we can use it
to load the image.
<img data-src="https://cdn.pixabay.com/photo/2018/09/16/15/31/boy-3681679_1280.jpg"
/>
and may be use a class to access all the images at once.
<img class="lazy-image"
data-src="https://cdn.pixabay.com/photo/2018/09/16/15/31/boy-3681679_1280.jpg" />
2. Check if the image is in the view port or visible in the screen. To do this we
will calculate the difference between the image and the screen with a buffer.
We are using buffer so that image could be loaded even if it is half visible only.
//Buffer
let inAdvance = 100;
//Buffer
let inAdvance = 50;
There are scenarios where we may invoke functions when it isn’t necessary. For
example, consider a scenario where we want to make an API call to the server on a
button click.
If the user spam’s the click then this will make API call on each click. This is
not what we want, we want to restrict the no of API calls that can be made. The
other call will be made only after a specified interval of time.
Debouncing and Throttling help us to gain control over the rate at which function
is called or executes.
btn.addEventListener('click', throttle(function() {
return console.log('HOLA! oppo', new Date().toUTCString());
}, 1000));
Then what is the difference between debouncing and throttling?
Debouncing:- It is used to invoke/call/execute function only when things have
stopped happening for a given specific time. For example, Call a search function to
fetch the result when the user has stopped typing in the search box. If the user
keeps on typing then reset the function.
Excessively invoking the function majorly hampers the performance in javascript and
considered as one of the key hurdles.
There are scenarios where we may invoke functions when it isn’t necessary. For
example, consider a callback function that we want to execute on the window resize.
It does not make any sense to call the function as we keep resizing.
We need to execute the callback function only when the resizing is finished.
Debouncing and Throttling help us to gain control over the rate at which function
is called or executes.
We created a function that will return a function. The outer function uses a
variable to keep track of time for the execution of the inner function.
The inner function will be called only after a specified window of time, to achieve
this we use setTimeout function inDebounce = setTimeout(() => func.apply(context,
args), delay);.
We store the reference of delayed function so that we can clear it if the outer
function is re-invoked before the specified time clearTimeout(inDebounce) and again
recall it.
If we are invoking for the first time, our function will execute at the end of our
delay. If we invoke and then reinvoke again before the end of our delay, the delay
restarts.
btn.addEventListener('click', debounce(function() {
console.info('HOLA! oppo', new Date().toUTCString());
}, 3000));
//true
This may seem to be working fine, but this approach fails when we change the order
of the elements.
//"{'a':1,'b':2,'c':3}" "{'b':2,'a':1,'c':3}"
console.log(JSON.stringify(a) === JSON.stringify(b));
//false
Comparing only arrays (Single and Multi dimensional).
We will create our own custom function which will compare only two different
arrays.
let result;
return result
}
console.log(compare([1,2,3],[1,2,3]));
// true
console.log(compare([1,2],[1,2,3]));
//false
// If the two inputs are not the same type, return false
if (currentType !== otherType) return false;
// Compare properties
if (currentType === '[object Array]') {
for (var i = 0; i < currentLen; i++) {
// Compare the item
if (equal(current[i], other[i]) === false) return false;
}
} else {
for (var key in current) {
if (current.hasOwnProperty(key)) {
// Compare the item
if (equal(current[key], other[key]) === false) return false;
}
}
}
Ques: Implement your own map, reduce, filter or any new array method in Javascript
| Prototypes
Javascript has many inbuilt methods for Javascript Array. In this blog, we will
implement our own map, reduce, filter methods. We will also learn to write any
custom method for Javascript Arrays.
Implement your own map, reduce, filter or any new array method in Javascript |
Prototypes
All the inbuilt methods are part of Array Prototype and they can can access the
array that’s calling the function by referring to the current scope. You can read
about prototypes and prototype chain if you aren’t aware of it.
Let’s implement a custom function sum:
var arr = [1,2,3];
arr.sum()
Output: 6
In order to implement this we should understand that this doesn’t work as normal
function. We have to add sum method to Array Prototype.
Array.prototype.sum = function(){
var sum = 0;
for(var i=0;i<this.length;i++){
sum =+ this[i];
}
return sum
}
Adding a sum method to Array.prototype gives us access to the current scope, which
is nothing but arr.
We can access arr by using “this” as this refers to the current scope on which this
method is called.
What we can see here is that we are trying to implement the logic for sum inside
the sum method. But in order to create map, reduce, filter, we need to implement a
method that can take the modifier from outside in order to make it more generic.
Array.prototype.map = function(callback){
var mapArray = [];
for(var i=0;i<this.length;i++){
mapArray.push(callback(this[i]))
}
return mapArray
}
arr.map((n) => {
return n+1;
})
Output: [2,3,4]
Here we can see that we are taking the modifier from outside in form of callback.
Callback is responsible for modifying the data of the original array. We are giving
user the flexibility to write its own map.
arr.filter((n) => {
return n == 1;
})
Output: [1]
And Reduce,
Array.prototype.reduce = function(callback, accumulator){
for(var i=0;i<this.length;i++){
accumulator =+callback(accumulator,this[i])
}
return accumulator
}
arr.reduce((n,m) => {
return n+m;
}, 0)
Output: 6
Conclusion: I hope you liked my post on How to Memoize any Function in Javascript |
Memoization. This is how we can optimize any performance heavy function. Please
comment if you want to share your solution. Memoization is also an important
Javascript Interview Question which you should be aware of.
CDN – Content Delivery Network or CDN comes as big rescue if you want scale
website. CDN helps you to serve all your static and dynamic assets through its
servers across the world. Even if traffic is increasing exponentially, CDN makes
sure that all requests are distributed across the world with requests being served
from nearest servers. This also decreases load time. Your servers can focus on
other stuff.
Load Balancing – Load balancing is very effective in scaling a website. As the name
suggests, load balancing is a process of distributing network traffic across
different servers. In this way, if one server is free then load balancer will
direct traffic to that server decreasing the load on current servers. This process
is done by using couple of algorithms like round robin, IP hash etc.
Caching – Local Caching which involves storing external resources locally and
looking up next time when same resources are requested. Centralized Caching focuses
on loading data once and sharing it across multiple devices. All can connect to
same store and pull in resources, Redis can be using for this purpose
More servers – It’s a no-brainer. Bigger and better server always help in handling
more traffic
Reduce Bandwidth usage – Whenever your server receives a lot of traffic, it’s
important to decrease bandwidth usage. This effectively leads to increase in page
speed, as load on server decreases. This can be done by compressing your code and
other resources.
JS Find function searches for the item in Javascript array and returns the first
item that satisfies the search criteria.
You might find Javascript developers using JS Filter method to find an item in an
array but it has a major drawback.
JS Filter function goes through all the items in JS Array and returns an array of
all items that meets the search criteria.
So, using JS Find Function or Javascript Array.Find(), we can avoid that and finish
our search as soon as we hit the first target.
Now, let’s focus on how can we implement Array.Find() or JS Find for any given
array:
var Array = ["john doe", "naomi kims", "dan jones", "ravi ks"];
Array.find(function(item){
return item === "john doe"
});
Now, if you try to do same with Array.Filter() over Javascript Find() then you
might have to do
var Array = ["john doe", "naomi kims", "dan jones", "ravi ks"];
Array.filter(function(item){
return item === "john doe"
})[0];
So, we can avoid extra iteration as well as step to access first element of JS
Array using Array.find().
But there might be scenarios when there is more than one record and you want all
records to be returned. In that case use, JS Filter over JS Find.
Questions related to javascript find method are sometimes asked in Javascript
Interview.
Here is an implementation of Array.find() in Javascript objects where it makes more
sense.
Suppose we have to find an object where age is 20.
var Array = [{
name: " John Doe",
age: 20
},
{
name: "Raavi",
age: 30
},
{
name: "K Shay",
age: 20
}];
Using Javascript Find(),
var Result = Array.find(function(item) {
return item.age === 20
})
Sum(1)(2)(3)
Currying: Currying is basically transforming sum(1,2,3) into sum(1)(2)(3). I will
be covering currying in details in another post. Let’s look at the code:
Case 1: add(1)(2)(3)
It’s basically a sequence of functions with single argument. So our approach is to
return a function which in turn returns another function to accept next argument.
function add(a){
return function(b){
return function(c){
return a+b+c
}
}
}
Case 2: add(1)(2)(3)…(n)()
It’s basically a sequence of n+1 functions with single argument except the last
one. So our approach is to return a function which in turn returns another function
to accept next argument and so on till the last argument doesn’t exist.
function add(a) {
return function(b){
if(b){
return add(a+b)
}
return a
}
}
Case 3: sum(1,2)(3,4)
So, this is similar as above just that we are accepting two arguments in single
call. So, we need to add the arguments. Let’s look at the code:
function sum(a,b) {
return function(c,d){
return a+b+c+d
}
}
So, it’s making sense now. Now let’s raise the complexity.
Case 4: add(1,2..n)(5,6…n)…(n)()
Now in this case, everything is infinite. We already know infinite currying, let’s
focus on infinite arguments.
function add(...args) {
let a = args.reduce((a, b) => a + b, 0)
return function(...args){
let b = args.reduce((a, b) => a + b, 0)
if(b){
return add(a+b)
}
return a
}
}
So this is complex, right? You won’t be asked this question during your initial
years of Javascript Interview but you never know. So, what’s happening here is, we
are using inbuilt rest operators to take infinite arguments and then calculating
the sum of all arguments. Rest remains the same as case 2.
Now, this solution is intended for people with less than 1 YOE in Javascript. If
you have better understanding of Javascript, you can go ahead with the below
solution in order to flatten a nested array in Javascript:
Ques: Makemytrip
Iterating though nested objects and listing all the key value pairs. You have to
check the type of value and when it’s a object go deeper till you find the last key
value pair, otherwise just list the key value pair.
Writing a function that can memoize any function including recursive ones.
Transform a function to give certain output, it was based on IIFE concept.
Deep vs Shallow copy of Javascript Object
Throttle based question on optimising search.
Few output questions based on Closure, Higher Order Functions and Hoisting etc
UI Mockup
Tech Stack and Architecture of the application. Local states/Redux/ContextApi
states.
Total functions and code for each function.
Caching, PWA, background sync implementation, scaling.
Redux vs ContextApi vs Passing Props
Call Stack related questions
How will setTimeOut respond inside for loop and using IIFE and let inside it.
Advanced JS: Interviewer needed in depth answers. He told me that i should have
more knowledge as i am a senior software engineer but i was a software engineer
with 2 Yrs working experience at the time of Interview.
What are Generator Function(function*) and output questions based on it(yield,
next).
Callback to Promise conversion and vice versa.
Logic behind Pure Components in React, useMemo vs useCallback, how does react
implement these methods.
Async Await with Promise based output questions including nesting etc
Ques: Flipkart
Prototypal Inheritance in Javscript and how does prototype chain works?
What is a reduce function in Javascript. How to write a polyfill of a reduce
function? He wanted me to cover all cases while writing a pollyfill of reduce. You
can check MDN documentation for that.
How does Redux Saga works, what problem it solves and how can we achieve our goals
without redux saga?
How does closures work?
How will i design a calendar? What controls will i make? What events will i attach?
How will i render a numbers in calendar for every month? And a bunch of other
calendar related questions. I had to write functions, CSS layouts etc. I nailed
this round.
Interviewer asked some popular Javascript Interview Questions.
3. Data Structures and Problem Solving: Interviewer was a back end engineer i
guess as he was not familiar of in built JS methods.
Given a string, reverse only the alphabets keeping rest of the character at the
same place
Find all pairs in an array where sum is equal to a certain number(You can create a
JS Object and then directly look for sum-num in Object)
I don’t remember as it has been a while since interview happened but it was a DP
based question(You have to use memoization to solve this)
Ques: wallmart
Questions based on currying with 4 different variations. I have written a detailed
post on it. ADD(1)(2)(3)…(N)() IN JAVASCRIPT | SUM(1,2)(3,4) | CURRYING | This
question went on for a long time as interviewer kept coming up with difficult
variations.
How does closures work in Javacript? Closure based output questions.
Drawing shapes in CSS using box modal? You can approach this by using borders to
create shapes like triangle etc.
Inheritance in Javascript and how to implement it in ES5?
Scope based questions(value of “this” under certain conditions) etc.
Virtual DOM and Shadow DOM implementation. How does react reconciliation works?
// No TypeError
person.name = "gfg";
console.log(person.name);
Object.freeze() method: If you want the value of the person object to be immutable,
you have to freeze it by using the Object.freeze() method.
<script>
const person = Object.freeze({name: "Geeksforgeeks"});
// TypeError
person.name = "gfg";
</script>
The Object.freeze() method is shallow, meaning that it can freeze the properties of
the object, not the objects referenced by the properties.
Example 2:
const person = Object.freeze({
name: 'Geeksforgeeks',
address: {
city:"Noida"
}
});
But the person.address object is not immutable, you can add a new property to the
person.address object as follows:
// No TypeError
person.address.country = "India";
Conclusion:
const prevents reassignment.
Object.freeze() prevents mutability.
Slice ( )
The slice( ) method copies a given part of an array and returns that copied part as
a new array. It doesn’t change the original array.
array.slice(from, until);
Splice ( )
The name of this function is very similar to slice( ). This naming similarity often
confuses developers. The splice( ) method changes an array, by adding or removing
elements from it. Let’s see how to add and remove elements with splice( ):
Removing Elements
For removing elements, we need to give the index parameter, and the number of
elements to be removed:
array.splice(index, number of elements);
Index is the starting point for removing elements. Elements which have a smaller
index number from the given index won’t be removed:
array.splice(2); // Every element starting from index 2, will be removed
If we don’t define the second parameter, every element starting from the given
index will be removed from the array:
let arr = [1,2,3,"hello",4.12,true];
arr.splice(2);
//[3,"hello",4.12,true]
arr now => [1,2]
As a second example, I give the second parameter as 1, so elements starting from
index 2 will be removed one by one each time we call the splice ( )method:
array.splice(2, 1);
Arr at beginning
let arr = [1,2,3,"hello",4.12,true];
After 1st call:
arr
[1,2,"hello",4.12,true]
3 is removed so “hello world” has now index 2
After 2nd call
arr
[1,2,4.12,true]
This time, “hello world” is removed as index: 2
This can continue until there is no index 2 anymore.
Adding Elements
For adding elements, we need to give them as the 3rd, 4th, 5th parameter (depends
on how many to add) to the splice ( ) method:
array.splice(index, number of elements, element, element);
As an example, I’m adding a and b in the very beginning of the array and I remove
nothing:
array.splice(0, 0, 'a', 'b');
arr.splice(0,0,"a","b");
[]
arr
["a","b",1,2,3,"hello",4.12,true]
a and b added to the beginning of array, no elements removed
Split ( )
Slice( ) and splice( ) methods are for arrays. The split( ) method is used for
strings. It divides a string into substrings and returns them as an array. It takes
2 parameters, and both are optional.
string.split(separator, limit);
Separator: Defines how to split a string… by a comma, character etc.
Limit: Limits the number of splits with a given number
The split( ) method doesn’t work directly for arrays. However, we can first convert
the elements of our array to a string, then we can use the split( ) method.
Let’s see how it works.
Firstly, we convert our array to a string with toString( ) method:
let myString = array.toString();
let mystring = arr.toString();
undefined
myString
"1,2,3,"hello",4.12,true"
Now let’s split myString by commas, limit them to three substrings, and return them
as an array:
let newArray = myString.split(",", 3);
["1","2","3"]
Only the first 3 elements are returned
As we can see, myString is split by commas. Since we limit split to 3, only the
first 3 elements are returned.
NOTE: If we have a usage like this: array.split(""); then each character of the
string will be divided as substrings:
Each character split one by one
Multiple params require parentheses. With simple expression return is not needed:
(param1, paramN) => expression
Arrow functions do not have their own this. Another example involving
Object.defineProperty():
'use strict';
var obj = {
a: 10
};
Object.defineProperty(obj, 'b', {
get: () => {
console.log(this.a, typeof this.a, this); // undefined 'undefined' Window {...}
(or the global object)
return this.a + 10; // represents global object 'Window', therefore 'this.a'
returns 'undefined'
}
});
// call
var result = add.call(obj, 1, 2, 3) // establishing the scope as "obj"
console.log(result) // result 106
// apply
const arr = [1, 2, 3]
var result = add.apply(obj, arr) // establishing the scope as "obj"
console.log(result) // result 106
// bind
var result = add.bind(obj) // establishing the scope as "obj"
console.log(result(1, 2, 3)) // result 106
With Arrow functions, since our add function is essentially created on the window
(global) scope, it will assume this is the window.
// ----------------------
// Arrow Example
// ----------------------
// Arrow Function
var add = (a, b, c) => this.num + a + b + c;
// call
console.log(add.call(obj, 1, 2, 3)) // result 2026
// apply
const arr = [1, 2, 3]
console.log(add.apply(obj, arr)) // result 2026
// bind
const bound = add.bind(obj)
console.log(bound(1, 2, 3)) // result 2026
Perhaps the greatest benefit of using Arrow functions is with DOM-level methods
(setTimeout, setInterval, addEventListener) that usually required some kind of
closure, call, apply or bind to ensure the function executed in the proper scope.
Traditional Example:
var obj = {
count : 10,
doSomethingLater : function (){
setTimeout(function(){ // the function executes on the window scope
this.count++;
console.log(this.count);
}, 300);
}
}
var obj = {
count : 10,
doSomethingLater : function(){
// The traditional function binds "this" to the "obj" context.
setTimeout( () => {
// Since the arrow function doesn't have its own binding and
// setTimeout (as a function call) doesn't create a binding
// itself, the "obj" context of the traditional function will
// be used within.
this.count++;
console.log(this.count);
}, 300);
}
}
obj.doSomethingLater();
No binding of arguments
Arrow functions do not have their own arguments object. Thus, in this example,
arguments is a reference to the arguments of the enclosing scope:
arr(); // 1
function foo(n) {
var f = () => arguments[0] + n; // foo's implicit arguments binding. arguments[0]
is n
return f();
}
foo(3); // 3 + 3 = 6
In most cases, using rest parameters is a good alternative to using an arguments
object.
function foo(n) {
var f = (...args) => args[0] + n;
return f(10);
}
foo(1); // 11
Use of the new operator
Arrow functions cannot be used as constructors and will throw an error when used
with new.
Arrow functions don't have their own “this”, and they don’t redefine the value of
“this ”within the function.
Regardless of how you execute arrow functions, this inside an arrow function always
refers to this from the outer context. This means that this keyword is lexically
bound in arrow functions.
To understand it better, let’s consider the above example of Method Invocation with
an arrow function to see the difference:
var variable = “Global Level Variable”;
let myObject = {
variable: “Object Level Variable”,
arrowFunction:() => {
console.log(this.variable);
},
regularFunction(){
console.log(this.variable);
}
};
myObject.arrowFunction(); // Print Global Level Variable
myObject.regularFunction(); // Print Object Level Variable
This behavior of arrow functions makes them really useful when using callbacks
inside methods.
You don't need to use workarounds like const self = this or callback.bind(this)
with arrow functions, and it prevents any mistakes that can be caused by the use of
this within callbacks.
2. Arguments Object.
In regular JavaScript functions, arguments keywords can be used to access the
passed arguments when the function is invoked.
For example, If I call a function with 3 arguments, I will be able to access them
using arguments keyword like this:
function exampleFunction() {
console.log(arguments[0]);
console.log(arguments[1]);
console.log(arguments[2]);
}
exampleFunction(1,2,3)
Output:
1
2
3
But, arrow functions do not have their own arguments and it uses the arguments from
the outer function.
The behavior of the arguments keyword within an arrow function is similar to the
behavior of this keyword we discussed earlier, and it is resolved lexically.
let exampleFunction = {
printArguments : () => {
console.log(arguments);
}
}
exampleFunction.printArguments(1,2,3)
Output: Reference error: argumensts is not defined
However, if you want to access arguments directly in an arrow function, you can use
the rest parameters feature:
let exampleFunction = {
printArguments : (…args) => {
console.log(…args);
}
}
exampleFunction.printArguments(1,2,3);
Output: 1 2 3
4. Implicit return
In regular functions, we can use the return keyword to return any value from a
function. If we don’t return anything, the function will implicitly return
undefined.
function exampleFunction() {
return 10;
}
exampleFunction(); // output -> 10
--------------------------------------------------------------------
function exampleFunction() {
var number = 10;
}
exampleFunction(); // output -> undefined
--------------------------------------------------------------------
function exampleFunction() {
var number = 10;
return;
}
exampleFunction(); // output -> undefined
Arrow functions behave in the same way when returning values. But there is one
advantage you can take from it.
If the arrow function contains one expression, you can omit the curly braces, and
then the expression will be implicitly returned.
const addOne = (number) => number + 1;
addOne(10);
Output: 11
Final Thoughts
In this article, I have discussed some significant differences between regular
functions and arrow functions in JavaScript. Based on the results and advantages,
you might feel that arrow functions are better than regular functions.
But, that’s not true for all cases, and there are some situations you should avoid
using arrow functions.
It is recommended to use regular functions when dealing with Promises, Callback
functions with dynamic context, and Object methods.
So, as a developer, you should understand these differences to identify the best
matching function type for your requirement.
let person = {
firstName: 'John',
lastName: 'Doe'
};
Code language: JavaScript (javascript)
In practice, you often need to create many similar objects like a list of persons.
To do this, you can use a constructor function to define a custom type and the new
operator to create multiple objects from this type.
The name of a constructor function starts with a capital letter like Person,
Document, etc.
A constructor function should be called only with the new operator.
Note that ES6 introduces the class keyword that allows you to define a custom type.
And classes are just syntactic sugar over the constructor functions with some
enhancements.
To create a new instance of the Person, you use the new operator:
// return this;
}
Code language: JavaScript (javascript)
Therefore, the following statement:
let person = {
firstName: 'John',
lastName: 'Doe'
};
Code language: JavaScript (javascript)
However, the constructor function Person allows you to create multiple similar
objects. For example:
this.getFullName = function () {
return this.firstName + " " + this.lastName;
};
}
Code language: JavaScript (javascript)
Now, you can create a new Person object and invoke the getFullName() method:
John Doe
The problem with the constructor function is that when you create multiple
instances of the Person, the this.getFullName() is duplicated in every instance.
This is not memory efficient.
To resolve this, you can use the prototype so that all instances of a custom type
can share the same method.
If return is called with an object, the constructor function returns that object
instead of this.
If return is called with a value other than an object, it’s ignored.
Calling a constructor function without the new keyword
It’s possible to call a constructor function without the new keyword like this:
If you attempt to access the firstName or lastName property, you’ll get an error:
console.log(person.firstName);
Code language: CSS (css)
Error:
person.getFullName();
Code language: CSS (css)
Error:
If a constructor function is called with the new keyword, the new.target returns a
reference to the function. Otherwise, it returns undefined.
Let’s show the value of the new.target to the console inside the Person function:
this.getFullName = function () {
return this.firstName + " " + this.lastName;
};
}
Code language: JavaScript (javascript)
The following returns undefined because the Person constructor function is called
like a regular function:
undefined
Code language: JavaScript (javascript)
However, the following returns a reference to the Person function because it’s
called with the new keyword:
[Function: Person]
Code language: JSON / JSON with Comments (json)
By leveraging the new.target, you can force users of the constructor function to
call it with the new keyword. And you can throw an error if they don’t do so like
this:
this.firstName = firstName;
this.lastName = lastName;
}
Code language: JavaScript (javascript)
Alternatively, you can make the syntax more flexible by creating a new Person
object if the users of the constructor function don’t use the new keyword:
this.firstName = firstName;
this.lastName = lastName;
}
console.log(person.firstName);
Code language: JavaScript (javascript)
This pattern is often used in JavaScript libraries and frameworks to make the
syntax more flexible.
Summary
JavaScript constructor function is a regular function used to create multiple
similar objects.
Since most modern kernels are multi-threaded, they can handle multiple operations
executing in the background. When one of these operations completes, the kernel
tells Node.js so that the appropriate callback may be added to the poll queue to
eventually be executed.
Poll phase: All the synchronous JavaScript code you write is executed in the poll
phase of the event loop.
console.log(1);
console.log(2);
O/p: 1 & 2
setImmediate(() => {
console.log('immediate'); // check phase
});
process.nextTick(() => {
console.log('nextTick'); //
});
// timeout_vs_immediate.js
setTimeout(() => {
console.log('timeout');
}, 0);
setImmediate(() => {
console.log('immediate');
});
$ node timeout_vs_immediate.js
timeout
immediate
$ node timeout_vs_immediate.js
immediate
timeout
However, if you move the two calls within an I/O cycle, the immediate callback is
always executed first:
// timeout_vs_immediate.js
const fs = require('fs');
fs.readFile(__filename, () => {
setTimeout(() => {
console.log('timeout'); //timer phase
}, 0);
setImmediate(() => {
console.log('immediate'); //check phase
});
console.log(1); //poll phase
});
$ node timeout_vs_immediate.js
immediate
timeout
$ node timeout_vs_immediate.js
immediate
timeout
The main advantage to using setImmediate() over setTimeout() is setImmediate() will
always be executed before any timers if scheduled within an I/O cycle or inside any
other callback, independently of how many timers are present.
Ques: process.nextTick()
Ans: You may have noticed that process.nextTick() was not displayed in the diagram,
even though it's a part of the asynchronous API. This is because process.nextTick()
is not technically part of the event loop. Instead, the nextTickQueue will be
processed after the current operation is completed, regardless of the current phase
of the event loop. Here, an operation is defined as a transition from the
underlying C/C++ handler, and handling the JavaScript that needs to be executed.
Looking back at our diagram, any time you call process.nextTick() in a given phase,
all callbacks passed to process.nextTick() will be resolved before the event loop
continues. This can create some bad situations because it allows you to "starve"
your I/O by making recursive process.nextTick() calls, which prevents the event
loop from reaching the poll phase.
The term “Event Loop” is a generic programming pattern. It describes a simple loop
which iterates through the results of completed events, and process them.
JavaScript/NodeJS event loops are no different.
When JavaScript applications run, they fire various events, and these events will
cause corresponding event handlers to be enqueued for processing. The event loop
continuously watches for any queued event handlers and will process them
accordingly.
Both the browser and NodeJS implements an asynchronous event-driven pattern with
JavaScript. However, the “Events”, in a browser’s context, are user interactions on
web pages (e.g, clicks, mouse movements, keyboard events etc.), but in Node’s
context, events are asynchronous server-side operations (e.g, File I/O access,
Network I/O etc.). Due to this difference of needs, Chrome and Node have different
Event Loop implementations, though they share the same V8 JavaScript engine to run
JavaScript.
Since “the event loop” is nothing but a programming pattern, V8 allows the ability
to plug-in an external event loop implementation to work with its JavaScript
runtime. Using this flexibility, the Chrome browser uses libevent as its event loop
implementation, and NodeJS uses libuv to implement the event loop. Therefore,
chrome’s event loop and NodeJS’s event loop are based on two different libraries
and which have differences, but they also share the similarities of the common
“Event Loop” programming pattern.
https://www.youtube.com/watch?v=ELNFqCOQhjs
Ques: What is a inline and block level elements in html
Ques: Diff between inline and inline block elements
Ques: What is total size of local storage.
Ques: What are the semantic elements in html
Ques: What is a box model
Ques: What is css specificity
Ques: In a div I have 10 divs, we want to show 5 div in a row each, how to do in
css
Ques: What is virtual DOM in react
Ques: Explain react class component life cycle
Ques: What is the use of shouldComponentUpdate method
Ques: Diff between react component and react.pure component
Ques: In react what are the methods in which we can write react setSate
Ques: what if I write setState in react.render method? (it will recursively
rerender itself - it will go to infinity lean and return error - execeeded stack)
Ques: What is higher order component
Ques: What is use of redux
Ques: In redux what connect method do
Ques: Remove duplicates from array
Ques: Get array of values from object
const x = {
a: 1,
b:2
}
Ans:
const xarr= [];
for (let i in x) {
xarr.push(x[i]);
}
Ques:
const x = {
a: 1,
b:2,
getA() {
console.log(this.a);
},
getB() {
console.log(this.b);
}
}
what modification will you do to print both consoles using below statement
x.getA().getB();
Ans:
const x = {
a: 1,
b:2,
getA() {
console.log(this.a);
return this;
},
getB() {
console.log(this.b);
}
}
Ques: Can (a==1 && a==2 && a==3) ever evaluate to true? If yes what will be value
of a.
The answer is — Yes
const a = {
num: 0,
valueOf: function() {
return this.num += 1
}
};
const equality = (a==1 && a==2 && a==3);
console.log(equality); // true
Reason: when you check loose equality with two different types of operators,
JavaScript will attempt to perform type coercion — it will attempt to coerce
(convert) the operands into a like/similar type.
In our equation: (a==1 && a==2 && a==3), JavaScript will attempt to coerce the
object a into a number prior to comparing them. When performing type coercion on an
object, JavaScript first attempts to call the valueOf() method.
Parts of a box
Making up a block box in CSS we have the:
Content box: The area where your content is displayed, which can be sized using
properties like width and height.
Padding box: The padding sits around the content as white space; its size can be
controlled using padding and related properties.
Border box: The border box wraps the content and any padding. Its size and style
can be controlled using border and related properties.
Margin box: The margin is the outermost layer, wrapping the content, padding, and
border as whitespace between this box and other elements. Its size can be
controlled using margin and related properties.
The below diagram shows these layers:
If we assume that a box has the following CSS defining width, height, margin,
border, and padding:
.box {
width: 350px;
height: 150px;
margin: 10px;
padding: 25px;
border: 5px solid black;
}
Copy to Clipboard
The actual space taken up by the box will be 410px wide (350 + 25 + 25 + 5 + 5) and
210px high (150 + 25 + 25 + 5 + 5).
Showing the size of the box when the standard box model is being used.
Note: The margin is not counted towards the actual size of the box — sure, it
affects the total space that the box will take up on the page, but only the space
outside the box. The box's area stops at the border — it does not extend into the
margin.
Semantic
Non-Semantic
Semantic Elements: Semantic elements have meaningful names which tells about type
of content. For example header, footer, table, … etc. HTML5 introduces many
semantic elements as mentioned below which make the code easier to write and
understand for the developer as well as instructs the browser on how to treat them.
article: It contains independent content which doesnt require any other context.
aside: It is used to place content in a sidebar i.e. aside the existing content. It
is related to surrounding content.
details
figcaption: These are used to add an image in a web page with small description.
figure
footer
header:it is for the header of a section introductory of a page. There can be
multiple headers on a page.
main
mark
nav: It is used to define a set of navigation links in the form of navigation bar
or nav menu.
section
Article
Example: Blog Post, Newspaper Article etc.
In this second example, it is shown how to create an easily scalable Express server
and how to allow a single server process to take advantage of the cluster module
with a few lines of code.
if(cluster.isMaster) {
var numWorkers = require('os').cpus().length;
cluster.on('online', function(worker) {
console.log('Worker ' + worker.process.pid + ' is online');
});
} else {
var app = require('express')();
app.all('/*', function(req, res) {res.send('process ' + process.pid + ' says
hello!').end();})
To view the messages, set up a procedure that recognizes the message event for both
the master and worker side:
worker.on('message', function(message){
console.log(message);
});
Within the code, the worker object is the reference returned by the fork ()
method .
process.on('message', function(message) {
console.log(message);
});
Messages can be strings or JSON objects. To send one, for example, from parent to
child process (from master to worker ), you can try the command:
worker.send({
type: 'task 1',
from: 'master',
data: {
// the data that you want to transfer
}
});
/***************************************
Property Descriptors Methods and Usage
Object.defineProperty(obj, propName, {} )
Object.defineProperties(obj, props)
Object.getOwnPropertyNames(obj)
Object.getOwnPropertyDescriptor(obj, prop)
Object.getOwnPropertyDescriptors(obj)
Object.keys(obj) - list of enumerable properties
Object.values(obj) - list of enumerable prop values
obj.propertyIsEnumerable(prop)
obj.hasOwnProperty(prop)
Objects can be
1. Extensible - new properties added
2. Frozen - props cannot be changed in any way
3. Sealed - props can't be deleted or configured
but are still writable
Object PROPERTIES can be
1. Writable - change the value
2. Enumerable - seen through a for...in loop
3. Configurable - change the property descriptors
Object.isExtensible(obj)
Object.isFrozen(obj)
Object.isSealed(obj)
Object.preventExtensions(obj)
Object.freeze(obj)
Object.seal(obj)
Descriptor Groups
DATA ACCESSOR
value get
writable set
configurable configurable
enumerable enumerable
****************************************/
let log = console.log;
let obj = {
name: 'Bob',
age: 45
};
Object.defineProperty(obj, 'test', {
value: 'Shagadelic',
writable: true,
configurable: true,
enumerable: false
} );
Object.defineProperty(obj, 'frank', {
configurable:true,
enumerable: true,
get: () => this.value,
set: (_val) => {
this.value = _val + " baby!";
}
});
Cons:
>Proxying is tricky
>L/7 Load balancer challanginf (Timeouts)
>Stateful, difficult to horizontally scale
Ques: What is pipe and compose in js and its polyfill for compose
Ans :- https://lnkd.in/gf2QXtmG
What is compose function , its polyfill and minor tweaks to make it more generic.
Ans:-
Refer here https://lnkd.in/g8vjMJCq
:- Coding question
Design custom JSON . parse method which takes a string and return json.
Couldn't solve it
https://developer.mozilla.org/en-US/docs/Learn/Performance/What_is_web_performance
https://www.digitalocean.com/community/questions/how-do-i-pass-client-ip-in-a-
kubernetes-cluster-to-my-nodejs-application
Ques: Given a multidimensional array with depth of n, flatten it. Once flattened
make it available as a method on array instance
Solution
/**
* [1,2,[3,4]] -> [1,2,3,4]
*/
function flatten(arr) {
return arr.reduce(function(acc, next){
let isArray = Array.isArray(next)
return acc.concat(isArray ? flatten(next) : next)
}, [])
}
if (!Array.prototype.flatten) {
Array.prototype.flatten = function() {
return flatten(this)
}
}
console.log(arr.flatten());
Ques: Create a promise from scratch
Solution
class CustomPromise {
state = "PENDING"
value = undefined
thenCallbacks = []
errorCallbacks = []
constructor(action) {
action(this.resolver.bind(this), this.reject.bind(this))
}
resolver(value) {
this.state = "RESOLVED"
this.value = value
this.thenCallbacks.forEach((callback) => {
callback(this.value)
})
}
reject(value) {
this.state = "REJECTED"
this.value = value
this.errorCallbacks.forEach((callback) => {
callback(this.value)
})
}
then(callback) {
this.thenCallbacks.push(callback)
return this
}
catch (callback) {
this.errorCallbacks.push(callback)
return this
}
}
promise
.then(function(response){
console.log(response)
})
.catch(function(error){
console.log(error)
})
Ques: Filter movie list by average rating, name. Sort filtered list by any field
inside movie object
Ans:// O(M)
function getMovies() {
return []; // [{id, name, year}]
}
// O(R)
function getRatings() {
return []; // [{id, movie_id, rating}] 0 <= rating <= 10 // e.g 9.3
}
/**
* minAvgRating ->
* avgRating >= minAvgRating
*
* sort ->
* name -> ascending order movies by name
* -name -> descending
*
* avgRating
*
*
* search ->
* 'ave' -> 'Avengers'
* 'avengers' -> 'Avengers'
* 'AvengersInfinitywar' -> 'Avengers'
*/
const toLower = str => str.toLocaleLowerCase()
Ques: Given an end point URL to fetch all the posts and comments. Do the following.
Map all the comments to the posts it belongs to. The resultant data after mapping
should be of below structure.
{
postId: [commentId, commentId]
}
Ans:
//service.js
const POSTS_URL = `https://jsonplaceholder.typicode.com/posts`;
const COMMENTS_URL = `https://jsonplaceholder.typicode.com/comments`;
fetchData();
if (!String.prototype.getHashCode) {
String.prototype.getHashCode = function(){
console.log('String instance ', this)
return this
}
}
//reduce
Array.prototype.reduce = function(func, initState) {
const arr = this
const callback = func
let init = initState
arr.forEach(function(value, index){
init=callback(init, value)
})
return init
}
if (allowEvents) {
callback.apply(context, args)
allowEvents = false;
timerId = setTimeOut(function(){
allowEvents = true
}, interval)
}
}
}
Ques: Design API polling mechanism. The API is called after a fixed interval. The
API is a stock API that fetches the latest price of stock. Upon fetching the
results, render the UI.
The question demands the design aspect of the solution and not the code. It was
open ended question.
Solution
//With setInterval, throttling and flags
setInterval=>Endpoint=>Render
Parent.prototype.getName = function() {
return this.name
}
function Children(name){
Parent.call(this, name)
}
x = 0;
console.log(x, y);
//Q.2
var x = [1];
var y = x;
x = [];
console.log(x,y);
//Q.3
function Abc() { console.log(this); };
Abc()
new Abc();
//Q.4
var x = 1;
var obj = {
x: 2,
getX: function () {
return console.log(this.x);
}
};
obj.getX()
let a = obj.getX
console.log(a)
//Q.5
//How to get the a to log 2 in the above code
//Q.6
console.log("A");
setTimeout(() => console.log("B"), 0);
setTimeout(() => console.log("C"), 0);
console.log("D");
//Q.7
setTimeout(function() {
console.log("A");
}, 0);
Promise.resolve().then(function() {
console.log("B");
}).then(function() {
console.log("C");
});
console.log("D");
//Q.8
let obj1 = {
a:1,
b:2
}
function mutate(obj) {
obj = {a:4, c:6}
}
console.log(obj1)
mutate(obj1)
console.log(obj1)
Solution
//A.1
0 1
//A.2
[] [1]
//A.3
window object is logged
//A.4
logs 2 and 1
//A.5
a.call(obj);
//A.6
A, D, B , C
//A.7
D, B, C, A
//A.8
{ a: 1, b: 2 }
{ a: 1, b: 2 }
Ques:Given an array of numbers implement the following
const list = [1,2,3,4,5,6,7,8]
const filteredArray = list.filter(between(3, 6)) // [4,5]
Solution
function between(start, end) {
return function (value,index) {
return value>start && value<end
}
}
https://dev.to/devabhijeet/all-front-end-interview-questions-asked-during-my-
recent-job-hunt-1kge
https://github.com/devAbhijeet/job-hunt-interview-questions-2020