Sitemap

Arrow Functions vs. Normal Functions: The Seven Missing Superpowers You Need to Know

key distinctions between arrow and normal functions

5 min readJul 9, 2025

--

Press enter or click to view image in full size
Photo by Ben Robbins on Unsplash

The Dynamic this Duo: this Binding

  • Normal Function Superpower: Normal functions get their own this context, which changes based on how they're called. (Explain call, apply, bind, and method calls).
// Code example: `this` in a normal function method
const person = {
name: "Alice",
greet: function() {
console.log(`Hello, my name is ${this.name}`);
}
};
person.greet(); // Output: "Hello, my name is Alice"

// Code example: `this` with call/apply/bind
const anotherPerson = {
name: "Bob"
};
person.greet.call(anotherPerson); // Output: "Hello, my name is Bob"
  • Arrow Function’s Limitation: Arrow functions don’t have their own this. They lexically inherit this from their surrounding scope. Explain why this is often a feature but can be a limitation when you need dynamic this.
// Code example: `this` in an arrow function
const anotherPerson = {
name: "Charlie",
greet: () => {
// 'this' here refers to the global object (or 'undefined' in strict mode)
// NOT the 'anotherPerson' object
console.log(`Hello, my name is ${this.name}`);
}
};
anotherPerson.greet(); // Output might be "Hello, my name is undefined" or similar, depending on environment

// When lexical 'this' is useful (e.g., inside a method)
const counter = {
value: 0,
start: function() {
// Normal function for the method itself to get 'this' of 'counter'
setInterval(() => {
// Arrow function here inherits 'this' from 'start' method
this.value++;
console.log(this.value);
}, 1000);
}
};
counter.start();

Hoisting Heroics: When You Can Call Before You Declare

  • Normal Function Superpower: Function declarations (a type of normal function) are hoisted, meaning you can call them before they appear in the code.
// Code example: Hoisting a normal function declaration
sayHello(); // Output: "Hello from a hoisted function!"

function sayHello() {
console.log("Hello from a hoisted function!");
}
  • Arrow Function’s Limitation: Arrow function expressions (and function expressions in general) are not hoisted in the same way. You need to declare them before you use them.
// Code example: No hoisting for arrow functions
// sayGoodbye(); // This would throw a ReferenceError

const sayGoodbye = () => {
console.log("Goodbye from an arrow function!");
};
sayGoodbye(); // This works

The arguments Arsenal: Accessing All Inputs

  • Normal Function Superpower: Normal functions have access to the arguments object, a built-in array-like structure containing all the arguments passed to the function.
// Code example: `arguments` object in a normal function
function sumAllNormal() {
let sum = 0;
for (let i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
console.log("Normal function sum:", sum);
}
sumAllNormal(1, 2, 3, 4); // Output: "Normal function sum: 10"
  • Arrow Function’s Limitation: Arrow functions do not have their own arguments object. You'd typically use rest parameters (...args) instead.
// Code example: No `arguments` object in arrow functions
const sumAllArrow = (...args) => { // Use rest parameters instead
const sum = args.reduce((acc, current) => acc + current, 0);
console.log("Arrow function sum (with rest parameters):", sum);
// console.log(arguments); // This would throw a ReferenceError or refer to outer scope's arguments
};
sumAllArrow(1, 2, 3, 4); // Output: "Arrow function sum (with rest parameters): 10"

Constructor Caper: Building New Objects with new

Normal Function Superpower: Normal functions can be used as constructors with the new keyword to create new instances of objects.

// Code example: Normal function as a constructor
function Car(make, model) {
this.make = make;
this.model = model;
}
const myCar = new Car("Honda", "Civic");
console.log(myCar); // Output: Car { make: "Honda", model: "Civic" }
  • Arrow Function’s Limitation: Arrow functions cannot be used as constructors. Trying to use new with an arrow function will throw an error.
// Code example: Arrow function cannot be a constructor
const Boat = (make, model) => {
this.make = make;
this.model = model;
};
// const myBoat = new Boat("Yamaha", "Speedster"); // This would throw TypeError: Boat is not a constructor
// console.log(myBoat);

Duplicate Debacle: Parameter Names

  • Normal Function Superpower: In non-strict mode, normal functions allow duplicate parameter names (though this is generally bad practice).
// Code example: Duplicate parameters in normal function (non-strict mode)
// Note: This is generally bad practice and should be avoided in new code.
function oldSchoolParams(a, b, a) {
console.log("Normal function with duplicate params:", a, b);
}
oldSchoolParams(1, 2, 3); // Output: "Normal function with duplicate params: 3 2" (last 'a' wins)
  • Arrow Function’s Limitation: Arrow functions, by their nature, are always in strict mode regarding parameters, meaning duplicate parameter names will throw a SyntaxError.
// Code example: Duplicate parameters throw error in arrow functions
// const modernParams = (x, y, x) => { // This line would cause a SyntaxError during parsing
// console.log(x, y);
// };
// modernParams(10, 20, 30);

Generator Glimmer: Pausing and Resuming Execution

  • Normal Function Superpower: Normal functions can be designated as generator functions (function*) allowing for iterable, pauseable execution.
// Code example: Normal function as a generator
function* idGenerator() {
let id = 1;
while (true) {
yield id++;
}
}
const gen = idGenerator();
console.log("Generated ID 1:", gen.next().value); // Output: "Generated ID 1: 1"
console.log("Generated ID 2:", gen.next().value); // Output: "Generated ID 2: 2"

Arrow Function’s Limitation: Arrow functions cannot be generator functions.

// Code example: Arrow function cannot be a generator
// const arrowGenerator =* () => { // SyntaxError: * is not allowed in arrow function parameters
// yield 1;
// };

Event Listener Elixir: this Context in DOM Events

  • Normal Function Superpower: When a normal function is used as an event listener, its this context refers to the element that triggered the event.
// Code example: `this` in a normal event listener
// (Imagine this running in a browser console)
/*
<button id="myButton">Click Me</button>
<script>
document.getElementById('myButton').addEventListener('click', function() {
console.log(this); // 'this' refers to the button element itself
this.textContent = "Clicked!";
});
</script>
*/
  • Arrow Function’s Limitation: If an arrow function is used as an event listener, its this will lexically inherit from its surrounding scope, which might not be the element you expect. This is a common gotcha!
// Code example: `this` in an arrow event listener
// (Imagine this running in a browser console)
/*
<button id="myOtherButton">Click Me Too</button>
<script>
// Outside any specific function scope, 'this' would be global (window)
// if this code block isn't wrapped in an outer function.
// Let's assume it's in a global script.
document.getElementById('myOtherButton').addEventListener('click', () => {
console.log(this); // 'this' refers to the 'window' object (or 'undefined' in strict modules)
// NOT the button element
});
</script>
*/

Tags for SEO

#javascript #frontendmaster #html #reacjs

--

--

Frontend Master
Frontend Master

Written by Frontend Master

A decade-long dance with code, sculpting the digital landscape. https://topmate.io/frontendmaster

Responses (2)