Function Declarations vs Expressions vs Arrows in JavaScript
Three ways to define functions in JS. Here is how they differ in hoisting, this, and arguments.
Function Declarations vs Expressions vs Arrows in JavaScript
JavaScript has three main ways to define functions. They differ in hoisting, this binding, arguments object, and more.
Function Declaration
function greet(name) { return `Hello, ${name}`; } `` - **Hoisting**: full body. Callable before the line. - **`this`**: determined at call time (default, implicit, explicit, new). - **`arguments`**: has its own `arguments` object. - **`new.target`**: available. - **Constructor**: can be called with `new`. ### Function Expression ```js const greet = function (name) { return `Hello, ${name}`; }; `` - **Hoisting**: variable only (`undefined` with `var`, TDZ with `let`/`const`). - **`this`**: same as declaration (determined at call time). - **`arguments`**: has its own `arguments` object. - **Constructor**: can be called with `new` (if not an arrow). ### Arrow Function ```js const greet = (name) => `Hello, ${name}`; `` - **Hoisting**: variable only (always an expression). - **`this`**: lexical (inherited from the enclosing scope). `call`/`apply`/`bind` cannot change it. - **`arguments`**: no own `arguments` object (references the enclosing function's). - **`new.target`**: not available. - **Constructor**: cannot be called with `new` (throws `TypeError`). - **`super`**: not available. - **`yield`**: not available (cannot be a generator). ### Comparison Table | Feature | Declaration | Expression | Arrow | |---|---|---|---| | Hoisting | Full body | Variable only | Variable only | | `this` | Call time | Call time | Lexical | | `arguments` | Own | Own | Inherited | | `new` | Yes | Yes | No | | `super` | Yes | Yes | No | | `yield` | Yes | Yes | No | ### When to Use Each - **Declaration**: top-level helpers, hoisting needed. - **Expression**: when you need a function as a value, but want `this`/`arguments`/`new`. - **Arrow**: short callbacks, when you want lexical `this` (inside methods, constructors). ### The Takeaway Declarations are hoisted with their body. Expressions are variable-assigned and follow variable hoisting. Arrows are always expressions, have lexical `this`, no `arguments`, and cannot be constructors. Use declarations for hoisting, expressions for `this`/`new`, arrows for lexical `this` and conciseness.
Declarations are hoisted with their full body. Expressions are variable-assigned (variable hoisting only). Arrows are always expressions with lexical this, no arguments object, and cannot be used as constructors.
No. Arrow functions inherit this from their enclosing lexical scope. call, apply, and bind cannot change an arrow's this. This is why arrows fix the this-in-callback bug inside methods and constructors.
No. Arrow functions do not have their own arguments object. If you reference arguments inside an arrow, it refers to the enclosing regular function's arguments. Use rest parameters (...args) in arrows instead.
No. Arrow functions cannot be used as constructors. Calling new ArrowFn() throws TypeError: ArrowFn is not a constructor. They do not have a [[Construct]] internal method.
Use arrows for short callbacks and when you want lexical this (inside methods, constructors). Use regular functions when you need this at call time, the arguments object, or constructor functionality (new).
Ready to master React completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master React
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

