JavaScript Interview Questions for Freshers

Pravin M
35 min readAug 17, 2023
JavaScript Interview Questions for Freshers
JavaScript Interview Questions for Freshers

Source:- JavaScript Developer Interview Questions for Freshers

For more questions and answers visit our website at Frontend Interview Questions

  1. What are the data types in JavaScript ?

In JavaScript, data types can be categorized into two main groups: primitive and non-primitive (also known as reference types) data types. Here’s an explanation of each:

  1. Primitive Data Types:

These are immutable data types that store a single value.

a. Boolean: Represents a logical value, either true or false. It is commonly used for conditions and branching in JavaScript.


let isTrue = true;
let a=5;
let isFalse = false;
console.log(isTrue); // Output: true
console.log(isFalse); // Output: false

b. Number: Represents numeric values, including integers and floating-point numbers.


let count = 10;
let price = 4.99;
console.log(count); // Output: 10
console.log(price); // Output: 4.99
undefined

c. String: Represents a sequence of characters enclosed in single or double quotes. Strings are used to represent textual data.


let message = "Hello, world!";
console.log(message); // Output: Hello, world!
undefined

d. Null: Represents the intentional absence of any object value. It is often assigned to a variable to indicate that it has no value or that the value is unknown.


let value = null;
console.log(value); // Output: null
undefined

e. Undefined: Represents an uninitialized or undeclared variable. If a variable is declared but not assigned a value, it will have the value of undefined.


let variable;
console.log(variable); // Output: undefined
undefined

f. Symbol: Represents a unique identifier. Symbols are typically used as keys in objects to avoid naming conflicts.


let id = Symbol("unique");
console.log(id); // Output: Symbol(unique)
undefined

2. Non-Primitive (Reference) Data Types:

These are mutable data types that store references to memory locations rather than the actual values.

a. Object: Represents a collection of key-value pairs and provides a way to group related data and functionality together. Objects can be created using object literals {}, constructor functions, or the class syntax introduced in ECMAScript 2015.


let person = {
name: "John",
age: 30,
isAdmin: false
};
console.log(person); // Output: { name: 'John', age: 30, isAdmin: false }
undefined

b. Array: Represents an ordered list of values. Arrays can hold values of any type, and their elements are accessed using numeric indices starting from 0.


let numbers = [1, 2, 3, 4, 5];
console.log(numbers); // Output: [1, 2, 3, 4, 5]
undefined

c. Function: Represents executable code that can be invoked and performs a specific task. Functions are one of the fundamental building blocks in JavaScript and can be defined using function declarations or function expressions.


function greet(name) {
console.log("Hello, " + name + "!");
}

greet("Alice"); // Output: Hello, Alice!
undefined

Non-primitive data types, such as objects, arrays, and functions, are passed by reference, meaning that when you assign them to a variable or pass them as arguments to functions, you are working with a reference to the original value stored in memory. Primitive data types, on the other hand, are passed by value, meaning that when you assign them to a variable or pass them as arguments, a copy of the value is created.

2. What is an object in JavaScript ?

In JavaScript, an object is a fundamental data type that represents a collection of key-value pairs. Objects in JavaScript can encapsulate both primitive data types (like strings, numbers, booleans) and other objects, making them powerful and flexible data structures.

An object is defined using curly braces {}, and each key-value pair inside the object is separated by a colon :. The key represents a unique identifier, while the value can be any valid JavaScript data type, including other objects or functions.

Ways to create object

  1. Simple function
function vehicle(name,maker,engine){ 
this.name = name;
this.maker = maker;
this.engine = engine;
}
//new keyword to create an object
let car = new vehicle('GT','BMW','1998cc');
//property accessors
console.log(car.name);

2. Creating JS Objects with object literal

//creating js objects with object literal 
let car = {
name : 'GT',
maker : 'BMW',
engine : '1998cc'
};

3. Creating object with Object.create() method:

The Object.create() method in JavaScript is utilized to create a new object, and it takes an existing object as a parameter to serve as the prototype for the newly generated object. This process enables inheritance, where the new object inherits properties and methods from its prototype. Example:

const coder = { 
isStudying : false,
printIntroduction : function(){
console.log(`My name is ${this.name}. Am I studying?: ${this.isStudying}`);
}
};
const me = Object.create(coder);
me.name = 'Mukul';
me.isStudying = true;
me.printIntroduction();

4. Using ES6 Classes

//using es6 classes 
class Vehicle {
constructor(name, maker, engine) {
this.name = name;
this.maker = maker;
this.engine = engine;
}
}

let car1 = new Vehicle('GT', 'BMW', '1998cc');

console.log(car1.name); //GT

3. In how many ways we can define an object in JavaScript ?

In JavaScript, there are multiple ways to define an object. Here are the most common ways:

  1. Object Literal: The simplest way to create an object is using the object literal syntax, denoted by curly braces `{}`. Properties and their values can be defined within the braces using the key-value pair format.
const person = {
name: 'John',
age: 25,
address: '123 Main St',
};

2. Constructor Function: You can define an object using a constructor function, which serves as a template for creating objects. Inside the constructor function, properties can be defined using the `this` keyword.

function Person(name, age, address) {
this.name = name;
this.age = age;
this.address = address;
}

const person = new Person('John', 25, '123 Main St');

3. Object.create(): The `Object.create()` method allows you to create a new object with a specified prototype object. You can define properties on the prototype object, which will be inherited by the created object.

const personPrototype = {
greet: function () {
console.log('Hello!');
},
};

const person = Object.create(personPrototype);
person.name = 'John';
person.age = 25;

4. Class: Introduced in ECMAScript 2015 (ES6), JavaScript supports class syntax for creating objects. Classes are essentially constructor functions with a more concise and structured syntax.

class Person {
constructor(name, age, address) {
this.name = name;
this.age = age;
this.address = address;
}
}

const person = new Person('John', 25, '123 Main St');

These are the main ways to define objects in JavaScript. Each method has its own use cases and advantages, so choose the one that best fits your needs and coding style.

4. How to define a class in JavaScript ?

In JavaScript, you can define a class using the `class` keyword. Here’s the basic syntax to define a class in JavaScript:

class ClassName {
// Class properties

// Constructor
constructor() {
// Initialize properties
}
// Methods
methodName() {
// Method logic
}
}

Let’s break down the syntax:

— `class ClassName` declares a new class with the name “ClassName”. You can replace “ClassName” with the desired name for your class.

— The class body is wrapped in curly braces `{}` and contains the properties and methods of the class.

— The `constructor` method is a special method that is executed when an instance of the class is created. It is used to initialize the class properties. You can define the constructor using the `constructor` keyword followed by parentheses `()`.

— Inside the class body, you can define other methods that perform specific actions or computations. Methods are defined without the `function` keyword.

Here’s an example of defining a simple class in JavaScript:

class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}

greet() {
console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
}
}

// Creating an instance of the Person class
const john = new Person('John', 30);
// Accessing properties and calling methods
console.log(john.name); // Output: John
console.log(john.age); // Output: 30
john.greet(); // Output: Hello, my name is John and I'm 30 years old.

In this example, the `Person` class has two properties (`name` and `age`) and a method (`greet`). The `constructor` initializes the `name` and `age` properties, and the `greet` method logs a greeting message to the console.

You can create instances of the class using the `new` keyword, as shown in the example with the `john` object. Then you can access the properties and call the methods on the instance.

5. What is defineProperty() method of javascript Object ?

The static method Object.defineProperty() defines a new property directly on an object, or modifies an existing property on an object, and returns the object.

Following are the properties present in Object.defineProperty() :-

configurable

true if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object. Defaults to false.

enumerable

true if and only if this property shows up during enumeration of the properties on the corresponding object. Defaults to false.

A data descriptor also has the following optional keys:-

value

The value associated with the property. Can be any valid JavaScript value (number, object, function, etc). Defaults to undefined.

writable

true if the value associated with the property may be changed with an assignment operator. Defaults to false.

Code e.g

const object1 = {};

Object.defineProperty(object1, 'property1', {
value: 42,
writable: false
});
object1.property1 = 77;
// throws an error in strict mode
console.log(object1.property1);
// expected output: 42

6. What is scope in JavaScript ?

Scope in JavaScript:

In JavaScript, scope refers to the context in which variables, functions, and objects are accessible and can be referenced. It defines the boundaries within which these identifiers have meaning and can be used. Understanding scope is crucial for writing well-organized, maintainable, and bug-free code.

Global Scope:

The global scope is the outermost scope in JavaScript and is accessible throughout the entire codebase. Variables declared in the global scope are considered global variables and can be accessed from any part of the program.

var globalVar = 42;

function printGlobalVar() {
console.log(globalVar);
}
printGlobalVar(); // Output: 42

In this example, `globalVar` is accessible both within the global scope and within the `printGlobalVar` function.

Local Scope (Function Scope and Block Scope):

Local scope refers to the context within a function or a block (created by curly braces `{}`). Variables declared within a local scope are only accessible within that scope.

function example() {
var localVar = "Hello, Scope!";
console.log(localVar);
}

example(); // Output: Hello, Scope!
// console.log(localVar); // Throws an error - localVar is not defined

In this example, `localVar` is accessible only within the `example` function. Attempting to access it outside the function would result in an error.

Nested Scope:

JavaScript supports nested scopes, meaning that functions and blocks can be defined within other functions or blocks. Inner scopes have access to variables declared in their parent scopes, but the reverse is not true.

function outer() {
var outerVar = "I'm outer!";

function inner() {
var innerVar = "I'm inner!";
console.log(outerVar); // Accessing outerVar from inner scope
}

inner();
// console.log(innerVar); // Throws an error - innerVar is not defined
}

outer(); // Output: I'm outer!

In this example, the `inner` function can access the variable `outerVar` from its parent scope, but the `outer` function cannot access `innerVar` from the child scope.

Block Scope with `let` and `const`:

ES6 introduced block scope for variables declared with `let` and `const`. These variables are confined to the block in which they are defined, including loops and conditionals.

if (true) {
let blockVar = "Inside Block Scope";
console.log(blockVar);
}

// console.log(blockVar); // Throws an error - blockVar is not defined

In this example, `blockVar` is accessible only within the if block.

Conclusion:

Scope is a fundamental concept in JavaScript that determines where variables, functions, and objects are accessible and can be used. It ensures the isolation and encapsulation of code, preventing unintended interactions and naming conflicts. Properly understanding and managing scope is essential for writing clean and maintainable JavaScript code.

7. Explain variable hoisting ?

Variable hoisting is a behavior in JavaScript where variable declarations are moved to the top of their respective scope, regardless of where the actual declaration occurs in the code. This means that variables can be used before they are declared, but they will have an initial value of undefined.

Here’s an example of variable hoisting:

function foo() {
console.log(x); // logs 'undefined'
var x = 10;
console.log(x); // logs '10'
}

foo();

In this example, we’ve defined a function foo that logs the value of variable x before and after it is declared and assigned a value of 10. Even though x is used before it is declared, JavaScript will hoist the declaration to the top of the function, so it will be available throughout the function with an initial value of undefined.

It’s important to note that variable hoisting only applies to variable declarations, not to variable assignments. This means that if you try to use a variable before it is declared and assigned a value, you will still get a ReferenceError.

Here’s an example:

function bar() {
console.log(y); // ReferenceError: y is not defined
y = 20;
console.log(y); // logs '20'
}

bar();

In this example, we’re trying to use variable y before it is declared. However, since there is no variable declaration for y, JavaScript will throw a ReferenceError. If we remove the first console.log statement and run the function again, we will see that y is assigned a value of 20.

It’s generally good practice to declare all variables at the top of their respective scope to avoid confusion and errors due to variable hoisting. This can be achieved using the let and const keywords, which have block scope and do not exhibit variable hoisting.

It’s important to understand that variable hoisting only applies to variables declared with the var keyword. Variables declared with let and const are also hoisted but have a different behavior known as the “temporal dead zone” (TDZ). In the TDZ, accessing variables before their declaration results in a ReferenceError. This behavior ensures that variables declared with let and const are not accessible before they are explicitly declared in the code.

Please find the detailed explanation here

8. Explain closures in javascript ?

In JavaScript, a closure is a combination of a function and the lexical environment within which that function was declared. It allows a function to access and remember variables from its outer (enclosing) scope even when the function is executed outside that scope.

To understand closures, it’s important to grasp the concept of lexical scope. Lexical scope means that variables and functions are defined within their containing scope, and they have access to variables from their parent scopes. When a function is defined inside another function, the inner function has access to variables and parameters of the outer function.

Here’s an example to demonstrate closures in JavaScript:

function outer() {
var outerVariable = 'I am from outer';
function inner() {
console.log(outerVariable);
}
return inner;
}

var closure = outer();
closure(); // Output: I am from outer

In this example, the `outer` function defines a variable called `outerVariable` and a nested function called `inner`. The `inner` function has access to the `outerVariable` even after the `outer` function has finished executing. When we invoke `outer()` and assign the returned `inner` function to the variable `closure`, we create a closure. The closure variable still holds a reference to the `inner` function along with its surrounding lexical environment, which includes the `outerVariable`. When we call `closure()`, it logs the value of `outerVariable`.

Closures are powerful because they enable functions to “remember” the variables in their lexical scope, even if the outer function has completed execution or the variables are not accessible in the current scope. This behavior allows for data encapsulation, private variables, and the creation of functions that can hold onto state information.

Closures are commonly used in scenarios like creating private variables, implementing function factories, and working with asynchronous code where you want to maintain access to variables across asynchronous callbacks. It’s important to note that closures can also lead to memory leaks if not handled carefully, as they keep references to the variables in their outer scopes, preventing them from being garbage collected.

It’s a good practice to be mindful of closure usage and avoid unnecessary memory consumption.

9. Difference between null and undefined ?

In JavaScript, `null` and `undefined` are two distinct primitive values that represent the absence of a meaningful value. Although they are similar in some ways, they have subtle differences. Here’s a breakdown of the differences between `null` and `undefined`:

  1. Assignment: `undefined` is a default value assigned to a variable that has been declared but has not been assigned a value. On the other hand, `null` is a value that can be assigned explicitly to a variable by the programmer to indicate the absence of an object or an empty value.
  2. Type: `undefined` is a type itself in JavaScript and represents the absence of a value. It is considered a primitive value. On the other hand, `null` is an object type, which means it is an empty object reference.
  3. Usage: `undefined` is commonly used to indicate the absence of a value, such as when a variable has not been assigned a value or when a function does not return a value explicitly. `null`, on the other hand, is typically used to indicate the intentional absence of an object or value.
  4. Behavior: When you try to access a variable that has been declared but not assigned a value, it will have the value of `undefined`. When a function does not return a value explicitly, it implicitly returns `undefined`. On the other hand, `null` must be assigned explicitly by the programmer and is not assigned automatically.
  5. Strict Equality: In JavaScript, `undefined` and `null` are not strictly equal to each other (`undefined === null` evaluates to `false`). They are distinct values with different types.
  6. Type Coercion: When performing loose equality comparisons (using `==`), `null` and `undefined` are loosely equal to each other (`null == undefined` evaluates to `true`). However, when using strict equality comparisons (using `===`), they are not equal (`null === undefined` evaluates to `false`).
  7. Passing Arguments: If a function parameter is not supplied with an argument, its value will be `undefined`. However, if you explicitly pass `null` as an argument, it will be assigned to that parameter.
  8. In summary, `undefined` represents the absence of a value or an uninitialized variable, while `null` represents the intentional absence of an object or an empty value. They have different types, behaviors, and use cases in JavaScript.

10. Difference between == and === ?

In one word, main difference between “==” and “===” operator is that formerly compares variable by making type correction e.g. if you compare a number with a string with numeric literal, == allows that, but === doesn’t allow that, because it not only checks the value but also type of two variable, if two variables are not of the same type “===” return false, while “==” return true.

11. What are the new features in ES6 , which were not there in previous JavaScript version ?

ES6 (ECMAScript 2015) is a major update to the JavaScript language specification, and it introduced many new features and improvements to the language. Here are some of the key features introduced in ES6: let and const: New ways to declare variables with block scope.

  1. Arrow functions: A new syntax for defining functions with shorter syntax, implicit returns, and lexical this.
  2. Template literals: A new syntax for creating string literals with interpolation and multiline support.
  3. Destructuring assignment: A new syntax for extracting values from objects and arrays into variables.
  4. Rest and spread operators: New syntax for working with function arguments and arrays.
  5. Default function parameters: A new way to define default values for function parameters.
  6. Classes: A new syntax for defining classes, which provide a more concise and familiar syntax for creating objects and inheritance.
  7. Modules: A new syntax for defining modules, which provide a better way to organize and reuse code.
  8. Promises: A new way to work with asynchronous code that simplifies error handling and chaining of operations.
  9. Symbol type: A new primitive type that provides a way to create unique values.
  10. Iterators and generators: New ways to work with collections of data, including custom iteration behavior.

These are just some of the many new features introduced in ES6, and they have significantly improved the capabilities and expressiveness of the JavaScript language.

Please check this link for all the ES6 features in detail

12. Explain time complexity ?

Time complexity is a fundamental concept within the field of computer science that is employed to assess the effectiveness of an algorithm. It quantifies how an algorithm’s runtime changes as the size of the input data increases. In simpler terms, it aids in our comprehension of how an algorithm’s execution time adapts as the input data becomes more extensive.

Example 1: Constant Time Complexity O(1)

Constant time complexity is observed in an algorithm when its execution time remains consistent, regardless of the input size.

function getFirstElement(arr) {
return arr[0];
}

In this instance, the getFirstElement function delivers the initial element of the arr array. Irrespective of the array's size, the function's execution time remains constant. This characterizes the algorithm's time complexity as O(1), representing a consistent execution time.

Example 2: Linear Time Complexity O(n)

Linear time complexity is exhibited by an algorithm when its execution time scales directly with the size of the input.”

function findElement(arr, target) {
for (let num of arr) {
if (num === target) {
return true;
}
}
return false;
}

In this case, the findElement function is designed to locate a particular target element within the arr array. With an increasing array size, the function's runtime extends linearly, indicating that it demands more time for larger arrays. Hence, the time complexity of this algorithm is O(n), symbolizing a linear time complexity.

Example 3: Quadratic Time Complexity O(n²)

Quadratic time complexity is demonstrated by an algorithm when its execution time expands in proportion to the square of the input size.

function printAllPairs(arr) {
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length; j++) {
console.log(arr[i], arr[j]);
}
}
}

In this scenario, the printAllPairs function is responsible for printing all possible pairs of elements found in the arr array. With an expanding array size, the nested loop's iterations increase exponentially, leading to a quadratic growth in execution time. Consequently, the time complexity of this algorithm is O(n^2), indicating a quadratic time complexity.

Conclusion:

The analysis of time complexity in JavaScript serves as a valuable tool for developers to evaluate how algorithms behave as input sizes vary. Through the application of concepts like Big O notation, programmers can measure and compare the efficiency of various solutions. This understanding of time complexity empowers JavaScript developers to optimize their code for enhanced performance, ensuring that applications run smoothly, even when handling larger datasets

13. What is space complexity ?

Space complexity refers to the amount of memory space an algorithm or program requires to execute, and how that memory usage grows as the input size increases. It’s essential to analyze and optimize space complexity to ensure efficient memory utilization. Let’s explore space complexity with some JavaScript examples.

Example 1: Constant Space Complexity O(1) An algorithm has constant space complexity when the amount of memory it uses remains constant, regardless of the input size.


function add(a, b) {
let result = a + b;
return result;
}

In this example, the `add` function takes two parameters, performs a simple addition, and returns the result. Regardless of the input values, the function uses only a few local variables, and the memory usage remains constant. Thus, the space complexity of this algorithm is O(1), indicating constant space usage.

Example 2: Linear Space Complexity O(n) An algorithm has linear space complexity when the memory it uses grows linearly with the input size.


function createArray(n) {
let arr = [];
for (let i = 0; i < n; i++) {
arr.push(i);
}
return arr;
}

In this example, the `createArray` function generates an array of length `n`. As `n` increases, the memory usage of the array grows proportionally. The function requires space to store each element in the array. Thus, the space complexity of this algorithm is O(n), signifying linear space usage.

Example 3: Quadratic Space Complexity O(n²)

An algorithm has quadratic space complexity when the memory usage grows proportionally to the square of the input size.


function createMatrix(n) {
let matrix = [];
for (let i = 0; i < n; i++) {
let row = [];
for (let j = 0; j < n; j++) {
row.push(i * j);
}
matrix.push(row);
}
return matrix;
}

In this example, the `createMatrix` function generates a matrix of size `n` by `n`. As `n` increases, the memory usage grows quadratically due to the nested loops creating `n * n` elements. The function requires space to store each element in the matrix. Therefore, the space complexity of this algorithm is O(n²), indicating quadratic space usage.

Conclusion:

Space complexity is a crucial consideration when designing algorithms in JavaScript. Analyzing how memory usage scales with input size helps ensure efficient memory utilization and optimal performance. By using Big O notation to express space complexity, developers can compare and optimize different algorithms for memory efficiency. Understanding space complexity is essential for creating well-designed, resource-efficient programs and applications.

14. Explain call(), bind() and apply() in JavaScript ?

In JavaScript, `call()`, `bind()`, and `apply()` are methods available on functions and are used to manipulate how functions are invoked and bound to a specific context. Here’s an explanation of each of these methods:

  1. `call()`:

The `call()` method is used to call a function with respect to any object. The `call()` method takes the context object as its first argument, followed by the arguments to be passed to the function. Syntax: `function.call(context, arg1, arg2, …)`

Example:

function greet(name) {
console.log(`Hello, ${name}! My name is ${this.name}.`);
}

const person = {
name: 'Alice'
};

greet.call(person, 'Bob');

Output:

Hello, Bob! My name is Alice.

In the example above, `call()` is used to invoke the `greet()` function with the `person` object as the context. The first argument `person` sets `this` inside the function to refer to the `person` object.

2. `bind()`:

The `bind()` method creates a new function with a specified context and initial arguments, without invoking it immediately. It returns a new function that, when called, has its `this` value set to the provided context and any additional arguments are prepended to the original function’s arguments. Syntax: `function.bind(context, arg1, arg2, …)`

Example:

function greet(name) {
console.log(`Hello, ${name}! My name is ${this.name}.`);
}

const person = {
name: 'Alice'
};

const greetPerson = greet.bind(person);
greetPerson('Bob');

Output:

Hello, Bob! My name is Alice.

In the example above, `bind()` is used to create a new function `greetPerson` that has its `this` value bound to the `person` object. The resulting function `greetPerson` can be invoked later with the remaining arguments.

3. `apply()`:

The `apply()` method is similar to `call()`, but it takes arguments as an array or an array-like object instead of individual arguments. It is used to invoke a function immediately, specifying the context and an array of arguments to be passed to the function.

Syntax: `function.apply(context, [arg1, arg2, …])`

Example:

function greet(name) {
console.log(`Hello, ${name}! My name is ${this.name}.`);
}

const person = {
name: 'Alice'
};

greet.apply(person, ['Bob']);

Output:

Hello, Bob! My name is Alice.

In the example above, `apply()` is used to invoke the `greet()` function with the `person` object as the context and an array containing the argument `’Bob’`.

To summarize:

`call()` invokes a function immediately with a specified context and individual arguments.

`bind()` creates a new function with a specified context and initial arguments, without invoking it immediately.

`apply()` invokes a function immediately with a specified context and an array of arguments.

These methods provide flexibility in managing the execution context (`this`) and arguments when working with JavaScript functions.

15. Advantage of using arrow functions ?

Arrow functions in JavaScript provide several advantages over traditional function expressions. Here are some benefits of using arrow functions:

  1. Concise Syntax: Arrow functions have a compact and concise syntax, making the code more readable and reducing the amount of boilerplate code. They are particularly useful for writing shorter and more expressive functions.
  2. Lexical `this` Binding: Arrow functions do not have their own `this` value. Instead, they lexically bind the `this` value of the enclosing scope. This means that the `this` value inside an arrow function is automatically inherited from the surrounding context. It eliminates the need to use `bind()`, `call()`, or `apply()` to preserve the `this` value or deal with `this`-related issues.
  3. No Arguments Object: Arrow functions do not have their own `arguments` object. Instead, they inherit the `arguments` object from the enclosing scope. This can be beneficial in scenarios where you need to access the arguments passed to an enclosing function.
  4. Implicit Return: Arrow functions provide implicit return behavior for concise one-line functions. If the function body consists of a single expression, you can omit the curly braces and the `return` keyword. The result of the expression will be automatically returned.
  5. Well-suited for Callbacks: Arrow functions are well-suited for callback functions, such as event handlers or asynchronous operations, where the lexical binding of `this` and the concise syntax can make the code more readable and maintainable.

Here’s an example to illustrate some of these advantages:

const numbers = [1, 2, 3, 4, 5];

// Traditional function expression
const squared1 = numbers.map(function (num) {
return num * num;
});

// Arrow function
const squared2 = numbers.map(num => num * num);

In the example above, the arrow function `num => num * num` provides a more concise and readable syntax compared to the traditional function expression. It also inherits the `this` value from the surrounding context, which can be useful in certain scenarios.

Overall, arrow functions enhance code readability, simplify `this` handling, and provide a more concise syntax for writing functions, making them a popular choice in modern JavaScript development.

16. What is webpack and babel ?

Webpack and Babel are two popular tools commonly used in modern JavaScript development to enhance the development workflow and optimize the deployment of web applications. Here’s a brief explanation of each:

  1. Webpack:

Webpack is a module bundler for JavaScript applications. It takes multiple JavaScript modules, along with their dependencies, and bundles them into a single optimized file or multiple files called bundles. Webpack helps manage the dependencies between modules, allowing developers to organize and structure their code in a modular manner.

Key features and benefits of Webpack include:

— Module bundling: Webpack bundles modules together, which improves the loading time of web applications by reducing the number of network requests required to fetch individual files.

— Dependency management: Webpack analyzes the dependencies between modules, allowing developers to use `import` and `export` statements to organize and split code into separate files.

— Loaders: Webpack supports various loaders that enable the transformation of different file types (e.g., JavaScript, CSS, images) during the bundling process. Loaders can apply transformations, such as transpiling newer JavaScript syntax with Babel or applying CSS preprocessing.

— Code splitting: Webpack enables code splitting, which allows for the creation of multiple bundles that can be loaded on-demand, improving application performance by loading only the necessary code for specific routes or features.

— Development server and hot module replacement: Webpack provides a development server that serves the bundled application locally during development. It also supports hot module replacement (HMR), which allows developers to see the changes they make in real-time without reloading the entire page.

2. Babel:

Babel is a popular JavaScript compiler that allows developers to write code using the latest JavaScript syntax (ES6+, JSX, TypeScript) and transpile it into JavaScript that is compatible with older browsers and environments. Babel helps bridge the gap between modern JavaScript features and browser support, enabling developers to use the latest

17. How can we add an element at the start of a JavaScript array ?

Method 1 : Using unshift() method To add an element at the start of a JavaScript array, you can use the `unshift()` method. Here’s an example:


const myArray = [2, 3, 4, 5];
myArray.unshift(1); // Add 1 at the start of the array
console.log(myArray); // Output: [1, 2, 3, 4, 5]

In this example, the `unshift()` method is called on the `myArray` array and passed the element `1` as an argument. This adds the element at the beginning of the array. The existing elements are shifted to the right, and the length of the array is increased by one.

Method 2: Using concat() method

Note that the `unshift()` method modifies the original array and returns the new length of the array. If you need a new array without modifying the original one, you can create a new array using the spread operator or the `concat()` method:


const myArray = [2, 3, 4, 5];
const newArray = [1, ...myArray]; // Using spread operator
console.log(newArray); // Output: [1, 2, 3, 4, 5]

// Alternatively, using concat()
const myArray = [2, 3, 4, 5];
const newArray = [1].concat(myArray);
console.log(newArray); // Output: [1, 2, 3, 4, 5]

Method 3 : Using splice() method


Let arr = [a,b, c]
arr.splice(0,0,x)
console.log(arr) //output - [x,a,b,c]

About splice() method :

It takes 3 parameters :

  1. The index from where to start
  2. Number of elements to remove starting from that index

3. Comma seprated list of the elements to add

18. How to capitalise all the first letters of a given string ?

Css way :

Use css property Text-transform with values as capitalize


Text-transform : capitalize;

JS way :

  1. Make first character of string as capital
  2. Loop over the given characters of string
  3. Whenever we find a space i.e “ “ while looping over the string, We have to capitalize the next letter of string using toUpperCase() method.

function capitalizeStr(str){
let arr = str.split("");
arr[0] = arr[0].toUpperCase();
for(let i in arr){
if(arr[i-1] === " "){
arr[i] = arr[i].toUpperCase();
}
}
return arr.join('');
}

console.log(capitalizeStr('just to test')) //output: Just To Test

18. What will be output of following code doit(); var doit = function (){ alert(‘x’); }

Output will be:- Uncaught TypeError: doit is not a function because function expressions in JavaScript are not hoisted. Therefore, you cannot use function expressions before defining them

19. Difference between pass by value and pass by reference ?

In programming, pass by value and pass by reference are two different approaches to parameter passing when invoking functions or methods. These concepts refer to how the values of arguments are assigned to parameters in function calls.

  1. Pass by Value: In pass by value, a copy of the value of the argument is passed to the function or method. Any changes made to the parameter within the function do not affect the original argument outside the function. This means that the function works with its own separate copy of the value.

Example of pass by value in JavaScript:


function increment(value) {
value = value + 1;
console.log('Inside function:', value);
}

let num = 5;
increment(num);
console.log('Outside function:', num);

Output:


Inside function: 6
Outside function: 5

In this example, the `increment` function takes an argument `value` and increments it by 1. However, the increment operation only affects the local copy of `value` within the function. The original value of `num` outside the function remains unchanged.

2. Pass by Reference: In pass by reference, a reference to the memory location of the argument is passed to the function or method. This means that changes made to the parameter within the function affect the original argument outside the function since they are pointing to the same memory location.

Example of pass by reference in JavaScript:


function changeName(obj) {
obj.name = 'John';
console.log('Inside function:', obj);
}

let person = { name: 'Alice' };
changeName(person);
console.log('Outside function:', person);

Output:


Inside function: { name: 'John' }
Outside function: { name: 'John' }

In this example, the `changeName` function takes an argument `obj` which is an object. It modifies the `name` property of the object to `’John’`. Since the parameter `obj` holds a reference to the same object as `person`, the change made inside the function is reflected outside as well.

It’s important to note that JavaScript is always pass by value, but when dealing with objects and arrays, the values being passed are references to the objects or arrays. So, in practical terms, the behavior may resemble pass by reference.

In summary, the main difference between pass by value and pass by reference is that in pass by value, a copy of the value is passed, while in pass by reference, a reference to the original value is passed. Pass by value does not affect the original value outside the function, while pass by reference allows modifications to affect the original value outside the function.

20. What is InstanceOf operator ?

The instanceof operator tests to see if the prototype property of a constructor appears anywhere in the prototype chain of an object. The return value is a boolean value.


function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
const auto = new Car('Honda', 'Accord', 1998);

console.log(auto instanceof Car);
// expected output: true

console.log(auto instanceof Object);
// expected output: true

21. What is the use of constructor() in a class ?

The constructor method is a special method for creating and initializing an object created with a class. There can only be one special method with the name “constructor” in a class. A SyntaxError will be thrown if the class contains more than one occurrence of a constructor method.

A constructor can use the super keyword to call the constructor of the super class. If you don’t provide your own constructor, then a default constructor will be supplied for you. If your class is a base class, the default constructor is empty:


constructor() {}

If your class is a derived class, the default constructor calls the parent constructor, passing along any arguments that were provided:

constructor(...args) {
super(...args);
}

22. How can we use javascript Set to remove duplicate elements of an array ?

Code to remove duplicates using set:


let arr=[1,2,2,3,4,4,4,5];
let result=[...new Set(arr)];
console.log(result); //1,2,3,4,5

The Set automatically removes duplicate elements because it only stores unique values. Then, we convert the Set back to an array using the spread operator …, resulting in the uniqueArray that contains only the unique elements from the original array.

23. What is the data storage limit of a cookie ? and what is the maximum number of characters that can be stored in a cookie string ?

The data storage limit for a cookie is 4kb i.e. 4096 bytes.

Now , talking about characters , a character in UTF-8 can take somewhere between 1 byte to 4 bytes of space . so in 4kb we can store between 1024 to 4096 characters.

24. How to make deep copy and shallow copy of objects ?

Shallow Copy:

A shallow copy of an object refers to a new object that is created, duplicating the structure of the original object. This duplicate contains references to the same child objects as the original but not the actual child objects themselves. In other words, while the top-level properties of the object are copied, any nested objects or arrays within the original object are still referenced by both the original and the shallow copy.

To better understand the concept of a shallow copy, consider an example using JavaScript:

const originalObject = {
prop1: 'Hello',
prop2: {
nestedProp1: 'World'
}
};

// Creating a shallow copy
const shallowCopy = Object.assign({}, originalObject);
// Modifying the shallow copy
shallowCopy.prop1 = 'Hola';
shallowCopy.prop2.nestedProp1 = 'Mundo';

console.log(originalObject); // { prop1: 'Hello', prop2: { nestedProp1: 'Mundo' } }
console.log(shallowCopy); // { prop1: 'Hola', prop2: { nestedProp1: 'Mundo' } }

In this example, we create a shallow copy of originalObject using Object.assign(). Both originalObject and shallowCopy have their top-level properties (like prop1) independently modified without affecting each other. However, when we modify a nested property (like nestedProp1) within shallowCopy, it also reflects the same change in originalObject. This is because both objects reference the same nested object

Deep cloning/copying an object in JavaScript means creating a new object that is an independent copy of the original object, including all nested objects and arrays. There are several approaches to deep cloning an object in JavaScript. Here are three common methods:

  1. Using `JSON.parse()` and `JSON.stringify()`:
const originalObject = {
name:'test name',
addr:{
city:'test city',
state:'test state'
}
}
const clonedObject = JSON.parse(JSON.stringify(originalObject)); // will returned clone of given object

This method works by converting the original object to a JSON string using `JSON.stringify()`, and then parsing the JSON string back into a new object using `JSON.parse()`. This creates a deep copy of the original object, but it has limitations. It will discard any function properties, undefined properties, or properties with circular references.

2. Using a recursive function:

function deepClone(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}

const clonedObj = Array.isArray(obj) ? [] : {};

for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clonedObj[key] = deepClone(obj[key]);
}
}

return clonedObj;
}

const originalObject = {
name:'test name',
addr:{
city:'test city',
state:'test state'
}
}

const clonedObject = deepClone(originalObject); // will returned clone of given object
let arr=[1,2,3,[4,5 ,[6,7]]];
const clonedArray = deepClone(arr); // will returned clone of given Array

This method involves creating a recursive function `deepClone()` that traverses the object and creates a deep copy by recursively cloning nested objects and arrays. It handles circular references and functions properly. However, be cautious when using this method with very large or deeply nested objects, as it can impact performance.

Keep in mind that deep cloning an object can have performance implications, especially for large or complex objects. Choose the method that suits your needs, taking into account performance considerations and the specific requirements of your use case.

25. What’s the difference between for loop and for each loop ?

In JavaScript, both the for loop and the forEach loop are used for iterating over elements in an array or other iterable objects. However, they have distinct characteristics and use cases that set them apart.

`for` Loop:

The `for` loop is a traditional loop construct that provides more control over the iteration process. It consists of three parts: initialization, condition, and iteration expression.

for (initialization; condition; iteration) {
// Code to be executed in each iteration
}

Example:

const numbers = [1, 2, 3, 4, 5];
for (let i = 0; i < numbers.length; i++) {
console.log(numbers[i]);
}

`forEach` Loop:

The `forEach` loop is a higher-order function provided by arrays that simplifies the iteration process. It takes a callback function as its argument and applies that function to each element in the array.

array.forEach(callback(currentValue, index, array) {
// Code to be executed for each element
});

Example:

const numbers = [1, 2, 3, 4, 5];
numbers.forEach(function(number) {
console.log(number);
});

Key Differences:

  1. Readability and Conciseness: The `forEach` loop is often considered more concise and readable, especially for simple iterations. It abstracts away the loop control logic, making the code easier to understand.
  2. Break and Continue: The `for` loop allows the use of `break` and `continue` statements to control the flow of iteration. The `forEach` loop does not natively support these statements.
  3. Access to Index: In the `for` loop, you can easily access the index of the current element (`i` in the example). In the `forEach` loop, you can also access the index, but it’s an optional parameter in the callback function.
  4. Return Value: The `for` loop can easily break the iteration and return a value from the loop block. In the `forEach` loop, you cannot directly return a value from the loop itself.

Choosing Between the Two:

— Use the `for` loop when you need more fine-grained control over the iteration, such as using `break` or `continue` statements, or when you need to manipulate the loop index.

— Use the `forEach` loop when you want a more concise and functional approach to iterating over elements. It’s especially useful for scenarios where you don’t need to modify the array itself.

Conclusion:

In summary, the choice between for and forEach loops depends on the specific requirements of your code. Both have their strengths and are valuable tools in JavaScript’s iteration toolbox.

26. What is a unary function ?

A unary function is a mathematical or programming function that takes exactly one argument. In programming, a unary function typically takes a single argument and produces a corresponding output.

Let’s explore a unary function with an example in JavaScript:

Example: Unary Function in JavaScript

// Unary function to square a number
function square(x) {
return x * x;
}
// Usage of the unary function
const number = 5;
const result = square(number);
console.log(result); // Output: 25

In this example, we have a unary function called `square` that takes a single argument `x`. The function calculates the square of the input number by multiplying `x` with itself and returns the result. When we call the function with `number` set to 5, it calculates the square (5 * 5) and returns 25, which is then printed to the console.

Conclusion:

As you can see, a unary function is a simple function that operates on a single argument, performing some computation, and returning the output. Unary functions are commonly used in various programming tasks, especially in functional programming paradigms, where operations on single values are frequent.

27. What is JSON in javascript and what are its advantages ?

JSON stands for JavaScript Object Notation, which is a lightweight data interchange format. It is easy for humans to read and write, and easy for machines to parse and generate.

JSON format consists of key-value pairs and is often used for transmitting data between a server and a web application, as an alternative to XML. JSON has become very popular due to its simplicity, flexibility, and wide support across various programming languages.

Some of the advantages of using JSON include:

  1. Lightweight: JSON has a simple syntax and is much lighter than XML, making it easier to parse and transmit over networks.
  2. Easy to read and write: JSON is easy to read and write, even for non-technical people, making it a popular choice for transmitting data.
  3. Cross-platform compatibility: JSON is supported by many programming languages and platforms, including JavaScript, Python, Ruby, and PHP, making it easy to use across different systems.
  4. Human-readable: JSON is easy to read and understand, which makes debugging and troubleshooting easier.
  5. Faster processing: JSON is faster to parse than XML, which can improve the performance of web applications.
  6. Flexible: JSON can be used to represent complex data structures and can be easily extended to support new data types. Overall, JSON is a versatile and widely-used data interchange format that offers many advantages over other formats like XML.

28. What is JSON.stringify() ?

JSON.stringify() is a built-in function in JavaScript that converts JavaScript objects into JSON strings. This function provides flexibility in handling complex data structures by serializing them into a string format that is easily readable and transferable. It plays a crucial role in various scenarios, including data transmission between client and server, storing data locally, and debugging applications.

Syntax

The syntax of JSON.stringify() is as follows:

JSON.stringify(value[, replacer[, space]])
  • value: The JavaScript object to be converted into a JSON string.
  • replacer (optional): A function that transforms the output JSON string or an array of properties to include in the resulting JSON string, or a replacer array consisting of specific property names to include.
  • space (optional): A string or number representing the spacing in the resulting JSON string for better readability. It can be used for indentation.

Understanding Parameters

  1. value: This parameter represents the JavaScript object that you want to convert into a JSON string. It can be any valid JavaScript object, including arrays, strings, numbers, booleans, and nested objects.
  2. replacer: This optional parameter allows you to customize the serialization process. It can be either a function or an array. If it’s a function, it will be called for each property in the object being stringified. You can manipulate the value and decide whether to include it in the resulting JSON string. If it’s an array, only the properties listed in the array will be included in the output.
  3. space: The space parameter is optional and used for pretty-printing the resulting JSON string. It specifies the indentation level or a string to insert for each level of indentation. If it’s a number, it represents the number of spaces to use for indentation. If it’s a string, that string (or the first 10 characters of it) is used as the indentation.

Practical Examples

Let’s dive into some practical examples to understand how JSON.stringify() works:

Example 1: Basic Usage

const person = {
name: 'John',
age: 30,
isAdmin: false,
hobbies: ['reading', 'coding', 'traveling']
};

const jsonStr = JSON.stringify(person);
console.log(jsonStr);

Output:

{"name":"John","age":30,"isAdmin":false,"hobbies":["reading","coding","traveling"]}

Example 2: Using Replacer

const user = {
username: 'Alice',
email: 'alice@example.com',
password: 'password123'
};

const jsonStr = JSON.stringify(user, ['username', 'email']);
console.log(jsonStr);

Output:

{"username":"Alice","email":"alice@example.com"}

Example 3: Using Replacer Function

const student = {
name: 'Bob',
age: 25,
department: 'Computer Science',
grades: { math: 95, science: 85, english: 90 }
};

const jsonStr = JSON.stringify(student, (key, value) => {
if (key === 'grades') {
return undefined; // Exclude 'grades' from the output
}
return value;
}, 2); // Indent with 2 spaces

console.log(jsonStr);

Output:

{
"name": "Bob",
"age": 25,
"department": "Computer Science"
}

Conclusion

JSON.stringify() is a powerful tool for serializing JavaScript objects into JSON strings. It offers flexibility through its parameters, allowing customization of the serialization process according to specific requirements. By mastering JSON.stringify(), you can effectively work with JSON data in various scenarios, from data transmission to storage and debugging. Understanding its syntax, parameters, and practical usage is essential for any JavaScript developer dealing with JSON data.

29. What is JSON.parse() ?

JSON.parse() is a built-in function in JavaScript used to parse JSON strings into JavaScript objects. It serves as a bridge between the textual JSON data format and the native JavaScript representation, enabling developers to work with JSON data effortlessly within their applications. Understanding JSON.parse() is fundamental for handling incoming JSON data from APIs, local storage, or other sources.

Syntax

The syntax of JSON.parse() is straightforward:

JSON.parse(text[, reviver])
  • text: The JSON string to be parsed into a JavaScript object.
  • reviver (optional): A function that transforms the parsed JSON object’s properties before returning the final object.

Understanding Parameters

  1. text: The JSON string passed to the JSON.parse() function should adhere to the JSON syntax rules. It typically consists of key-value pairs, arrays, nested objects, strings, numbers, booleans, or null values.
  2. reviver: The reviver function, if provided, is invoked for each key-value pair in the parsed JSON object. It receives two arguments: the key and the corresponding value. Inside the reviver function, you can manipulate the value or filter out specific properties based on your requirements.

Practical Examples

Let’s explore some practical examples to illustrate the usage of JSON.parse():

Example 1: Basic Usage

const jsonString = '{"name": "Alice", "age": 30, "isAdmin": true}';
const parsedObject = JSON.parse(jsonString);
console.log(parsedObject);

Output:

{ name: 'Alice', age: 30, isAdmin: true }

Example 2: Parsing an Array

const jsonArrayString = '[{"name": "John", "age": 25}, {"name": "Emily", "age": 28}]';
const parsedArray = JSON.parse(jsonArrayString);
console.log(parsedArray);

Output:

[ { name: 'John', age: 25 }, { name: 'Emily', age: 28 } ]

Example 3: Using Reviver Function

const jsonStringWithDates = '{"dateOfBirth": "2022-01-01T00:00:00.000Z"}';

const parsedObjectWithDates = JSON.parse(jsonStringWithDates, (key, value) => {
if (key === 'dateOfBirth') {
return new Date(value); // Convert string to Date object
}
return value;
});

console.log(parsedObjectWithDates);

Output:

{ dateOfBirth: 2022-01-01T00:00:00.000Z }

Conclusion

JSON.parse() is a crucial function in JavaScript for parsing JSON strings into JavaScript objects. Its simplicity and versatility make it an indispensable tool for handling JSON data in web applications. By understanding its syntax, parameters, and practical usage, developers can effectively integrate JSON data into their applications, enabling seamless communication with external APIs, storage systems, and other data sources. Mastering JSON.parse() empowers developers to harness the full potential of JSON data within their JavaScript applications.

Input / Output Questions:-

->What will be the output of below code snippet :-

function x() {
return 2;
}

alert(x());

function x() {
return 3;
}

Output will be : 3 as functions are hoisted to the top

-> What will be the output of the below code :-

var a = 90;
doit();
function doit(){
console.log(a);
var a = 10;
}

Output will be : undefined

-> What will be the output of the below code:

  for (var i= 0; i < 5; i++){
setTimeout(() => console.log(i));
}

Output will be:-

5 5 5 5 5

Reason — some people may think that the output should be 0,1,2,3,4 . But there is a twist here , the arrow function written inside setTimeout does not executes right way , instead it goes in the event queue.

So , when the loop iterates from i = 0 till i =4 , all the five console.log(i) statements would go in the event queue , now at the end of iteration the value of i becomes 5 .

After this the 5 console.log(i) statements present in the event queue would execute and hence we would see 5 printed 5 times on console.

-> What will be the output of the below code:

let obj ={
a: 10,
vir : function(){
x();
console.log(this.a);
function x(){
console.log(this.a)
}
}
}
obj.vir();

Output: — The output of the above code for first ‘this.a’ is ‘10’ and second ‘this.a’ inside function x is ‘undefined’.

Reason being that ‘this’ keyword when directly used inside an object’s method points to the object itself but in the above code ‘this’ keyword is present inside x() function of the vir() method , so its not being directly used in object’s method vir() , so it would refer to window object and there is no variable ‘a’ in the window object so output will be ‘undefined’.


let obj ={
a: 10,
vir : function(){
x();
console.log(this.a); //output 10
function x(){
console.log(this.a) // undefined
}
}
}
obj.vir();

-> What will be the output of the following :

console.log(4.toString());
console.log(4.2.toString());
console.log(4*undefined);

Output:-



console.log(4.toString()); //Uncaught SyntaxError: Invalid or unexpected token
console.log(4.2.toString()); //"4.2"
console.log(4*undefined); //NaN

-> What will be the output of following code:-

for (var i= 0; i < 5; i++){
(function(i) {
setTimeout( () => console.log(i))
})(i);
}

Output:- 0 1 2 3 4

--

--

Pravin M

I am a frontend developer with 10+ years of experience