Javascript Interview Preparation:Part 3

Javascript Interview Preparation:Part 3

Demystifying Functions

So today we are going to discuss some popular interview questions on functions which is a very important topic in JS and obviously also required a lot in development.

What are Functions in JS?

According to MDN Web Docs,

Functions are one of the fundamental building blocks in JavaScript. A function in JavaScript is similar to a procedure—a set of statements that performs a task or calculates a value, but for a procedure to qualify as a function, it should take some input and return an output where there is some obvious relationship between the input and the output. To use a function, you must define it somewhere in the scope from which you wish to call it

Lets go and solve some popular interview questions asked on functions.

What is a Function Declaration or Statement?

function addTwoNumbers(a,b){
return (a+b);

Above is an example of a simple function decalration or statement.

What is Function Expression?

Whenever a function is stored inside of a variable then it is known as a function expression since the function is present as an expression .

const addTwoNumbers=function(a,b){
return (a+b);
}

Addon Question: what can we call this function? Anonymous function since it is not directly given a name but its name is the same as the variable name and using that you can call it.

addTwoNumbers(4,5);

Below is the screenshot of the working result:

What are First Class Functions?

MDN Web Docs has got an awesome defintion for this :

A programming language is said to have First-class functions when functions in that language are treated like any other variable. For example, in such a language, a function can be passed as an argument to other functions, can be returned by another function and can be assigned as a value to a variable.

Lets take an example:

function square(num){
return num*num;
}

function displaySquare(fn){
console.log("Square of 5="+fn(5));
}

displaySquare(square);//here as you can see that the square function's 
//reference is passed as  an argument and gets stored in fn and then later 
//fn(5) , the square function gets called by sending 5 as parameter

Here is a screenshot of the working of the code:

What is an IIFE?

An IIFE (Immediately Invoked Function Expression) is a JS function that runs as soon as it is defined.
Lets see an example:

(function sum2(a,b){
console.log(a+b);
})(4,5);//as you can see the fn gets immediately called with 4 and 5 as 
//parameters

Heres the output:

Follow up question : have a look at the code below and try to solve it before seeing the working:

(function (x){
return (function (y){
console.log(x);
})(2)}
)(1);

Working: so whats occuring here is the outside function gets immediately called with x receiving 1 and then inner function gets called with y receiving 2 but in the console x's value get displayed which is 1.

Proof:

Lets do some warmup first. This is an example taken directly from MDN Web Docs.

// The following variables are defined in the global scope
const num1 = 20;
const num2 = 3;
const name = "Chamakh";

// This function is defined in the global scope
function multiply() {
  return num1 * num2;//global variables num1 and num2 being used
}

console.log(multiply()); // 60

// A nested function example
function getScore() {
  const num1 = 2;
  const num2 = 3;
//local variables num1 and num2 shadow global ones
  function add() {
    return `${name} scored ${num1 + num2}`;
  }

  return add();
}

console.log(getScore()); // "Chamakh scored 5"

Having done our warmup ,lets see the followup question. Have a look at both of the loops and try to figure out the difference in output.

for(let i=0;i<5;i++)
{
setTimeout(function(){
console.log(i)},i*1000);
}

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

So guess what for the first one the output would be :0 1 2 3 4 (each after one second delay) and for the second one it would be :5 5 5 5 5 (each after one second delay).

Lets see ChatGPT's reason for this :

For the first snippet, letcreates a new binding foriin each iteration of the loop. So, when the setTimeout functions execute, they capture the value ofiat that iteration. The delay for each setTimeout increases by 1000 milliseconds for each iteration.

And for the second snippet, vardoes not create a new binding foriin each iteration of the loop. So, when the setTimeout functions execute, they use the final value ofiafter the loop has finished executing. The delay for each setTimeout increases by 1000 milliseconds for each iteration.

You can always use ChatGPT to clear your doubts on "popular" topics. But still try to double check.

A normal function is hoisted completely and hence a function call before or after the function definition does not affect the result. Lets see an example .

console.log(addTwoNumbers(4,5));

function addTwoNumbers(a,b){
return (a+b);
}

console.log(addTwoNumbers(4,5));

As you can see the output remains the same:

Follow up: view the code below and predict the output.

var x=21;
var fn=function(){
console.log(x);
var x=20;
}
fn();

You might have thought since var x = 20 is yet to be executed so it will print 21 from global context but , undefined is the answer since a separate execution cotext is created for the function and here the local variable is internally hoisted and hence it returns undefined.
Proof:

Params vs Arguments

Simple stuff.

function hello(a,b)//formal parameters also known as params
{
return "hello"
}

hello(4,5);//actual parameters also known as arguments

Rest vs Spread Operator

Lets see an example for this one.

function addTwoNumbers(...nums)//here the "rest" operator takes up the 
//incoming values in an array which you can understand by the output as well
{
console.log(nums);
console.log("Addition of two given numbers is:"+(nums[0]+nums[1]));
}
var input=[5,6];
addTwoNumbers(...input);//its the same as addTwoNumbers(5,6) where the "spread"
//operator spreads the values of the array in the arguments zone

Lets see the output:

Follow up question: view the code below and figure out the answer.

function something(a,b,c,...numbers)//always keep the rest operator or spread
//operator at the end
{
console.log(a,b,c,numbers);
}

something(5,6,7,8,9,0,1);

Lets see if your answer is correct.

What are Callback Functions

We have discussed callback functions before in map,filter and reduce and saw its application .Still lets go through a MDN Web Docs defintion and example.

A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action.
Lets look at an example:

function givename()
{
return "Mainak";
}

function printName(callback)//givename is recieved as callback and can be
//called using callback()
{
console.log(callback());
}

printName(givename);//givename is passed as callback

The output:

What are arrow functions?

According to MDN Web Docs, an arrow function expression is a compact alternative to a traditional function expression, with some semantic differences and deliberate limitations in usage:

  • Arrow functions don't have their own bindings to this, arguments, or super, and should not be used as methods.

  • Arrow functions cannot be used as constructors. Calling them with new throws a TypeError. They also don't have access to the new.target keyword.

  • Arrow functions cannot use yield within their body and cannot be created as generator functions.

Lets see an example:

const arrow=()=>{
console.log("hello");
}

arrow();

Normal Function vs Arrow Function

  • Syntax
//normal function
function addTwoNumbers1(a,b){
return (a+b);
}

//arrow function
const addTwoNumbers2=(a,b)=>{
return (a+b);
}
  • Implicit Return
//you can rewrite the above arrow function like this but not with normal fn
const addTwoNumbers2=(a,b)=>(a+b)
  • Arguments
//normal functions receive the arguments even without receiving them in the 
//formal parameters but arrow functions cannot
function hello(){
console.log(arguments);
}
hello(4,5);

  • This keyword
const user={
username:"Mainak",
rc1:()=>{
console.log(this.username);
},
rc2(){
console.log(this.username);
}
}
user.rc1();//this wont work and will return undefined since as per definition
//of arrow function it can't be used with this keyword
user.rc2();//normal function will work fine and will give the output

Wrapping Up

So thats it and thanks a lot for reading this far and I will meet you in the next part where we will demystify Closures , till then bye!