js3
25 Javascript Interview Question

25 Javascript Interview Question

1. What’s the difference between undefined and null?.

 Before understanding the differences between undefined and null we must understand the similarities between them.

  • They belong to JavaScript’s 7 primitive types.
 let primitiveTypes = ['string','number','null','undefined','boolean','symbol', 'bigint'];
  • They are falsy values. Values that evaluated to false when converting it to boolean using Boolean(value) or !!value.
   console.log(!!null); //logs false
   console.log(!!undefined); //logs false

   console.log(Boolean(null)); //logs false
   console.log(Boolean(undefined)); //logs false

Ok, let’s talk about the differences.

  • undefined is the default value of a variable that has not been assigned a specific value. Or a function that has no explicit return value ex. console.log(1). Or a property that does not exist in an object. The JavaScript engine does this for us the assigning of undefined value.
  let _thisIsUndefined;
  const doNothing = () => {};
  const someObj = {
    a : "ay",
    b : "bee",
    c : "si"
  };

  console.log(_thisIsUndefined); //logs undefined
  console.log(doNothing()); //logs undefined
  console.log(someObj["d"]); //logs undefined
  • null is “a value that represents no value”null is value that has been explicitly defined to a variable. In this example we get a value of null when the fs.readFile method does not throw an error.
  fs.readFile('path/to/file', (e,data) => {
     console.log(e); //it logs null when no error occurred
     if(e){
       console.log(e);
     }
     console.log(data);
   });

When comparing null and undefined we get true when using == and false when using ===. You can read the reason here.

   console.log(null == undefined); // logs true
   console.log(null === undefined); // logs false

2. What does the && operator do?

 The && or Logical AND operator finds the first falsy expression in its operands and returns it and if it does not find any falsy expression it returns the last expression. It employs short-circuiting to prevent unnecessary work. I’ve used this in the catch block when closing database connection in one of my projects.

   console.log(false && 1 && []); //logs false
   console.log(" " && true && 5); //logs 5

Using if statements.

  const router: Router = Router();

  router.get('/endpoint', (req: Request, res: Response) => {
     let conMobile: PoolConnection;
     try {
        //do some db operations
     } catch (e) {
     if (conMobile) {
      conMobile.release();
     }
  }
});

Using && operator.

const router: Router = Router();

router.get('/endpoint', (req: Request, res: Response) => {
  let conMobile: PoolConnection;
  try {
     //do some db operations
  } catch (e) {
    conMobile && conMobile.release()
  }
});

3. What does the || operator do?

 The || or Logical OR operator finds the first truthy expression in its operands and returns it. This too employs short-circuiting to prevent unnecessary work. It was used before to initialize default parameter values IN functions before ES6 Default function parameters was supported.

console.log(null || 1 || undefined); //logs 1

function logName(name) {
  var n = name || "Mark";
  console.log(n);
}

logName(); //logs "Mark"

4. Is using the + or unary plus operator the fastest way in converting a string to a number?

 According to MDN Documentation the + is the fastest way of converting a string to a number because it does not perform any operations on the value if it is already a number.

5. What is the DOM?

 DOM stands for Document Object Model is an interface (API) for HTML and XML documents. When the browser first reads (parses) our HTML document it creates a big object, a really big object based on the HTML document this is the DOM. It is a tree-like structure that is modeled from the HTML document. The DOM is used for interacting and modifying the DOM structure or specific Elements or Nodes.

Imagine if we have an HTML structure like this.

<!DOCTYPE html>
<html lang="en">

<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <meta http-equiv="X-UA-Compatible" content="ie=edge">
   <title>Document Object Model</title>
</head>

<body>
   <div>
      <p>
         <span></span>
      </p>
      <label></label>
      <input>
   </div>
</body>

</html>

The DOM equivalent would be like this.

The document object in JavaScript represents the DOM. It provides us many methods that we can use to selecting elements to update element contents and many more.

6. What is Event Propagation?

 When an event occurs on a DOM element, that event does not entirely occur on that just one element. In the Bubbling Phase, the event bubbles up or it goes to its parent, to its grandparents, to its grandparent’s parent until it reaches all the way to the window while in the Capturing Phase the event starts from the window down to the element that triggered the event or the event.target.

Event Propagation has three phases.

  1. Capturing Phase – the event starts from window then goes down to every element until it reaches the target element.
  2. Target Phase – the event has reached the target element.
  3. Bubbling Phase – the event bubbles up from the target element then goes up every element until it reaches the window.
Event Propagation

7. What’s Event Bubbling?

 When an event occurs on a DOM element, that event does not entirely occur on that just one element. In the Bubbling Phase, the event bubbles up or it goes to its parent, to its grandparents, to its grandparent’s parent until it reaches all the way to the window.

If we have an example markup like this.

 <div class="grandparent">
    <div class="parent">
      <div class="child">1</div>
    </div>
  </div>

And our js code.

function addEvent(el, event, callback, isCapture = false) {
  if (!el || !event || !callback || typeof callback !== 'function') return;
  if (typeof el === 'string') {
    el = document.querySelector(el);
  };
  el.addEventListener(event, callback, isCapture);
}

addEvent(document, 'DOMContentLoaded', () => {
  const child = document.querySelector('.child');
  const parent = document.querySelector('.parent');
  const grandparent = document.querySelector('.grandparent');

  addEvent(child, 'click', function (e) {
    console.log('child');
  });

  addEvent(parent, 'click', function (e) {
    console.log('parent');
  });

  addEvent(grandparent, 'click', function (e) {
    console.log('grandparent');
  });

  addEvent(document, 'click', function (e) {
    console.log('document');
  });

  addEvent('html', 'click', function (e) {
    console.log('html');
  })

  addEvent(window, 'click', function (e) {
    console.log('window');
  })

});

The addEventListener method has a third optional parameter useCapture with a default value of false the event will occur in the Bubbling phase if true the event will occur in the Capturing Phase. If we click on the child element it logs child,parent,grandparenthtmldocument and window respectively on the console. This is Event Bubbling.

8. What’s Event Capturing?

 When an event occurs on a DOM element, that event does not entirely occur on that just one element. In Capturing Phase, the event starts from the window all the way down to the element that triggered the event.

If we have an example markup like this.

 <div class="grandparent">
    <div class="parent">
      <div class="child">1</div>
    </div>
  </div>

And our js code.

function addEvent(el, event, callback, isCapture = false) {
  if (!el || !event || !callback || typeof callback !== 'function') return;
  if (typeof el === 'string') {
    el = document.querySelector(el);
  };
  el.addEventListener(event, callback, isCapture);
}

addEvent(document, 'DOMContentLoaded', () => {
  const child = document.querySelector('.child');
  const parent = document.querySelector('.parent');
  const grandparent = document.querySelector('.grandparent');

  addEvent(child, 'click', function (e) {
    console.log('child');
  }, true);

  addEvent(parent, 'click', function (e) {
    console.log('parent');
  }, true);

  addEvent(grandparent, 'click', function (e) {
    console.log('grandparent');
  }, true);

  addEvent(document, 'click', function (e) {
    console.log('document');
  }, true);

  addEvent('html', 'click', function (e) {
    console.log('html');
  }, true)

  addEvent(window, 'click', function (e) {
    console.log('window');
  }, true)

});

The addEventListener method has a third optional parameter useCapture with a default value of false the event will occur in the Bubbling phase if true the event will occur in the Capturing Phase. If we click on the child element it logs window,document,htmlgrandparent and parent and child respectively on the console. This is Event Capturing.

9. What’s the difference between event.preventDefault() and event.stopPropagation() methods?

 The event.preventDefault() method prevents the default behavior of an element. If used in a form element it prevents it from submitting. If used in an anchor element it prevents it from navigating. If used in a contextmenu it prevents it from showing or displaying. While the event.stopPropagation() method stops the propogation of an event or it stops the event from occurring in the bubbling or capturing phase.

10. How to know if the event.preventDefault() method was used in an element?

 We can use the event.defaultPrevented property in the event object. It returns a boolean indicating if the event.preventDefault() was called in a particular element.

11. Why does this code obj.someprop.x throw an error?

const obj = {};
console.log(obj.someprop.x);

Obviously, this throws an error due to the reason we are trying to access a
x property in the someprop property which have an undefined value. Remember properties in an object which does not exist in itself and its prototype has a default value of undefined and undefined has no property x.

12. What is event.target ?

 In simplest terms, the event.target is the element on which the event occurred or the element that triggered the event.

Sample HTML Markup.

<div onclick="clickFunc(event)" style="text-align: center;margin:15px;
border:1px solid red;border-radius:3px;">
    <div style="margin: 25px; border:1px solid royalblue;border-radius:3px;">
        <div style="margin:25px;border:1px solid skyblue;border-radius:3px;">
          <button style="margin:10px">
             Button
          </button>
        </div>
    </div>
  </div>

Sample JavaScript.

 function clickFunc(event) {
  console.log(event.target);
}

If you click the button it will log the button markup even though we attach the event on the outermost div it will always log the button so we can conclude that the event.target is the element that triggered the event.

13. What is event.currentTarget?

 The event.currentTarget is the element on which we attach the event handler explicitly.

Copying the markup in Question 12.
Sample HTML Markup.

<div onclick="clickFunc(event)" style="text-align: center;margin:15px;
border:1px solid red;border-radius:3px;">
    <div style="margin: 25px; border:1px solid royalblue;border-radius:3px;">
        <div style="margin:25px;border:1px solid skyblue;border-radius:3px;">
          <button style="margin:10px">
             Button
          </button>
        </div>
    </div>
  </div>

And changing our the JS a little bit.

function clickFunc(event) {
  console.log(event.currentTarget);
}

If you click the button it will log the outermost div markup even though we click the button. In this example, we can conclude that the event.currentTarget is the element on which we attach the event handler.

14. What’s the difference between == and === ?

 The difference between ==(abstract equality) and ===(strict equality) is that the == compares by value after coercion and === compares by value and type without coercion.

Let’s dig deeper on the ==. So first let’s talk about coercion.

coercion is the process of converting a value to another type. As in this case, the == does implicit coercion. The == has some conditions to perform before comparing the two values.

Suppose we have to compare x == y values.

  1. If x and y have same type. Then compare them with the === operator.
  2. If x is null and y is undefined then return true.
  3. If x is undefined and y is null then return true.
  4. If x is type number and y is type string Then return x == toNumber(y).
  5. If x is type string and y is type number Then return toNumber(x) == y.
  6. If x is type boolean Then return toNumber(x) == y.
  7. If y is type boolean Then return x == toNumber(y).
  8. If x is either string,symbol or number and y is type object Then return x == toPrimitive(y).
  9. If x is either object and x is either string,symbol Then return toPrimitive(x) == y.
  10. Return false.

Note: toPrimitive uses first the valueOf method then the toString method in objects to get the primitive value of that object.

Let’s have examples.

xyx == y
55true
1'1'true
nullundefinedtrue
0falsetrue
'1,2'[1,2]true
'[object Object]'{}true

These examples all return true.

The first example goes to condition one because x and y have the same type and value.

The second example goes to condition four y is converted to a number before comparing.

The third example goes to condition two.

The fourth example goes to condition seven because y is boolean.

The fifth example goes to condition eight. The array is converted to a string using the toString() method which returns 1,2.

The last example goes to condition ten. The object is converted to a string using the toString() method which returns [object Object].

xyx === y
55true
1'1'false
nullundefinedfalse
0falsefalse
'1,2'[1,2]false
'[object Object]'{}false

If we use the === operator all the comparisons except for the first example will return false because they don’t have the same type while the first example will return true because the two have the same type and value.

15. Why does it return false when comparing two similar objects in JavaScript?

 Suppose we have an example below.

let a = { a: 1 };
let b = { a: 1 };
let c = a;

console.log(a === b); // logs false even though they have the same property
console.log(a === c); // logs true hmm

JavaScript compares objects and primitives differently. In primitives it compares them by value while in objects it compares them by reference or the address in memory where the variable is stored. That’s why the first console.log statement returns false and the second console.log statement returns truea and c have the same reference and a and b are not.

16. What does the !! operator do?

 The Double NOT operator or !! coerces the value on the right side into a boolean. basically it’s a fancy way of converting a value into a boolean.

console.log(!!null); //logs false
console.log(!!undefined); //logs false
console.log(!!''); //logs false
console.log(!!0); //logs false
console.log(!!NaN); //logs false
console.log(!!' '); //logs true
console.log(!!{}); //logs true
console.log(!![]); //logs true
console.log(!!1); //logs true
console.log(!![].length); //logs false

17. How to evaluate multiple expressions in one line?

We can use the , or comma operator to evaluate multiple expressions in one line. It evaluates from left-to-right and returns the value of the last item on the right or the last operand.

let x = 5;

x = (x++ , x = addFive(x), x *= 2, x -= 5, x += 10);

function addFive(num) {
  return num + 5;
}

If you log the value of x it would be 27. First, we increment the value of x it would be 6, then we invoke the function addFive(6) and pass the 6 as a parameter and assign the result to x the new value of x would be 11. After that, we multiply the current value of x to 2 and assign it to x the updated value of x would be 22. Then, we subtract the current value of x to 5 and assign the result to x the updated value would be 17. And lastly, we increment the value of x by 10 and assign the updated value to x now the value of x would be 27.

18. What is Hoisting?

 Hoisting is the term used to describe the moving of variables and functions to the top of their (global or function) scope on where we define that variable or function.

Ok to understand Hoisting, I have to explain the execution context.
The Execution Context is the “environment of code” that is currently executing. The Execution Context has two phases compilation and execution.

Compilation – in this phase it gets all the function declarations and hoists them up to the top of their scope so we can reference them later and gets all variables declaration (declare with the var keyword) and also hoists them up and give them a default value of undefined.

Execution – in this phase it assigns values to the variables hoisted earlier and it executes or invokes functions (methods in objects).

Note: only function declarations and variables declared with the var keyword are hoisted not function expressions or arrow functionslet and const keywords.

Ok, suppose we have an example code in the global scope below.

console.log(y);
y = 1;
console.log(y);
console.log(greet("Mark"));

function greet(name){
  return 'Hello ' + name + '!';
}

var y;

This code logs undefined,1Hello Mark! respectively.

So the compilation phase would look like this.

function greet(name) {
  return 'Hello ' + name + '!';
}

var y; //implicit "undefined" assignment

//waiting for "compilation" phase to finish

//then start "execution" phase
/*
console.log(y);
y = 1;
console.log(y);
console.log(greet("Mark"));
*/

for example purposes, I commented on the assignment of variable and function call.

After the compilation phase finishes it starts the execution phase invoking methods and assigns values to variables.

function greet(name) {
  return 'Hello ' + name + '!';
}

var y;

//start "execution" phase

console.log(y);
y = 1;
console.log(y);
console.log(greet("Mark"));

19. What is Scope?

 Scope in JavaScript is the area where we have valid access to variables or functions. JavaScript has three types of Scopes. Global ScopeFunction Scope, and Block Scope(ES6).

  • Global Scope – variables or functions declared in the global namespace are in the global scope and therefore is accessible everywhere in our code.
   //global namespace
   var g = "global";

   function globalFunc(){
     function innerFunc(){
          console.log(g); // can access "g" because "g" is a global variable
     }
     innerFunc();
   }  
  • Function Scope – variables,functions and parameters declared within a function are accessible inside that function but not outside of it.
    function myFavoriteFunc(a) {
       if (true) {
          var b = "Hello " + a;
       }
       return b;
   }
   myFavoriteFunc("World");

   console.log(a); // Throws a ReferenceError "a" is not defined
   console.log(b); // does not continue here 
  • Block Scope – variables (let,const) declared within a block {} can only be access within it.
 function testBlock(){
   if(true){
     let z = 5;
   }
   return z; 
 }

 testBlock(); // Throws a ReferenceError "z" is not defined

Scope is also a set of rules for finding variables. If a variable does not exist in the current scope it look ups and searches for a variable in the outer scope and if does not exist again it looks up again until it reaches the global scope if the variable exists then we can use it if not it throws an error. It searches for the nearest variable and it stops searching or looking up once it finds it. This is called Scope Chain.

   /* Scope Chain
   Inside inner function perspective

   inner's scope -> outer's scope -> global's scope
  */


  //Global Scope
  var variable1 = "Comrades";   
  var variable2 = "Sayonara";

  function outer(){
  //outer's scope
    var variable1 = "World";
    function inner(){
    //inner's scope
      var variable2 = "Hello";
      console.log(variable2 + " " + variable1);
    }
    inner();
  }  
  outer(); 
// logs Hello World 
// because (variable2 = "Hello") and (variable1 = "World") are the nearest 
// variables inside inner's scope.
Scope

20. What are Closures?

 This is probably the hardest question of all these questions because Closures is a controversial topic. So I’m gonna explain it from what I understand.

Closures is simply the ability of a function at the time of declaration to remember the references of variables and parameters on its current scope, on its parent function scope, on its parent’s parent function scope until it reaches the global scope with the help of Scope Chain. Basically it is the Scope created when the function was declared.

Examples are a great way to explain closures.

   //Global's Scope
   var globalVar = "abc";

   function a(){
   //testClosures's Scope
     console.log(globalVar);
   }

   a(); //logs "abc" 
   /* Scope Chain
      Inside a function perspective

      a's scope -> global's scope  
   */ 

In this example, when we declare the a function the Global Scope is part of a's closure.

a's closure

The reason for the variable globalVar which does not have a value in the image because of the reason that the value of that variable can change based on where and when we invoke the a function.
But in our example above the globalVar variable will have the value of abc.

Ok, let’s have a complex example.

var globalVar = "global";
var outerVar = "outer"

function outerFunc(outerParam) {
  function innerFunc(innerParam) {
    console.log(globalVar, outerParam, innerParam);
  }
  return innerFunc;
}

const x = outerFunc(outerVar);
outerVar = "outer-2";
globalVar = "guess"
x("inner");


This will print “guess outer inner”. The explanation for this is that when we invoke the outerFunc function and assigned the returned value the innerFunc function to the variable x, the outerParam will have a value of outer even though we assign a new value outer-2 to the outerVar variable because
the reassignment happened after the invocation of the outer function and in that time when we invoke the outerFunc function it’s look up the value of outerVar in the Scope Chain, the outerVar will have a value of “outer”. Now, when we invoke the x variable which have a reference to the innerFunc, the
innerParam will have a value of inner because thats the value we pass in the invocation and the globalVar variable will have a value of guess because before the invocation of the x variable we assign a new value to the globalVar and at the time of invocation x the value of globalVar in the Scope Chain is guess.

We have an example that demonstrates a problem of not understanding closure correctly.

const arrFuncs = [];
for(var i = 0; i < 5; i++){
  arrFuncs.push(function (){
    return i;
  });
}
console.log(i); // i is 5

for (let i = 0; i < arrFuncs.length; i++) {
  console.log(arrFuncs[i]()); // all logs "5"
}

This code is not working as we expected because of Closures.
The var keyword makes a global variable and when we push a function
we return the global variable i. So when we call one of those functions in that array after the loop it logs 5 because we get
the current value of i which is 5 and we can access it because it’s a global variable. Because Closures keeps the references of that variable not its values at the time of it’s creation. We can solve this using IIFES or changing the var keyword to let for block-scoping.

21. What are the falsy values in JavaScript?

 const falsyValues = ['', 0, null, undefined, NaN, false];

falsy values are values that when converted to boolean becomes false.

22. How to check if a value is falsy?

 Use the Boolean function or the Double NOT operator !!

23. What does "use strict" do?

 "use strict" is a ES5 feature in JavaScript that makes our code in Strict Mode in functions or entire scriptsStrict Mode helps us avoid bugs early on in our code and adds restrictions to it.

Restrictions that Strict Mode gives us.

  • Assigning or Accessing a variable that is not declared.
 function returnY(){
    "use strict";
    y = 123;
    return y;
 }
  • Assigning a value to a read-only or non-writable global variable;
   "use strict";
   var NaN = NaN;
   var undefined = undefined;
   var Infinity = "and beyond";
  • Deleting an undeletable property.
   "use strict";
   const obj = {};

   Object.defineProperty(obj, 'x', {
      value : '1'
   });  

   delete obj.x;
  • Duplicate parameter names.
   "use strict";

   function someFunc(a, b, b, c){

   }
  • Creating variables with the use of the eval function.
 "use strict";

 eval("var x = 1;");

 console.log(x); //Throws a Reference Error x is not defined

  • The default value of this will be undefined.
  "use strict";

  function showMeThis(){
    return this;
  }

  showMeThis(); //returns undefined

There are many more restrictions in Strict Mode than these.

24. What’s the value of this in JavaScript?

 Basically, this refers to the value of the object that is currently executing or invoking the function. I say currently due to the reason that the value of this changes depending on the context on which we use it and where we use it.

   const carDetails = {
     name: "Ford Mustang",
     yearBought: 2005,
     getName(){
        return this.name;
     },
     isRegistered: true
   };

   console.log(carDetails.getName()); // logs Ford Mustang

This is what we would normally expect because in the getName method we return this.namethis in this context refers to the object which is the carDetails object that is currently the “owner” object of the function executing.

Ok, Let’s some add some code to make it weird. Below the console.log statement add this three lines of code

   var name = "Ford Ranger";
   var getCarName = carDetails.getName;

   console.log(getCarName()); // logs Ford Ranger

The second console.log statement prints the word Ford Ranger which is weird because in our first console.log statement it printed Ford Mustang. The reason to this is that the getCarName method has a different “owner” object that is the window object. Declaring variables with the var keyword in the global scope attaches properties in the window object with the same name as the variables. Remember this in the global scope refers to the window object when "use strict" is not used.

  console.log(getCarName === window.getCarName); //logs true
  console.log(getCarName === this.getCarName); // logs true

this and window in this example refer to the same object.

One way of solving this problem is by using the apply and call methods in functions.

   console.log(getCarName.apply(carDetails)); //logs Ford Mustang
   console.log(getCarName.call(carDetails));  //logs Ford Mustang

The apply and call methods expects the first parameter to be an object which would be value of this inside that function.

IIFE or Immediately Invoked Function Expression, Functions that are declared in the global scope, Anonymous Functions and Inner functions in methods inside an object has a default of this which points to the window object.

   (function (){
     console.log(this);
   })(); //logs the "window" object

   function iHateThis(){
      console.log(this);
   }

   iHateThis(); //logs the "window" object  

   const myFavoriteObj = {
     guessThis(){
        function getThis(){
          console.log(this);
        }
        getThis();
     },
     name: 'Marko Polo',
     thisIsAnnoying(callback){
       callback();
     }
   };


   myFavoriteObj.guessThis(); //logs the "window" object
   myFavoriteObj.thisIsAnnoying(function (){
     console.log(this); //logs the "window" object
   });

If we want to get the value of the name property which is Marko Polo in the myFavoriteObj object there are two ways to solve this.

First, we save the value of this in a variable.

   const myFavoriteObj = {
     guessThis(){
         const self = this; //saves the this value to the "self" variable
         function getName(){
           console.log(self.name);
         }
         getName();
     },
     name: 'Marko Polo',
     thisIsAnnoying(callback){
       callback();
     }
   };

In this image we save the value of this which would be the myFavoriteObj object. So we can access it inside the getName inner function.

Second, we use ES6 Arrow Functions.

   const myFavoriteObj = {
     guessThis(){
         const getName = () => { 
           //copies the value of "this" outside of this arrow function
           console.log(this.name);
         }
         getName();
     },
     name: 'Marko Polo',
     thisIsAnnoying(callback){
       callback();
     }
   };

Arrow Functions does not have its own this. It copies the value of this of the enclosing lexical scope or in this example the value of this outside the getName inner function which would be the myFavoriteObj object. We can also determine the value of this on how the function is invoked.

25. What is the prototype of an object?

 A prototype in simplest terms is a blueprint of an object. It is used as a fallback for properties and methods if it does exist in the current object. It’s the way to share properties and functionality between objects. It’s the core concept around JavaScript’s Prototypal Inheritance.

  const o = {};
  console.log(o.toString()); // logs [object Object] 

Even though the o.toString method does not exist in the o object it does not throw an error instead returns a string [object Object]. When a property does not exist in the object it looks into its prototype and if it still does not exist it looks into the prototype’s prototype and so on until it finds a property with the same in the Prototype Chain. The end of the Prototype Chain is the Object.prototype.

   console.log(o.toString === Object.prototype.toString); // logs true
   // which means we we're looking up the Prototype Chain and it reached 
   // the Object.prototype and used the "toString" method.

26. What is an IIFE, what is the use of it?

 An IIFE or Immediately Invoked Function Expression is a function that is gonna get invoked or executed after its creation or declaration. The syntax for creating IIFE is that we wrap the function (){} inside a parentheses () or the Grouping Operator to treat the function as an expression and after that we invoke it with another parentheses (). So an IIFE looks like this (function(){})().

(function () {

}());

(function () {

})();

(function named(params) {

})();

(() => {

})();

(function (global) {

})(window);

const utility = (function () {
   return {
      //utilities
   };
})();

These examples are all valid IIFE. The second to the last example shows we can pass arguments to an IIFE function. The last example shows that we can save the result of the IIFE to a variable so we can reference it later.

The best use of IIFE is making initialization setup functionalities and to avoid naming collisions with other variables in the global scope or polluting the global namespace. Let’s have an example.

<script src="https://cdnurl.com/somelibrary.js"></script>

Suppose we have a link to a library somelibrary.js that exposes some global functions that we use can in our code but this library has two methods that we don’t use createGraph and drawGraph because these methods have bugs in them. And we want to implement our own createGraph and drawGraph methods.

  • One way of solving this is by changing the structure of our scripts.
<script src="https://cdnurl.com/somelibrary.js"></script>
<script>
   function createGraph() {
      // createGraph logic here
   }
   function drawGraph() {
      // drawGraph logic here
   }
</script>

When we use this solution we are overriding those two methods that the library gives us.

  • Another way of solving this is by changing the name of our own helper functions.
<script src="https://cdnurl.com/somelibrary.js"></script>
<script>
   function myCreateGraph() {
      // createGraph logic here
   }
   function myDrawGraph() {
      // drawGraph logic here
   }
</script>

When we use this solution we will also change those function calls to the new function names.

  • Another way is using an IIFE.
<script src="https://cdnurl.com/somelibrary.js"></script>
<script>
   const graphUtility = (function () {
      function createGraph() {
         // createGraph logic here
      }
      function drawGraph() {
         // drawGraph logic here
      }
      return {
         createGraph,
         drawGraph
      }
   })();
</script>

In this solution, we are making a utility variable that is the result of IIFE which returns an object that contains two methods createGraph and drawGraph.

Another problem that IIFE solves is in this example.

var li = document.querySelectorAll('.list-group > li');
for (var i = 0, len = li.length; i < len; i++) {
   li[i].addEventListener('click', function (e) {
      console.log(i);
   })
}

Suppose we have a ul element with a class of list-group and it has 5 li child elements. And we want to console.log the value of i when we click an individual li element.
But the behavior we want in this code does not work. Instead, it logs 5 in any click on an li element. The problem we’re having is due to how Closures work. Closures are simply the ability of functions to remember the references of variables on its current scope, on its parent function scope and in the global scope. When we declare variables using the var keyword in the global scope, obviously we are making a global variable i. So when we click an li element it logs 5 because that is the value of i when we reference it later in the callback function.

  • One solution to this is an IIFE.
var li = document.querySelectorAll('.list-group > li');
for (var i = 0, len = li.length; i < len; i++) {
   (function (currentIndex) {
      li[currentIndex].addEventListener('click', function (e) {
         console.log(currentIndex);
      })
   })(i);
}

This solution works because of the reason that the IIFE creates a new scope for every iteration and we capture the value of i and pass it into the currentIndex parameter so the value of currentIndex is different for every iteration when we invoke the IIFE.

27. What is the use Function.prototype.apply method?

 The apply invokes a function specifying the this or the “owner” object of that function on that time of invocation.

const details = {
  message: 'Hello World!'
};

function getMessage(){
  return this.message;
}

getMessage.apply(details); // returns 'Hello World!'

This method works like Function.prototype.call the only difference is how we pass arguments. In apply we pass arguments as an array.

const person = {
  name: "Marko Polo"
};

function greeting(greetingMessage) {
  return `${greetingMessage} ${this.name}`;
}

greeting.apply(person, ['Hello']); // returns "Hello Marko Polo!"

28. What is the use Function.prototype.call method?

 The call invokes a function specifying the this or the “owner” object of that function on that time of invocation.

const details = {
  message: 'Hello World!'
};

function getMessage(){
  return this.message;
}

getMessage.call(details); // returns 'Hello World!'

This method works like Function.prototype.apply the only difference is how we pass arguments. In call we pass directly the arguments separating them with a comma , for every argument.

const person = {
  name: "Marko Polo"
};

function greeting(greetingMessage) {
  return `${greetingMessage} ${this.name}`;
}

greeting.call(person, 'Hello'); // returns "Hello Marko Polo!"

 206 total views,  1 views today

Leave a Reply

Your email address will not be published. Required fields are marked *