Article Image

Javascript

Interview

Javascript Concepts Part 2

JavaScript Concepts - Part 2

Understanding Hoisting

Hoisting refers to JavaScript's default behavior of moving declarations to the top of their scope during the compilation phase. This ensures that variables and function declarations are recognized before any code is executed.

Example with variables:

console.log(foo); // undefined
var foo = 1;
console.log(foo); // 1
  • Function Declarations: The function body is hoisted.
  • Function Expressions: Only the variable declaration is hoisted, not the function body.
// Function Declaration
console.log(foo); // [Function: foo]
foo(); // 'FOOOOO'
function foo() {
  console.log('FOOOOO');
}

// Function Expression
console.log(bar); // undefined
bar(); // TypeError: bar is not a function
var bar = function () {
  console.log('BARRRR');
};

For let and const, variables are hoisted but remain uninitialized, leading to a "temporal dead zone" until declared.

Closures Explained

Closures are functions that retain access to their outer scope's variables, even after the outer function has completed execution. This behavior is made possible due to JavaScript's lexical scoping.

Example:

function outerFunc() {
  let outerVar = 'I am outside!';
  function innerFunc() {
    console.log(outerVar);
  }
  return innerFunc;
}
const myInnerFunc = outerFunc();
myInnerFunc(); // Output: "I am outside!"

The innerFunc retains access to outerVar even when called outside its lexical scope.

Rest vs Spread Operators

Rest Operator

The rest operator (...) consolidates multiple elements into an array.

function myBio(firstName, lastName, ...details) {
  return details;
}

myBio("John", "Doe", "Developer", "Male");
// Output: ["Developer", "Male"]

Spread Operator

The spread operator (...) expands iterables into individual elements.

Example 1: Arrays

const nameParts = ["John", "Doe"];
const fullName = ["Mr.", ...nameParts];
console.log(fullName);
// Output: ["Mr.", "John", "Doe"]

Example 2: Strings

const word = "Hello";
console.log([...word]);
// Output: ["H", "e", "l", "l", "o"]

Example 3: Function Calls

const nums = [1, 2, 3];
console.log(Math.max(...nums)); // Output: 3

Example 4: Objects

const person = { firstName: "John", lastName: "Doe" };
const extended = { ...person, age: 30 };
console.log(extended);
// Output: { firstName: "John", lastName: "Doe", age: 30 }

Pure vs Impure Functions

  1. Pure Functions
    • Predictable.
    • No side effects.
    • Always return the same output for the same input.
  2. Impure Functions
    • Unpredictable.
    • Have side effects (e.g., modifying global variables, API calls).
// Pure Function
const pureAdd = (arr, num) => [...arr, num];

// Impure Function
const impureAdd = (arr, num) => {
  arr.push(num);
  return arr;
};

Higher-Order Functions

A higher-order function accepts a function as an argument or returns one.

Map

const nums = [1, 2, 3];
const doubled = nums.map(num => num * 2);
console.log(doubled); // Output: [2, 4, 6]

Filter

const ages = [10, 20, 30];
const adults = ages.filter(age => age >= 18);
console.log(adults); // Output: [20, 30]

Reduce

const nums = [1, 2, 3];
const sum = nums.reduce((total, num) => total + num, 0);
console.log(sum); // Output: 6

Call, Apply, and Bind

These methods allow functions to execute in different contexts.

CAB

Call

Invokes a function with arguments passed individually.

function greet(greeting) {
  return `${greeting}, ${this.name}`;
}
const person = { name: "John" };
console.log(greet.call(person, "Hello")); // Output: "Hello, John"

Apply

Similar to call, but arguments are passed as an array.

console.log(greet.apply(person, ["Hi"])); // Output: "Hi, John"

Bind

Returns a new function with a specific context.

const boundGreet = greet.bind(person, "Hey");
console.log(boundGreet()); // Output: "Hey, John"

This detailed breakdown of JavaScript concepts provides a strong foundation for interviews and practical applications.

Thanks for reading!!!

Muneer Ahmed

Author

0