Arrow & Normal function in JavaScript
Arrow & Normal(Annonymous) function Explanation
Let me explain the differences between arrow functions and normal (regular) functions with practical examples.
const person = {
name: "Alice",
age: 25,
// Normal function - 'this' refers to the person object
greetNormal: function() {
console.log(`Hi, I'm ${this.name}`);
},
// Arrow function - 'this' refers to parent scope (window/global)
greetArrow: () => {
console.log(`Hi, I'm ${this.name}`); // 'this.name' will be undefined
}
};
person.greetNormal(); // Output: "Hi, I'm Alice"
person.greetArrow(); // Output: "Hi, I'm undefined"
Practical Example: Event Handlers
class Counter {
constructor() {
this.count = 0;
this.button = document.querySelector('#myButton');
}
// Using normal function - 'this' will refer to the button element
setupWithNormalFunction() {
this.button.addEventListener('click', function() {
this.count++; // ERROR: 'this' is the button, not Counter
console.log(this.count);
});
}
// Using arrow function - 'this' refers to Counter instance
setupWithArrowFunction() {
this.button.addEventListener('click', () => {
this.count++; // WORKS: 'this' is the Counter instance
console.log(this.count);
});
}
}
const counter = new Counter();
counter.setupWithArrowFunction(); // This works correctly
Constructor Functions
// Normal functions can be used as constructors
function Person(name, age) {
this.name = name;
this.age = age;
}
const alice = new Person("Alice", 25); // Works fine
// Arrow functions CANNOT be used as constructors
const PersonArrow = (name, age) => {
this.name = name;
this.age = age;
};
const bob = new PersonArrow("Bob", 30); // ERROR: PersonArrow is not a constructor
Real-World Practical Example: API Calls
class UserService {
constructor() {
this.apiUrl = 'https://api.example.com/users';
this.users = [];
}
// Using arrow function maintains 'this' context
fetchUsers() {
fetch(this.apiUrl)
.then(response => response.json())
.then(data => {
// Arrow function: 'this' still refers to UserService
this.users = data;
console.log(this.users);
})
.catch(error => {
console.error('Error:', error);
});
}
// With normal function, you'd need to bind or use a variable
fetchUsersNormal() {
const self = this; // Store reference to 'this'
fetch(this.apiUrl)
.then(function(response) {
return response.json();
})
.then(function(data) {
// Normal function: 'this' would be undefined in strict mode
// So we use 'self' instead
self.users = data;
console.log(self.users);
});
}
}
Key Points to Remember: Arrow vs Normal Functions
Arrow Functions (=>)
- this is lexically bound – inherits this from parent scope, doesn’t have its own this
- No arguments object – must use rest parameters (…args) instead
- Cannot be used as constructors – can’t use new keyword
- No prototype property
- Cannot be used as generators – can’t use function* syntax
- More concise syntax – especially for single expressions
- Implicit return – for single expressions without {}
- Cannot be hoisted – must be declared before use (behaves like const/let)
Best Use Cases
- Array methods (map, filter, reduce, forEach)
- Callbacks and event listeners in class methods
- Promises and async operations
- Short utility functions
- When you need to preserve parent this
Normal Functions (function)
- this is dynamically bound – depends on how function is called
- Has arguments object – array-like object of all arguments
- Can be used as constructors – works with new keyword
- Has prototype property – for inheritance
- Can be used as generators – function* syntax available
- Function hoisting – can be called before declaration
- Has own this, arguments, super, new.target
Syntax Variations
// Function Declaration (hoisted)
function name(params) {
// statements
}
// Function Expression (not hoisted)
const name = function(params) {
// statements
};
// Anonymous Function
function(params) {
// statements
}
// Named Function Expression
const name = function funcName(params) {
// statements
};
Best Use Cases
- Object methods that need this to refer to the object
- Constructor functions for creating objects
- When you need arguments object
- Methods in prototypes
- When function hoisting is needed
- Recursive named functions
