Arrow functions vs Normal functions

In JavaScript, both arrow functions and normal functions can access variables from their enclosing scope due to lexical scoping. However, there is a notable difference in how this is treated by these two types of functions, which can affect how you might increment a variable inside a setTimeout.

Normal Function (Function Expression)

When you use a normal function, this refers to the context in which the function is called. If the context isn't bound or specified, in non-strict mode, this will default to the global object (window in browsers), or undefined in strict mode.

function Counter() {
  this.value = 0;

  // Using a normal function
  setTimeout(function increment() {
    this.value++;
    console.log(this.value);
  }, 1000);
}

const counter = new Counter(); //

In the above code, this inside the increment function does not refer to the instance of Counter because setTimeout calls increment with its own context. To fix this, you can bind the context explicitly:

function Counter() {
  this.value = 0;

  setTimeout((function increment() {
    this.value++;
    console.log(this.value);
  }).bind(this), 1000); // Using `.bind(this)` to ensure `this` refers to the Counter instance
}

const counter = new Counter();

Arrow Function

Arrow functions do not have their own this context. Instead, they capture the this value of the enclosing execution context at the time they are created. This means that within an arrow function, this remains the same throughout the lifecycle of the function and is lexically bound.

function Counter() {
  this.value = 0;

  // Using an arrow function
  setTimeout(() => {
    this.value++;
    console.log(this.value);
  }, 1000);
}

const counter = new Counter();

In this case, the arrow function captures the this value from the Counter function, so this.value refers to the value property on the Counter instance.

Incrementing a Variable with setTimeout

If the goal is simply to increment a variable and not to manipulate an object's properties, you don't need to worry about this at all. Here's how you can do it with both function types:

let value = 0;
setTimeout(function increment() {
  value++;
  console.log(value);
}, 1000);

// Using an arrow function
let value = 0;
setTimeout(() => {
  value++;
  console.log(value);
}, 1000);