Skip to content

JavaScript

Why using var should be avoided in moder JS?

You should avoid var in modern JavaScript because it has confusing scoping rules and behavior that can easily lead to bugs. The introduction of let and const in ES6 provides much safer and more predictable alternatives.

Here are the main reasons why:

1. Function Scope vs. Block Scope

This is the most significant difference. Variables declared with let and const have block scope, while var has function scope.

  • Block Scope (let/const): The variable only exists within the block ({...}) it was declared in. This is how most other programming languages work and is generally more intuitive.
  • Function Scope (var): The variable exists throughout the entire function in which it was declared, even outside the block.

Example:

JavaScript
function scopeTest() {
  if (true) {
    var myVar = "I am var";     // function-scoped
    let myLet = "I am let";     // block-scoped
    const myConst = "I am const"; // block-scoped
  }

  console.log(myVar);   // "I am var" -> 'var' leaks out of the if-block
  // console.log(myLet);   // ReferenceError: myLet is not defined
  // console.log(myConst); // ReferenceError: myConst is not defined
}

scopeTest();

Because var "leaks" out of blocks, it can lead to bugs where variables are accidentally overwritten or accessed in places you don't expect.

2. Hoisting

In JavaScript, variable declarations are "hoisted" (moved to the top of their scope) before the code is executed. However, var and let/const behave differently.

  • var is hoisted and initialized with undefined. This means you can access a var variable before its declaration without an error—it will just be undefined. This can hide bugs.

    JavaScript
    console.log(hoistedVar); // Outputs: undefined (not an error!)
    var hoistedVar = "I am hoisted";
    console.log(hoistedVar); // Outputs: "I am hoisted"
    
  • let and const are hoisted but not initialized. Accessing them before their declaration results in a ReferenceError. The area before the declaration is called the Temporal Dead Zone (TDZ), which prevents you from using a variable before it's declared. This is much safer.

    JavaScript
    // console.log(hoistedLet); // ReferenceError: Cannot access 'hoistedLet' before initialization
    let hoistedLet = "I am not accessible before this line";
    

3. Global Object Pollution

When used in the global scope (outside of any function), var creates a property on the global object (window in browsers). let and const do not.

This can cause problems by accidentally overwriting global properties defined by the browser or other scripts.

JavaScript
var globalVar = "I'm on the window object";
let globalLet = "I am not on the window object";

console.log(window.globalVar); // "I'm on the window object"
console.log(window.globalLet); // undefined

Conclusion: Use let and const

For cleaner, safer, and more predictable code, always use const by default for variables that won't be reassigned, and use let for variables that you intend to reassign. There is no modern use case where var is the better choice.


What are Arrow Functions in JavaScript?

Arrow functions are a compact way to write functions in JavaScript. Introduced in ES6, they offer a shorter syntax compared to traditional function expressions and have a special behavior with the this keyword.

Syntax

The core of an arrow function is the => "fat arrow," which gives it its name.

  • Traditional Function Expression:
JavaScript
const add = function (a, b) {
  return a + b;
};
  • Arrow Function Equivalent:
JavaScript
const add = (a, b) => {
  return a + b;
};

Arrow functions can be even more concise:

  • Implicit Return: If the function has only one expression, you can omit the curly braces {} and the return keyword.
    JavaScript
    const multiply = (a, b) => a * b; // Implicitly returns a * b
    
  • Single Parameter: If there's only one parameter, you can omit the parentheses ().
    JavaScript
    const greet = (name) => `Hello, ${name}!`;
    
  • No Parameters: If there are no parameters, you must use empty parentheses.
    JavaScript
    const sayHello = () => "Hello World!";
    

The 'this' Keyword: The Biggest Difference

The most significant difference isn't the syntax but how arrow functions handle the this keyword.

  • Traditional Functions get their own this value based on how they are called. This can be confusing, as this can change depending on the context (e.g., a simple function call, a method call, etc.).

  • Arrow Functions do not have their own this. Instead, they lexically inherit this from their parent scope. This means this has the same value inside the arrow function as it does outside of it.

Example

Consider an object with a method that uses a timer.

  • With a Traditional Function (Problem):
JavaScript
const person = {
  name: "Alex",
  sayNameAfterDelay: function () {
    setTimeout(function () {
      // 'this' here is the global window object, not 'person'
      console.log(this.name); // Prints 'undefined' or ''
    }, 1000);
  },
};
person.sayNameAfterDelay();

To fix this, developers historically had to use workarounds like const self = this; or .bind(this).

  • With an Arrow Function (Solution):
JavaScript
const person = {
  name: "Alex",
  sayNameAfterDelay: function () {
    setTimeout(() => {
      // The arrow function inherits 'this' from sayNameAfterDelay
      console.log(this.name); // Correctly prints 'Alex'
    }, 1000);
  },
};
person.sayNameAfterDelay();

The arrow function "remembers" the this from its surrounding context, making the code much more intuitive.


What is the Event Object is JS?

The event object is a special object that's automatically passed to an event handler function whenever an event (like a click, keypress, or mouse movement) occurs. It's packed with information about that specific event.

Think of it as a detailed report about what just happened. If the event is a "click," the event object tells you where the user clicked, what element they clicked on, and more.

How It Works in Code

When you write an event listener, you can include a parameter in your callback function. This parameter, conventionally named e, evt, or event, will automatically receive the event object from the browser.

HTML
<button id="myButton">Click Me</button>
JavaScript
const button = document.getElementById('myButton');

// The 'e' parameter here is the event object
button.addEventListener('click', function(e) {
  console.log(e); // Logs the entire MouseEvent object to the console

  // You can now access properties of the event
  console.log('Event type:', e.type);        // "click"
  console.log('Target element:', e.target);  // <button id="myButton">...</button>
});

When you click the button, the browser creates the event object and passes it to your function.

Common Properties and Methods

The event object has many useful properties and methods. The exact ones available depend on the type of event, but here are some of the most common:

  • event.target: The most useful property. It's the element that triggered the event. For example, if you click on a button, event.target is that button element.

  • event.type: A string indicating the type of event that occurred (e.g., "click", "keydown", "mouseover").

  • event.preventDefault(): A method that stops the browser's default behavior for that event. For example, calling this on a form's "submit" event will prevent the page from reloading.

  • event.stopPropagation(): A method that stops an event from "bubbling up" to parent elements. This prevents event listeners on ancestor elements from also firing.

  • event.key: For keyboard events (keydown, keyup), this property tells you which key was pressed (e.g., "a", "Enter", "Escape").

  • event.clientX and event.clientY: For mouse events, these properties give you the horizontal and vertical coordinates of the mouse pointer relative to the visible part of the browser window.


What is an Even Handler Function?

An event handler is a JavaScript function that runs in response to a specific event, like a user clicking a button or pressing a key. It's the code that "handles" the event by performing a task.

Think of it as the set of instructions for a fire alarm. The event is smoke being detected. The event handler is the function that runs in response: "sound the alarm, flash the lights, and call the fire department."

How to Assign Event Handlers

There are a few ways to attach an event handler to an HTML element, but the modern addEventListener() method is the best practice.

1. Inline HTML Attribute (Old Method - Avoid)

You can assign the handler directly in the HTML. This is generally avoided because it mixes your JavaScript logic with your HTML structure.

HTML
<button onclick="alert('You clicked me!')">Click Me</button>

2. DOM Property

You can assign a function to an element's on<event> property (e.g., onclick, onmouseover). This is better, but you can only assign one handler per event.

JavaScript
const button = document.getElementById('myButton');

button.onclick = function() {
  console.log('Button was clicked!');
};

This is the standard and most flexible method. It allows you to attach multiple handlers for the same event to a single element.

The event handler function automatically receives the event object as its first argument, providing details about the event.

JavaScript
const button = document.getElementById('myButton');

// The function below is the event handler
const handleClick = (e) => {
  // 'e' is the event object
  console.log('Button was clicked!');
  console.log('Target element:', e.target);
};

// We "listen" for a 'click' event and attach our handler function to it
button.addEventListener('click', handleClick);

In this example, handleClick is the event handler. The addEventListener method is the event listener that waits for the event to happen and then calls the handler.