« Javascript interview questions

What are the different data types present in javascript?

To know the type of a JavaScript variable, we can use the typeof operator.

  1. 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.

1var str = 'Vivek Singh Bisht'; //using double quotes
2var str2 = 'John Doe'; //using single quotes

Number - It represents a number and can be written with or without decimals.

1var x = 3; //without decimal
2var y = 3.6; //with decimal

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.

1var bigInteger = 234567890123456789012345678901234567890;

Boolean - It represents a logical entity and can have only two values : true or false. Booleans are generally used for conditional testing.

1var a = 2;
2var b = 3;
3var c = 2;
4a == b;
5a == c;

Undefined - When a variable is declared but not assigned, it has the value of undefined and it’s type is also undefined.

1var x; // value of x is undefined
2var y = undefined; // we can also set the value of a variable as undefined

Null - It represents a non-existent or a invalid value.

1var z = null;

Symbol - It is a new data type introduced in the ES6 version of javascript. It is used to store an anonymous and unique value.

1var symbol1 = Symbol('symbol');
2typeof of primitive types :
3typeof "John Doe" // Returns "string"
4typeof 3.14 // Returns "number"
5typeof true // Returns "boolean"
6typeof 234567890123456789012345678901234567890n // Returns bigint
7typeof undefined // Returns "undefined"
8typeof null // Returns "object" (kind of a bug in JavaScript)
9typeof Symbol('symbol') // Returns Symbol
  1. 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.

1var obj1 = {
2 x: 43,
3 y: 'Hello world!',
4 z: function () {
5 return this.x;
6 },
7};

// Collection of data as an ordered list

1var array1 = [5, 'Hello', true, 4.1];

Note- It is important to remember that any data type that is not a primitive data type, is of Object type in javascript.

Explain Hoisting in javascript

Hoisting is the default behaviour of javascript where all the variable and function declarations are moved on top.

This means that irrespective of where the variables and functions are declared, they are moved on top of the scope. The scope can be both local and global.

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;

Difference between “ == “ and “ === “ operators.

Both are comparison operators. The difference between both the operators is that "==" is used to compare values whereas, "===" is used to compare both values and types.

1var x = 2;
2var y = '2';
3x == y; // Returns true since the value of both x and y is the same
4x === y; // Returns false since the typeof x is "number" and typeof y is "string"

Difference between var, let and const keywords in JavaScript

var_let_const.png

Objects in javascript

Now each value of each keys we have here can be any type in JavaScript, it can be a number, a string, a boolean, null, undefined, it can even be another object, or an array, or a function.

Function vs Methods

If a function is part of an object, in object oriented programming terms, we refer to that function as a method.

Factory functions

1function createCircle(radius) {
2 // return {
3 // radius: radius,
4 // draw: function(){
5 // console.log('circle draw method called fronm factory function');
6 // }
7 // };
8 return {
9 radius,
10 draw() {
11 console.log('circle draw method called from factory function');
12 },
13 };
14}
15
16const circle1 = createCircle(5);
17circle1.draw();

Constructor function

When we use the new operator, 3 things happen:

  • this operator first creates an empty object
  • then it will set this to point to this object
  • and finally it will return that object from this function.
1function Circle(radius) {
2 this.radius = radius;
3 this.draw = function () {
4 console.log('draw from Constructor function');
5 };
6}
7
8const circle2 = new Circle(7);
9circle2.draw();

Objects in JavaScript

Objects in JavaScript are dynamic which means once you create them you can always add new properties or methods, or remove existing ones.

1const myCircle = {
2 radius: 5,
3};
4
5console.log(myCircle);
6myCircle.color = 'red';
7console.log(myCircle);
8myCircle.draw = function () {};
9console.log(myCircle);
10delete myCircle.color;
11console.log(myCircle);
12delete myCircle.radius;
13console.log(myCircle);

Every object in javascript has a property called constructor

And that references the function that was used to construct or create that object.

1function createCircle(radius){
2 // return {
3 // radius: radius,
4 // draw: function(){
5 // console.log('circle draw method called fronm factory function');
6 // }
7 // };
8 return {
9 radius,
10 draw(){
11 console.log('circle draw method called from factory function');
12 }
13 };
14}
15
16const circle1 = createCircle(5);
17circle1.draw();
18
19circle1.constructor
20ƒ Object() { [native code] }
21
22function Circle(radius){
23 this.radius = radius;
24 this.draw = function(){
25 console.log('draw from Constructor function');
26 }
27}
28
29const circle2 = new Circle(7);
30circle2.draw();
31
32circle2.constructor
33ƒ Circle(radius){
34 this.radius = radius;
35 this.draw = function(){
36 console.log('draw from Constructor function');
37 }
38}

This is a built it constructor function in javascript. When we create an object using object literal syntax, internally the JavaScript engine uses this constructor function.

1ƒ Object() { [native code] }

In JavaScript we have a few other built in constructors,

So, single quotes or double code, or back tick. Using these literals is cleaner and simpler than using the constructor.

1const an =""
2an.constructor
3ƒ String() { [native code] }
1new String();
2new Boolean();
3new Number();

Functions are objects

1Circle.constructor
2ƒ Function() { [native code] }

When we declare a function using this syntax, internally, JavaScript engine will use this function constructor to create this object.

Internally, JavaScript engine will use this Function constructor to create this object.

In Javascript we have 2 categories of types

Value types:

  • Number
  • String
  • Boolean
  • Symbol
  • undefined
  • null

Value types:

  • Objects
  • Functions
  • Arrays

Objects are not iterables

for of loop can only be used with iterables

Constructor Object Function

Whenever we create object using object literal syntax internally that is translated to a call to this constructor function.

Internally this

1const x = { value: 1 };

is translated to

1const x = new Object();

Object keys

This method returns string array of keys.

1for (let key of Object.keys(circle)) {
2 console.log(key);
3}

Object Entries

1for (let key of Object.entries(circle)) {
2 console.log(key);
3}

Check if a key exists in object

1if ('radius' in circle) console.log('yes');

Cloning Object

Object.assign

1const circle = {
2 radius: 1,
3 draw: function () {
4 console.log('draw');
5 },
6};
7
8const another1 = Object.assign({}, circle);
9const another2 = Object.assign({ color: 'red' }, circle);
10
11console.log(another1);
12console.log(another2);

spread operator

1const circle = {
2 radius: 1,
3 draw: function () {
4 console.log('draw');
5 },
6};
7
8const another = { ...circle };
9console.log(another);

Garbage Collector

A javascript engine has a garbage collector. It finds constants and variables and then de-allocate the memory that was allocated to them. Memory allocation and de-allocation happens automatically behind the scenes and I have no control over that. We can't tell Garbage Collector when to run and de-allocate which objects from the memory.

Math Object

Math.round(1.9)

Math object

1console.log(Math.round(1.9));
2console.log(Math.max(1, 2, 6, 0, -2));
3console.log(Math.min(1, 2, 6, 0, -2));

String

In javascript we have 2 types of strings. One is primitive string another is string object. When we use the dot notation with a string primitive, JavaScript engine internally wraps this with a string object, we don't see that, but we can work with this like a string object.

1const message = 'Anish';
2console.log(typeof message);
3const another = new String('Dubey');
4console.log(typeof another);
1const message = 'This is my first message';
2console.log(typeof message);
3const another = new String('Dubey');
4console.log(typeof another);
5
6console.log(message.length);
7console.log(message[0]);
8console.log(message[1]);
9console.log(message.includes('An'));
10console.log(message.includes('an'));
11console.log(message.includes('my'));
12console.log(message.includes('This'));
13console.log(message.includes('this'));
14console.log(message.startsWith('This'));
15console.log(message.startsWith('me'));
16console.log(message.endsWith('message'));
17console.log(message.endsWith('me'));
18console.log(message.indexOf('me'));
19console.log(message.replace('first', 'second'));
20console.log(message);
21console.log(message.toUpperCase());
22console.log(message.toLowerCase());
23console.log(message);
24
25const unTrimmedMessage = ' This is my untrimmed message. ';
26console.log(unTrimmedMessage.trim());
27console.log(unTrimmedMessage);
28
29const newLineMessage = 'This is my\n first message';
30console.log(newLineMessage);
31
32const escapeCharMessage = "This is my 'first message";
33console.log(escapeCharMessage);
34
35console.log(message.split(' '));

Template literals

1const name = 'Anish';
2
3const message = `Hi ${name} ${2 + 3}
4
5Thank you for joining my mailing list
6
7Regards
8Anish
9`;
10
11console.log(message);

Date

1const now = new Date();
2const date1 = new Date('May 11 2018 09:00');
3const date2 = new Date(2017, 4, 11, 9);
4
5console.log(now);
6console.log(date1);
7console.log(date2);
8
9now.setFullYear(2005);
10console.log(now);

Object Equality

1let address1 = new Address('a', 'b', 'c');
2let address2 = new Address('a', 'b', 'c');
3let address3 = address1;
4
5function Address(street, city, zipCode) {
6 this.street = street;
7 this.city = city;
8 this.zipCode = zipCode;
9}
10
11function areEqual(address1, address2) {
12 return (
13 address1.street === address2.street &&
14 address1.city === address2.city &&
15 address1.zipCode === address2.zipCode
16 );
17}
18
19function areSame(address1, address2) {
20 return address1 === address2;
21}
22
23console.log(areEqual(address1, address2));
24console.log(areSame(address1, address2));
25console.log(areSame(address1, address3));

Adding elements in Array

1const numbers = [3, 4, 1, 3];
2
3numbers.push(5, 6);
4numbers.unshift(1, 2);
5numbers.splice(2, 0, 'a', 'b');
6console.log(numbers);
7
8console.log(numbers.indexOf(1));
9console.log(numbers.indexOf(4));
10console.log(numbers.indexOf(9));
11
12console.log(numbers.lastIndexOf(1));
13
14console.log(numbers.includes(5));
15console.log(numbers.includes(9));
16
17console.log(numbers.indexOf(1));
18console.log(numbers.indexOf(1, 3));

All these methods have second parameter that is optional that is starting index.

Array find method

1const courses = [
2 { id: 1, name: 'a' },
3 { id: 2, name: 'b' },
4];
5
6const course = courses.find(function (course) {
7 return course.name === 'a';
8});
9
10console.log(course);
11
12const course1 = courses.find(function (course) {
13 return course.name === 'xyz';
14});
15
16console.log(course1);
17
18const courseIndex = courses.findIndex(function (course) {
19 return course.name === 'xyz';
20});
21
22console.log(courseIndex);
23
24const courseIndex1 = courses.findIndex(function (course) {
25 return course.name === 'b';
26});
27
28console.log(courseIndex1);

If not found then undefined will be returned and if found that particular element of the array is returned.

Shorter way using arrow functions.

1const courses = [
2 { id: 1, name: 'a' },
3 { id: 2, name: 'b' },
4];
5
6const course = courses.find((course) => course.name === 'a');
7
8console.log(course);

Removing elements from Array

1const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
2
3const last = numbers.pop();
4console.log(last);
5console.log(numbers);
6
7const first = numbers.shift();
8console.log(first);
9console.log(numbers);
10
11numbers.splice(2, 3);
12console.log(numbers);

Emptying the array

1let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
2let another = numbers;
3
4// This won't work if we have multiple references to the original array
5numbers = [];
6
7console.log(numbers);
8console.log(another);
1let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
2let another = numbers;
3
4numbers.length = 0;
5
6console.log(numbers);
7console.log(another);
1let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
2let another = numbers;
3
4numbers.splice(0, numbers.length);
5
6console.log(numbers);
7console.log(another);
1let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
2let another = numbers;
3
4//This is not ideal where we have a million elements Because then pop will be called a million times
5while (numbers.length > 0) {
6 numbers.pop();
7}
8
9console.log(numbers);
10console.log(another);

Combining and slicing arrays

1const first = [1, 2, 3, 4];
2const second = [7, 8, 9, 10];
3
4const combined = first.concat(second);
5
6console.log({ combined });
7console.log({ first });
8console.log({ second });
9
10const slice = combined.slice(2, 5);
11
12console.log({ slice });
13console.log({ combined });
14
15const slice1 = combined.slice(2);
16console.log({ slice1 });
17
18// this will copy the entire array
19const combined2 = combined.slice();
20console.log({ combined2 });

In both these methods if we are dealing with primitive values then these primitive values will be copied to the new array. But if you have objects inside array then those are not copied their references are copied that means input in both the arrays will point to the same object.

1const first = [1, 2, 3, { id: 5 }];
2const second = [7, 8, 9, 10];
3
4const combined = first.concat(second);
5
6first[3].id = 115;
7
8console.log({ combined });
9console.log({ first });
10console.log({ second });

Shorter using spread operator

1const first = [1, 2, 3, { id: 5 }];
2const second = [7, 8, 9, 10];
3
4const combined = [...first, ...second];
5const combined1 = [...first, 'a', ...second, 'b'];
6
7console.log({ combined });
8console.log({ combined1 });
9console.log({ first });
10console.log({ second });

Iterating through array

1const numbers = [1, 2, 3, { id: 5 }];
2
3for (let num of numbers) {
4 console.log(num);
5}
6
7numbers.forEach(function (num) {
8 console.log(num);
9});
10
11numbers.forEach((num) => console.log(num));
12numbers.forEach((num, index) => console.log(index, num));

Joining Arrays

1const numbers = [1, 2, 3, 4];
2const joined = numbers.join(',');
3console.log(joined);
4
5const message = 'This is my message';
6const parts = message.split(' ');
7console.log(parts);
8
9console.log(parts.join('-'));

Sorting Arrays

1const numbers = [2, 3, 1];
2numbers.sort();
3console.log(numbers);
4
5numbers.reverse();
6console.log(numbers);

sorting objects

1const courses = [
2 { id: 1, name: 'Nodejs' },
3 { id: 2, name: 'javascript' },
4];
5console.log(courses);
6
7courses.sort(function (a, b) {
8 const nameA = a.name.toLowerCase();
9 const nameB = b.name.toLowerCase();
10
11 if (nameA < nameB) return -1;
12 if (nameA > nameB) return 1;
13
14 return 0;
15});
16
17console.log(courses);

Testing elements of array

every method & some method

1const numbers = [1, -1, 2, 3];
2
3const allPositive = numbers.every(function (value) {
4 return value >= 0;
5});
6
7console.log(allPositive);
8
9const atLeastOnePositive = numbers.some(function (value) {
10 return value >= 0;
11});
12
13console.log(atLeastOnePositive);

As soon as every finds an element that doesn't match this criteria, it's going to stop searching.

As soon as some finds an element that matches this criteria, it's going to return true.

Filtering Arrays

1const numbers = [1, -1, 2, 3];
2
3const filtered = numbers.filter(function (value) {
4 return value >= 0;
5});
6
7console.log(filtered);

shorter using arrow functions.

1const numbers = [1, -1, 2, 3];
2
3const filtered = numbers.filter((value) => value >= 0);
4
5console.log(filtered);

Mapping an array

these don't modify original array. They return new array;

1const numbers = [1, -1, 2, 3];
2const items = numbers.map((n) => '<li>' + n + `</li>`);
3const html = '<ul>' + items.join('') + '</ul>';
4console.log(html);
5
6const items1 = numbers.map((n) => {
7 const obj = { value: n };
8 return obj;
9});
10
11console.log(items1);

Chaining methods

1const numbers = [1, -1, 2, 3];
2const items = numbers
3 .filter((n) => n >= 0)
4 .map((n) => ({ value: n }))
5 .filter((obj) => obj.value > 1)
6 .map((obj) => obj.value);
7
8console.log(items);

Reducing an array

1let numbers = [1, -1, 2, 3];
2
3let sum = 0;
4
5for (let number of numbers) {
6 sum = sum + number;
7}
8
9console.log(sum);
10
11numbers = [1, 2, 3];
12
13const ans = numbers.reduce((accumulator, currentValue) => {
14 return accumulator + currentValue;
15}, 0);
16
17console.log(ans);

This callback function is executed multiple times, each time this currentValue will be set to one element in this array. So in each call, we want to get this currentValue and add it to accumulator.

Now we can make this code even shorter. We can exclude the initialization of the accumulator, and with this, accumulator will be set to the first element and currentValue to be the second element.

1let numbers = [1, 2, 3];
2
3const ans = numbers.reduce((accumulator, currentValue) => {
4 return accumulator + currentValue;
5});
6
7console.log(ans);

Functions

We can use the function declaration syntax or function expression which basically involves declaring a variable or a constant.

1//Function declaration
2function walk() {
3 console.log('walk');
4}
5
6//Anonymous function expression
7const run = function () {
8 console.log('walk');
9};
10
11//Named function expression
12const run1 = function walk1() {
13 console.log('walk');
14};
15
16let move = run;
17
18run();
19walk();
20run1();
21move();

Hoisting in Javascript

We can call a function that is defined using the function declaration syntax before it's definition. The reason for this is because when our JavaScript engine executes this code, it moves all the function declarations to the top.

Hoisting is the process of moving function declarations to the top of the file. And this is done automatically by the JavaScript engine that is executing this code.

1walk();
2function walk() {
3 console.log('walk');
4}
5
6// run(); // this will give error Cannot access 'run' before initialization
7const run = function () {
8 console.log('walk');
9};

Javascript is a dynamic language

JavaScript is a dynamic language, so we can declare a variable, set it to a number and then change its type and set it to a string and that perfectly fine from the perspective of a JavaScript engine.

1let x = 1;
2console.log(x);
3
4x = 'a';
5console.log(x);

Arguments

But in JavaScript, it doesn't matter that if a function has 2 parameters, we can pass only 1 argument. We can even pass no arguments.

1function sum(a, b) {
2 return a + b;
3}
4
5console.log(sum(1, 2));
6console.log(sum(1)); //a=1 b=undefined so answer is NaN
7console.log(sum()); //a=undefined b=undefined so answer is NaN

We can even pass additional arguments.

Every function in JavaScript has a special object called arguments. arguments has a length property that returns the number of arguments that are passed. We have this other property, callee which returns the currently executed function, so you see we have a reference to our sum function.

We can use the for of loop, on arrays, but technically this loop can be used on any object that has an iterator. So the plain objects that we create with the object literal syntax, they don't have an iterator, but this particular object you can see, here we have symbol.iterator.

1function sum(a, b) {
2 console.log(arguments);
3 return a + b;
4}
5
6console.log(sum(1, 2, 3, 4, 5));
7
8function sum1(a, b) {
9 let total = 0;
10 for (let value of arguments) {
11 total = total + value;
12 }
13 return total;
14}
15
16console.log(sum1(1, 2, 3, 4, 5));
17
18function sum2() {
19 let total = 0;
20 for (let value of arguments) {
21 total = total + value;
22 }
23 return total;
24}
25
26console.log(sum2(1, 2, 3, 4, 5, 10));

The rest operator

1function sum(...args) {
2 console.log(args);
3 return args.reduce((a, b) => a + b);
4}
5
6console.log(sum(1, 2, 3, 4, 5));

Rest parameter must be last formal parameter. So we cannot have a parameter after using the rest operator.

Default Parameter

Whenever you want to give the function parameter a default value, make sure that parameter is the last parameter in the list, or give all the parameters after that a default value.

1function interest(principal, rate, years) {
2 rate = rate || 3.5;
3 years = years || 5;
4 return ((principal * rate) / 100) * years;
5}
6console.log(interest(10000));
7
8function interest(principal, rate = 3.5, years = 5) {
9 return ((principal * rate) / 100) * years;
10}
11console.log(interest(10000));

getter setter

1const person = {
2 firstname: 'Anish',
3 secondname: 'Kumar',
4 get fullName() {
5 return `${this.firstname} ${this.secondname}`;
6 },
7 set fullName(value) {
8 const parts = value.split(' ');
9 this.firstname = parts[0];
10 this.secondname = parts[1];
11 },
12};
13
14console.log(person.fullName);
15console.log(person.firstname);
16console.log(person.secondname);
17
18person.fullName = 'John smith';
19
20console.log(person.fullName);
21console.log(person.firstname);
22console.log(person.secondname);

Try Catch

1const person = {
2 firstname: 'Anish',
3 secondname: 'Kumar',
4 get fullName() {
5 return `${this.firstname} ${this.secondname}`;
6 },
7 set fullName(value) {
8 if (typeof value !== 'string') {
9 throw new Error('Value is not a string');
10 }
11 const parts = value.split(' ');
12 if (parts.length !== 2) {
13 throw new Error('Enter a first and second name');
14 }
15 this.firstname = parts[0];
16 this.secondname = parts[1];
17 },
18};
19
20try {
21 person.fullName = null;
22} catch (e) {
23 alert(e);
24}

Scope

So a scope of a variable or a constant, determines where that variable or constant is accessible.

1{
2 const name = 'ansih';
3}
4
5// console.log(name); //ReferenceError: name is not defined
1function start() {
2 const message = 'hi';
3
4 if (true) {
5 const another = 'bye';
6 }
7
8 // console.log(another); //ReferenceError: another is not defined
9}
10
11start();
1function start() {
2 for (let i = 0; i < 10; i++) {
3 console.log(i);
4 }
5 //console.log(i); //ReferenceError: i is not defined
6}
7
8start();
1const color = 'red'; //global scope
2
3function start() {
4 console.log(color);
5}
6
7function stop() {
8 console.log(color);
9}
10
11start();
12
13stop();

let vs var

When you declare a variable with var. It's scope, is not limited to the block in which it's defined. It's limited to the function in which it's defined.

So before ES6, var was the only way to declare variables and constants. Starting from ES6, also called ES2015, now we have two new keywords let and const, to define different variables and constants.

These two keywords create block scope variables, but var creates function scoped variables.

1function start() {
2 for (let i = 0; i < 10; i++) {
3 console.log(i);
4 }
5 //console.log(i); //ReferenceError: i is not defined
6}
7
8start();
1function start() {
2 for (var i = 0; i < 10; i++) {
3 console.log(i);
4 }
5 console.log(i);
6}
7
8start();

When we use var, outside of a function, this creates a global variable and attaches that global variable to the window object in the browser. So in browsers we have this window object, which is a complex object with lots of proprties.

In contrast when we use the let keyword to define a global variable, that global variable is not attached to the window object.

If a third party library also has a variable with the same name, that variable can override your variable.

1var color = 'red';
2let age = 30;
3
4//So technically this is a global function, it's attached to the window object and that is bad practice.
5function sayHi() {
6 console.log('HI');
7}

this

when you use the new operator this new operator creates a new empty object and sets this in this constructor function to point to this empty object.

1const video = {
2 title: 'a',
3 play: function () {
4 console.log(this);
5 },
6};
7
8video.stop = function () {
9 console.log(this);
10};
11
12video.play();
13video.stop();
14
15function playVideo() {
16 console.log(this); // we are going to see the global object which is window in browsers and global in Node.
17}
18playVideo();
19
20function Video() {
21 this.title = 'kumar';
22 this.name = 'manish';
23 console.log(this);
24}
25
26const v = new Video();
1const video = {
2 title: 'a',
3 tags: ['a', 'b', 'c'],
4 showTags() {
5 this.tags.forEach(function (tag) {
6 console.log(this, tag);
7 });
8 },
9};
10
11// showTags function is just a regular function. It's not a method in the video object. So because this is a regular function, this references the global object
12video.showTags();
13
14//for each method has two parameters,the first parameter is our callback function, the second parameter is thisArg? So we can pass an object here, and this will reference that object. For example, here I can pass a new object
15
16const video1 = {
17 title: 'a',
18 tags: ['a', 'b', 'c'],
19 showTags() {
20 this.tags.forEach(function (tag) {
21 console.log(this, tag);
22 }, this);
23 },
24};
25
26video1.showTags();

Changing this

1const video = {
2 title: 'a',
3 tags: ['a', 'b', 'c'],
4 showTags() {
5 const self = this;
6 this.tags.forEach(function (tag) {
7 console.log(self.title, tag);
8 });
9 },
10};
11video.showTags();
1function playVideo(a, b) {
2 console.log(this);
3}
4
5playVideo();
6
7playVideo.call({ title: 'call' }, 1, 2);
8
9playVideo.apply({ title: 'apply' }, [1, 2]);
10
11fn = playVideo.bind({ title: 'bind' });
12playVideo();
13fn();
1const video = {
2 title: 'a',
3 tags: ['a', 'b', 'c'],
4 showTags() {
5 this.tags.forEach(
6 function (tag) {
7 console.log(this.title, tag);
8 }.bind(this)
9 );
10 },
11};
12video.showTags();

Arrow functions inherit this from the containing function.

1const video = {
2 title: 'a',
3 tags: ['a', 'b', 'c'],
4 showTags() {
5 this.tags.forEach((tag) => {
6 console.log(this.title, tag);
7 });
8 },
9};
10video.showTags();

Array.isArray

1console.log(sum(1, 2, 3, 4));
2
3function sum(...items) {
4 return items.reduce((a, b) => a + b);
5}
6
7console.log(sum2([1, 2, 3, 4]));
8
9function sum2(...items) {
10 if (items.length === 1 && Array.isArray(items[0])) {
11 items = items[0];
12 }
13 return items.reduce((a, b) => a + b);
14}

calculate circle area

1const circle = {
2 radius: 1,
3 get area() {
4 return Math.PI * this.radius * this.radius;
5 },
6};
7
8console.log(circle.area);

What is the output of the following code?

1const b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
2
3for (let i = 0; i < 10; i++) {
4 setTimeout(() => console.log(b[i]), 1000);
5}
6
7for (var i = 0; i < 10; i++) {
8 setTimeout(() => console.log(b[i]), 1000);
9}
11
22
33
44
55
66
77
88
99
1010
11undefined
12undefined
13undefined
14undefined
15undefined
16undefined
17undefined
18undefined
19undefined
20undefined

In JavaScript, how do you turn an Object into an Array []?

1let obj = { id: '1', name: 'user22', age: '26', work: 'programmer' };
2//Method 1: Convert the keys to Array using - Object.keys()
3console.log(Object.keys(obj));
4// ["id", "name", "age", "work"]
5
6// Method 2 Converts the Values to Array using - Object.values()
7console.log(Object.values(obj));
8// ["1", "user22r", "26", "programmer"]
9
10// Method 3 Converts both keys and values using - Object.entries()
11console.log(Object.entries(obj));
12//[["id", "1"],["name", "user22"],["age", "26"],["work", “programmer"]]

Write the code to find the vowels

1const findVowels = (str) => {
2 let count = 0;
3 const vowels = ['a', 'e', 'i', 'o', 'u'];
4 for (let char of str.toLowerCase()) {
5 if (vowels.includes(char)) {
6 count++;
7 }
8 }
9 return count;
10};

Write the code given If two strings are anagrams of one another, then return true.

1var firstWord = 'Deepak';
2var secondWord = 'Aman';
3
4isAnagram(firstWord, secondWord); // true
5
6function isAnagram(one, two) {
7 //Change both words to lowercase for case insensitivity..
8 var a = one.toLowerCase();
9 var b = two.toLowerCase();
10
11 // Sort the strings, then combine the array to a string. Examine the outcomes.
12 a = a.split('').sort().join('');
13 b = b.split('').sort().join('');
14
15 return a === b;
16}

Write the code for dynamically inserting new components.

1<html>
2 <head>
3 <title>inserting new components dynamically</title>
4 <script type="text/javascript">
5 function addNode() {
6 var newP = document.createElement('p');
7 var textNode = document.createTextNode(' This is other node');
8 newP.appendChild(textNode);
9 document.getElementById('parent1').appendChild(newP);
10 }
11 </script>
12 </head>
13 <body>
14 <p id="parent1">firstP</p>
15 <p></p>
16 </body>
17</html>

Implement a function that returns an updated array with r right rotations on an array of integers a .Example:

1function rotateRight(arr, rotations) {
2 if (rotations == 0) return arr;
3 for (let i = 0; i < rotations; i++) {
4 let element = arr.pop();
5 arr.unshift(element);
6 }
7 return arr;
8}
9rotateRight([2, 3, 4, 5, 7], 3); // Return [4,5,7,2,3]
10rotateRight([44, 1, 22, 111], 5); // Returns [111,44,1,22]

Write a function that performs binary search on a sorted array.

1function binarySearch(arr,value,startPos,endPos){
2 if(startPos > endPos) return -1;
3
4 let middleIndex = Math.floor(startPos+endPos)/2;
5
6 if(arr[middleIndex] === value) return middleIndex;
7
8 elsif(arr[middleIndex > value]){
9 return binarySearch(arr,value,startPos,middleIndex-1);
10 }
11 else{
12 return binarySearch(arr,value,middleIndex+1,endPos);
13 }
14}

Modify Code

1// Each time bigFunc is called, an array of size 700 is being created,
2// Modify the code so that we don't create the same array again and again
3
4function bigFunc(element) {
5 let newArray = new Array(700).fill('♥');
6 return newArray[element];
7}
8
9console.log(bigFunc(599)); // Array is created
10console.log(bigFunc(670)); // Array is created again
1function bigFunc() {
2 let newArray = new Array(700).fill('♥');
3 return (element) => newArray[element];
4}
5
6let getElement = bigFunc(); // Array is created only once
7getElement(599);
8getElement(670);

Guess the output

1(function (a) {
2 return (function () {
3 console.log(a);
4 a = 23;
5 })();
6})(45);
145

Guess the output

1(function (a) {
2 return (function () {
3 a = 23;
4 console.log(a);
5 })();
6})(45);
123

Guess the output

1let hero = {
2 powerLevel: 99,
3 getPower() {
4 return this.powerLevel;
5 },
6};
7
8let getPower = hero.getPower;
9
10let hero2 = { powerLevel: 42 };
11console.log(getPower());
12console.log(hero.getPower());
13console.log(getPower.apply(hero2));
1undefined
299
342

Guess the output

1const a = function () {
2 console.log(this);
3
4 const b = {
5 func1: function () {
6 console.log(this);
7 },
8 };
9
10 const c = {
11 func2: () => {
12 console.log(this);
13 },
14 };
15
16 b.func1();
17 c.func2();
18};
19
20a();
1global/window object
2object "b"
3global/window object

Guess the output

1const b = {
2 name: 'Vivek',
3 f: function () {
4 var self = this;
5 console.log(this.name);
6 (function () {
7 console.log(this.name);
8 console.log(self.name);
9 })();
10 },
11};
12b.f();
1"Vivek"
2undefined
3"Vivek"

Guess the output

1var x = 23;
2
3(function () {
4 var x = 43;
5 (function random() {
6 x++;
7 console.log(x);
8 var x = 21;
9 })();
10})();
1NaN

Guess the output

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:

1function random() {
2 var x; // x is hoisted
3 x++; // x is not a number since it is not initialized yet
4 console.log(x); // Outputs NaN
5 x = 21; // Initialization of x
6}

Guess the output

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’.

Both x[y] and x[z] are referencing the same property.

1let x = {},
2 y = { name: 'Ronny' },
3 z = { name: 'John' };
4x[y] = { name: 'Vivek' };
5x[z] = { name: 'Akki' };
6console.log(x[y]);
1{ name: 'Akki' }

Guess the output

1function runFunc() {
2 console.log('1' + 1);
3 console.log('A' - 1);
4 console.log(2 + '-2' + '2');
5 console.log('Hello' - 'World' + 78);
6 console.log('Hello' + '78');
7}
111
2NaN
32-22
4NaN
5Hello78

Guess the output

1let a = 0;
2let b = false;
3console.log(a == b);
4console.log(a === b);
1true
2false

Guess the output

1function func1() {
2 setTimeout(() => {
3 console.log(x);
4 console.log(y);
5 }, 3000);
6
7 var x = 2;
8 let y = 12;
9}
10func1();
12
212

Outputs 2 and 12. Since, even though let variables are not hoisted, due to the async nature of javascript, the complete function code runs before the setTimeout function. Therefore, it has access to both x and y.

Guess the output

1function func2() {
2 for (var i = 0; i < 3; i++) {
3 setTimeout(() => console.log(i), 2000);
4 }
5}
6func2();
13
23
33

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.

Guess the output

1function(){
2 setTimeout(()=> console.log(1),2000);
3 console.log(2);
4 setTimeout(()=> console.log(3),0);
5 console.log(4);
6 }
7)();
12
24
33
41

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.

What are the primitive data types in JavaScript?

  • Boolean
  • Undefined
  • Null
  • Number
  • String

What is Object Destructuring?

1const classDetails = {
2 strength: 78,
3 benches: 39,
4 blackBoard: 1,
5};
6
7const {
8 strength: classStrength,
9 benches: classBenches,
10 blackBoard: classBlackBoard,
11} = classDetails;
12
13console.log(classStrength); // Outputs 78
14console.log(classBenches); // Outputs 39
15console.log(classBlackBoard); // Outputs 1
16
17const { strength: strength } = classDetails;
18// The above line of code can be written as:
19const { strength } = classDetails;

Weakmap

In javascript, Map is used to store key-value pairs. The key-value pairs can be of both primitive and non-primitive types. WeakMap is similar to Map with key differences:

  • The keys and values in weakmap should always be an object.
  • If there are no references to the object, the object will be garbage collected.
1const map1 = new Map();
2map1.set('Value', 1);
3
4const map2 = new WeakMap();
5map2.set('Value', 2.3); // Throws an error
6
7let obj = { name: 'Vivek' };
8const map3 = new WeakMap();
9map3.set(obj, { age: 23 });

WeakSet

In javascript, a Set is a collection of unique and ordered elements. Just like Set, WeakSet is also a collection of unique and ordered elements with some key differences:

Weakset contains only objects and no other type.

An object inside the weakset is referenced weakly. This means, that if the object inside the weakset does not have a reference, it will be garbage collected.

Unlike Set, WeakSet only has three methods, add() , delete() and has() .

1const newSet = new Set([4, 5, 6, 7]);
2console.log(newSet); // Outputs Set {4,5,6,7}
3
4const newSet2 = new WeakSet([3, 4, 5]); //Throws an error
5
6let obj1 = { message: 'Hello world' };
7const newSet3 = new WeakSet([obj1]);
8console.log(newSet3.has(obj1)); // true

What are generator functions?

Introduced in the ES6 version, generator functions are a special class of functions. They can be stopped midway and then continue from where they had stopped. Generator functions are declared with the function* keyword instead of the normal function keyword.

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:

1function normalFunc() {
2 return 22;
3 console.log(2); // This line of code does not get executed
4}

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.

1function* genFunc() {
2 yield 3;
3 yield 4;
4}
5genFunc(); // 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.

For example, if we run the next() method on the above code:

1genFunc().next(); // Returns {value: 3, done:false}

As one can see the next method returns an object consisting of a 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).

What are classes in javascript?

Introduced in the ES6 version, classes are nothing but syntactic sugars for constructor functions. They provide a new way of declaring constructor functions in javascript. Below are the examples of how classes are declared and used:

1// Before ES6 version, using constructor functions
2function Student(name, rollNumber, grade, section) {
3 this.name = name;
4 this.rollNumber = rollNumber;
5 this.grade = grade;
6 this.section = section;
7}
8
9// Way to add methods to a constructor function
10Student.prototype.getDetails = function () {
11 return 'Name: ${this.name}, Roll no: ${this.rollNumber}, Grade: ${this.grade}, Section:${this.section}';
12};
13
14let student1 = new Student('Vivek', 354, '6th', 'A');
15student1.getDetails();
16// Returns Name: Vivek, Roll no:354, Grade: 6th, Section:A
17
18// ES6 version classes
19class Student {
20 constructor(name, rollNumber, grade, section) {
21 this.name = name;
22 this.rollNumber = rollNumber;
23 this.grade = grade;
24 this.section = section;
25 }
26
27 // Methods can be directly added inside the class
28 getDetails() {
29 return 'Name: ${this.name}, Roll no: ${this.rollNumber}, Grade:${this.grade}, Section:${this.section}';
30 }
31}
32
33let student2 = new Student('Garry', 673, '7th', 'C');
34student2.getDetails();
35// Returns Name: Garry, Roll no:673, Grade: 7th, Section:C

37. What is the use of promises in javascript?

Promises are used to handle asynchronous operations in javascript.

Before promises, callbacks were used to handle asynchronous operations. But due to the limited functionality of callbacks, using multiple callbacks to handle asynchronous code can lead to unmanageable code.

Promise object has four states -

  • 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.

Promises are used to handle asynchronous operations like server requests, for ease of understanding, we are using an operation to calculate the sum of three elements.

1function sumOfThreeElements(...elements) {
2 return new Promise((resolve, reject) => {
3 if (elements.length > 3) {
4 reject('Only three elements or less are allowed');
5 } else {
6 let sum = 0;
7 let i = 0;
8 while (i < elements.length) {
9 sum += elements[i];
10 i++;
11 }
12 resolve('Sum has been calculated: ' + sum);
13 }
14 });
15}
16
17sumOfThreeElements(4, 5, 6)
18 .then((result) => console.log(result))
19 .catch((error) => console.log(error));
20// In the code above, the promise is fulfilled so the then() method gets executed
21
22sumOfThreeElements(7, 0, 33, 41)
23 .then((result) => console.log(result))
24 .catch((error) => console.log(error));
25// In the code above, the promise is rejected hence the catch() method gets executed

What are arrow functions?

Arrow functions were introduced in the ES6 version of javascript. They provide us with a new and shorter syntax for declaring functions. Arrow functions can only be used as a function expression.

1// Traditional Function Expression
2var add = function (a, b) {
3 return a + b;
4};
5
6// Arrow Function Expression
7var arrowAdd = (a, b) => a + b;
1var obj1 = {
2 valueOfThis: function () {
3 return this;
4 },
5};
6var obj2 = {
7 valueOfThis: () => {
8 return this;
9 },
10};
11
12obj1.valueOfThis(); // Will return the object obj1
13obj2.valueOfThis(); // Will return window/global object

The biggest difference between the traditional function expression and the arrow function is the handling of this keyword. By general definition, 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 this keyword. 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. Therefore, in the code above, obj2.valueOfThis() returns the window object.

Which method is used to retrieve a character from a certain index?

The charAt() function of the JavaScript string finds a char element at the supplied index. The index number begins at 0 and continues up to n-1, Here n is the string length.

What is DOM? DOM stands for Document Object Model. DOM is a programming interface for HTML and XML documents.

When the browser tries to render an 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.

Example of how HTML code gets converted to DOM:

dom.png

What is the use of a constructor function in javascript?

Constructor functions are used to create objects in javascript.

If we want to create multiple objects having similar properties and methods, constructor functions are used.

Note- The name of a constructor function should always be written in Pascal Notation: every word should start with a capital letter.

1function Person(name, age, gender) {
2 this.name = name;
3 this.age = age;
4 this.gender = gender;
5}
6
7var person1 = new Person('Vivek', 76, 'male');
8console.log(person1);
9
10var person2 = new Person('Courtney', 34, 'female');
11console.log(person2);

26. What is recursion in a programming language?

1function computeSum(arr) {
2 if (arr.length === 1) {
3 return arr[0];
4 } else {
5 return arr.pop() + computeSum(arr);
6 }
7}
8computeSum([7, 8, 9, 99]); // Returns 123

What is memoization?

1function addTo256(num) {
2 return num + 256;
3}
4addTo256(20); // Returns 276
5addTo256(40); // Returns 296
6addTo256(20); // Returns 276
1function memoizedAddTo256() {
2 var cache = {};
3
4 return function (num) {
5 if (num in cache) {
6 console.log('cached value');
7 return cache[num];
8 } else {
9 cache[num] = num + 256;
10 return cache[num];
11 }
12 };
13}
14var memoizedFunc = memoizedAddTo256();
15
16memoizedFunc(20); // Normal return
17memoizedFunc(20); // Cached return

23. What are callbacks?

A callback is a function that will be executed after another function gets executed. In javascript, functions are treated as first-class citizens, they can be used as an argument of another function, can be returned by another function, and can be used as a property of an object.

Functions that are used as an argument to another function are called callback functions. Example:

1function divideByHalf(sum) {
2 console.log(Math.floor(sum / 2));
3}
4
5function multiplyBy2(sum) {
6 console.log(sum * 2);
7}
8
9function operationOnSum(num1, num2, operation) {
10 var sum = num1 + num2;
11 operation(sum);
12}
13
14operationOnSum(3, 3, divideByHalf); // Outputs 3
15
16operationOnSum(5, 5, multiplyBy2); // Outputs 20

Explain Closures in JavaScript.

Closures are an ability of a function to remember the variables and functions that are declared in its outer scope.

1function randomFunc() {
2 var obj1 = { name: 'Vivian', age: 45 };
3
4 return function () {
5 console.log(obj1.name + ' is ' + 'awesome'); // Has access to obj1 even when the randomFunc function is executed
6 };
7}
8
9var initialiseClosure = randomFunc(); // Returns a function
10
11initialiseClosure();

When the function randomFunc() runs, it seems that the returning function is using the variable obj1 inside it:

Therefore randomFunc(), instead of destroying the value of obj1 after execution, saves the value in the memory for further reference. This is the reason why the returning function is able to use the variable declared in the outer scope even after the function is already executed.

This ability of a function to store a variable for further reference even after it is executed is called Closure.

Explain Scope and Scope Chain in javascript.

Scope in JS determines the accessibility of variables and functions at various parts of one’s code.

In general terms, the scope will let us know at a given part of code, what are variables and functions we can or cannot access.

There are three types of scopes in JS:

  • 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.

1var globalVariable = 'Hello world';
2
3function sendMessage() {
4 return globalVariable; // can access globalVariable since it's written in global space
5}
6function sendMessage2() {
7 return sendMessage(); // Can access sendMessage function since it's written in global space
8}
9sendMessage2(); // Returns “Hello world”

Function Scope: Any variables or functions declared inside a function have local/function scope, which means that all the variables and functions declared inside a function, can be accessed from within the function and not outside of it.

1function awesomeFunction() {
2 var a = 2;
3
4 var multiplyBy2 = function () {
5 console.log(a * 2); // Can access variable "a" since a and multiplyBy2 both are written inside the same function
6 };
7}
8console.log(a); // Throws reference error since a is written in local scope and cannot be accessed outside
9
10multiplyBy2(); // Throws reference error since multiplyBy2 is written in local scope

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.

1{
2 let x = 45;
3}
4
5console.log(x); // Gives reference error since x cannot be accessed outside of the block
6
7for (let i = 0; i < 2; i++) {
8 // do something
9}
10
11console.log(i); // Gives reference error since i cannot be accessed outside of the for loop block

Scope Chain: JavaScript engine also uses Scope to find variables. Let’s understand that using an example:

1var y = 24;
2
3function favFunction() {
4 var x = 667;
5 var anotherFavFunction = function () {
6 console.log(x); // Does not find x inside anotherFavFunction, so looks for variable inside favFunction, outputs 667
7 };
8
9 var yetAnotherFavFunction = function () {
10 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
11 };
12
13 anotherFavFunction();
14 yetAnotherFavFunction();
15}
16favFunction();

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, a reference error is thrown.

What is currying in JavaScript?

Currying is an advanced technique to transform a function of arguments n, to n functions of one or fewer arguments.

1function add(a) {
2 return function (b) {
3 return a + b;
4 };
5}
6
7add(3)(4);
1function multiply(a, b) {
2 return a * b;
3}
4
5function currying(fn) {
6 return function (a) {
7 return function (b) {
8 return fn(a, b);
9 };
10 };
11}
12
13var curriedMultiply = currying(multiply);
14
15multiply(4, 3); // Returns 12
16
17curriedMultiply(4)(3); // Also re

Explain this keyword.

1function doSomething() {
2 console.log(this);
3}
4
5doSomething();

Since the function is invoked in the global context, the function is a property of the global object. Therefore, the output of the above code will be the global object.

1var obj = {
2 name: 'vivek',
3 getName: function () {
4 console.log(this.name);
5 },
6};
7
8obj.getName();

In the above code, at the time of invocation, the getName function is a property of the object obj , therefore, this keyword will refer to the object obj, and hence the output will be “vivek”.

1var obj = {
2 name: 'vivek',
3 getName: function () {
4 console.log(this.name);
5 },
6};
7
8var getName = obj.getName;
9
10var obj2 = { name: 'akshay', getName };
11obj2.getName();

The output will be “akshay”.

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.

1var obj1 = {
2 address: 'Mumbai,India',
3 getAddress: function () {
4 console.log(this.address);
5 },
6};
7
8var getAddress = obj1.getAddress;
9var obj2 = { name: 'akshay' };
10obj2.getAddress();

The output will be an error.

Although in the code above, this keyword refers to the object obj2, obj2 does not have the property address, hence the getAddress function throws an error.

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.

1function higherOrder(fn) {
2 fn();
3}
4
5higherOrder(function () {
6 console.log('Hello world');
7});
8function higherOrder2() {
9 return function () {
10 return 'Do something';
11 };
12}
13var x = higherOrder2();
14x(); // Returns "Do something"

What do you mean by strict mode in javascript and characteristics of javascript strict-mode?

In ECMAScript 5, a new feature called JavaScript Strict Mode allows you to write a code or a function in a "strict" operational environment. In most cases, this language is 'not particularly severe' when it comes to throwing errors. In 'Strict mode,' however, all forms of errors, including silent errors, will be thrown. As a result, debugging becomes a lot simpler. Thus programmer's chances of making an error are lowered.

Characteristics of strict mode in javascript

  • Duplicate arguments are not allowed by developers.
  • In strict mode, you won't be able to use the JavaScript keyword as a parameter or function name.
  • The 'use strict' keyword is used to define strict mode at the start of the script. Strict mode is supported by all browsers.
  • Engineers will not be allowed to create global variables in 'Strict Mode.

What is an Immediately Invoked Function in JavaScript?

Syntax of IIFE :

1(function () {
2 // Do something;
3})();

To understand IIFE, we need to understand the two sets of parentheses that are added while creating an IIFE :

The first set of parenthesis:

1(function () {
2 //Do something;
3});

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.

1function() {
2 //Do something;
3}
4// 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.

The second set of parenthesis:

1(function () {
2 //Do something;
3})();

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:

1(function () {
2 // Do something;
3});
4
5// Returns the function declaration

Therefore to invoke the function, we use the second set of parenthesis.

Explain passed by value and passed by reference.

In JavaScript, primitive data types are passed by value and non-primitive data types are passed by reference.

1var y = 234;
2var z = y;

In the above example, the 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.

1var obj = { name: 'Vivek', surname: 'Bisht' };
2var obj2 = obj;

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.

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.

What is NaN property in JavaScript?

NaN property represents the “Not-a-Number” value. It indicates a value that is not a legal number.

typeof of NaN will return a Number.

To check if a value is NaN, we use the isNaN() function,

Note- isNaN() function converts the given value to a Number type, and then equates to NaN.

1isNaN('Hello'); // Returns true
2isNaN(345); // Returns false
3isNaN('1'); // Returns false, since '1' is converted to Number type which results in 0 ( a number)
4isNaN(true); // Returns false, since true converted to Number type results in 1 ( a number)
5isNaN(false); // Returns false
6isNaN(undefined); // Returns true

Is javascript a statically typed or a dynamically typed language?

JavaScript is a dynamically typed language. In a dynamically typed language, the type of a variable is checked during run-time in contrast to a statically typed language, where the type of a variable is checked during compile-time.

What is a potential pitfall with using typeof bar === "object" to determine if bar is an object? How can this pitfall be avoided?

Although typeof bar === "object" is a reliable way of checking if bar is an object, the surprising gotcha in JavaScript is that null is also considered an object!

1var bar = null;
2console.log(typeof bar === 'object'); // logs true!

the problem can easily be avoided by also checking if bar is null:

1console.log(bar !== null && typeof bar === 'object'); // logs false

First, the above solution will return false if bar is a function. In most cases, this is the desired behavior, but in situations where you want to also return true for functions, you could amend the above solution to be:

1console.log(
2 bar !== null && (typeof bar === 'object' || typeof bar === 'function')
3);

However, there’s one other alternative that returns false for nulls, arrays, and functions, but true for objects:

1console.log(bar !== null && bar.constructor === Object);

Define output

1(function () {
2 var a = (b = 3);
3})();
4
5console.log('a defined? ' + (typeof a !== 'undefined'));
6console.log('b defined? ' + (typeof b !== 'undefined'));

Since both a and b are defined within the enclosing scope of the function, and since the line they are on begins with the var keyword, most JavaScript developers would expect typeof a and typeof b to both be undefined

But in fact, var a = b = 3; is actually shorthand for:

1b = 3;
2var a = b;

As a result (if you are not using strict mode), the output of the code snippet would be:

1a defined? false
2b defined? true

But how can b be defined outside of the scope of the enclosing function? Well, since the statement var a = b = 3; is shorthand for the statements b = 3; and var a = b;, b ends up being a global variable (since it is not preceded by the var keyword) and is therefore still in scope even outside of the enclosing function.

Note that, in strict mode (i.e., with use strict), the statement var a = b = 3; will generate a runtime error of ReferenceError: b is not defined

define output

1var myObject = {
2 foo: 'bar',
3 func: function () {
4 var self = this;
5 console.log('outer func: this.foo = ' + this.foo);
6 console.log('outer func: self.foo = ' + self.foo);
7 (function () {
8 console.log('inner func: this.foo = ' + this.foo);
9 console.log('inner func: self.foo = ' + self.foo);
10 })();
11 },
12};
13myObject.func();
1outer func: this.foo = bar
2outer func: self.foo = bar
3inner func: this.foo = undefined
4inner func: self.foo = bar

In the outer function, both this and self refer to myObject and therefore both can properly reference and access foo.

In the inner function, though, this no longer refers to myObject. As a result, this.foo is undefined in the inner function, whereas the reference to the local variable self remains in scope and is accessible there.

Consider the two functions below. Will they both return the same thing? Why or why not?

1function foo1() {
2 return {
3 bar: 'hello',
4 };
5}
6
7function foo2() {
8 return;
9 {
10 bar: 'hello';
11 }
12}

Surprisingly, these two functions will not return the same thing. Rather:

1console.log('foo1 returns:');
2console.log(foo1());
3console.log('foo2 returns:');
4console.log(foo2());

will yield:

1foo1 returns:
2Object {bar: "hello"}
3foo2 returns:
4undefined

Not only is this surprising, but what makes this particularly gnarly is that foo2() returns undefined without any error being thrown.

The reason for this has to do with the fact that semicolons are technically optional in JavaScript (although omitting them is generally really bad form). As a result, when the line containing the return statement (with nothing else on the line) is encountered in foo2(), a semicolon is automatically inserted immediately after the return statement.

No error is thrown since the remainder of the code is perfectly valid, even though it doesn’t ever get invoked or do anything

In what order will the numbers 1-4 be logged to the console when the code below is executed? Why?

1(function () {
2 console.log(1);
3 setTimeout(function () {
4 console.log(2);
5 }, 1000);
6 setTimeout(function () {
7 console.log(3);
8 }, 0);
9 console.log(4);
10})();

The values will be logged in the following order:

11
24
33
42

Write a simple function (less than 160 characters) that returns a boolean indicating whether or not a string is a palindrome.

1function isPalindrome(str) {
2 return str == str.split('').reverse().join('');
3}
4
5console.log(isPalindrome('anishhsina'));

Write a sum method which will work properly when invoked using either syntax below

1function sum(x) {
2 if (arguments.length == 2) {
3 return arguments[0] + arguments[1];
4 } else {
5 return function (y) {
6 return x + y;
7 };
8 }
9}

In JavaScript, functions provide access to an arguments object which provides access to the actual arguments passed to a function. This enables us to use the length property to determine at runtime the number of arguments passed to the function.

1function sum(x, y) {
2 if (y !== undefined) {
3 return x + y;
4 } else {
5 return function (y) {
6 return x + y;
7 };
8 }
9}

When a function is invoked, JavaScript does not require the number of arguments to match the number of arguments in the function definition. If the number of arguments passed exceeds the number of arguments in the function definition, the excess arguments will simply be ignored. On the other hand, if the number of arguments passed is less than the number of arguments in the function definition, the missing arguments will have a value of undefined when referenced within the function. So, in the above example, by simply checking if the 2nd argument is undefined, we can determine which way the function was invoked and proceed accordingly.

Map over an array and reduce it to array

Hoisting

1console.log(foo);
2foo = 1;

Above will throw an error.

1console.log(foo);
2var foo = 2;

This is print undefined. var declaration is bubbled to the top. This is called Hoisting. Above will get converted to

1var foo;
2console.log(foo);
3foo = 2;

This will how it will be interpreted by javascript.

1foo = 2;
2console.log(foo);
3var foo = 3;

Above will print 2. Above will be interpreted as

1var foo;
2foo = 2;
3console.log(foo);
4foo = 3;
1foo();
2
3function foo() {
4 console.log('anish');
5}

This will be interpreted as

1function foo() {
2 console.log('anish');
3}
4
5foo();

Functions are hoisted to the top.

1console.log(a);
2
3const a = 1;

This will throw an error. const and let doesn't get bubbled to the top.