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

Related Posts

What are the HTML5 APIs you know

Here are the major features introduced in ES6 (ECMAScript 2015) Geolocation API – Where…

Read
What are the new features came with ES6 standards

Here are the major features introduced in ES6 (ECMAScript 2015) Variables and Scope let…

Read