What function declaration methods do you know and what are their differences?

👨‍💻 Frontend Developer 🟡 Often Asked 🎚️ Medium
#JavaScript #Functions #JS Basics

Brief Answer

JavaScript has 5 main methods for declaring functions:

  1. Function Declaration — function declaration
  2. Function Expression — function expression
  3. Arrow Function — arrow function (ES6)
  4. Method Definition — object method
  5. Constructor Function — constructor function

Key differences:

  • Hoisting (lifting)
  • Context this
  • Syntax and readability
  • Ability to use as constructor

Function Declaration Methods

1. Function Declaration

Classic way of declaring a function.

function greet(name) {
  return `Hello, ${name}!`;
}
 
console.log(greet("Alexander")); // "Hello, Alexander!"

Features:

  • Hoisting — function is available before declaration
  • Creates a named function
  • Can be used as constructor
  • Has its own this context
// Works thanks to hoisting!
console.log(sayHello("World")); // "Hello, World!"
 
function sayHello(name) {
  return `Hello, ${name}!`;
}

2. Function Expression

Function as a variable value.

const greet = function(name) {
  return `Hello, ${name}!`;
};
 
console.log(greet("Alexander")); // "Hello, Alexander!"

Features:

  • No hoisting — available only after declaration
  • Can be anonymous or named
  • Can be used as constructor
  • Has its own this context
// Error! sayHello is not defined
// console.log(sayHello("World")); // ReferenceError
 
const sayHello = function(name) {
  return `Hello, ${name}!`;
};
 
// Named function expression
const factorial = function fact(n) {
  return n <= 1 ? 1 : n * fact(n - 1);
};

3. Arrow Function

Short syntax for functions, introduced in ES6.

// Regular arrow function
const greet = (name) => {
  return `Hello, ${name}!`;
};
 
// Short notation (implicit return)
const greetShort = name => `Hello, ${name}!`;
 
// No&nbsp;parameters
const sayHello = () => "Hello!";
 
// Multiple parameters
const add = (a, b) => a + b;
 
console.log(greet("Alexander")); // "Hello, Alexander!"
console.log(add(5, 3));         // 8

Features:

  • No hoisting
  • Lexical this — inherits context
  • Cannot be used as constructor
  • No own arguments
  • Short syntax
const obj = {
  name: "Alexander",
  
  // Regular function
  regularMethod: function() {
    console.log(this.name); // "Alexander"
    
    const inner = function() {
      console.log(this.name); // undefined (this = window/global)
    };
    inner();
  },
  
  // Arrow function
  arrowMethod: function() {
    console.log(this.name); // "Alexander"
    
    const inner = () => {
      console.log(this.name); // "Alexander" (inherits this)
    };
    inner();
  }
};

4. Method Definition

Short syntax for object methods (ES6).

const person = {
  name: "Alexander",
  age: 30,
  
  // Short method syntax
  greet() {
    return `Hello, I'm ${this.name}!`;
  },
  
  // Equivalent to:
  greetOld: function() {
    return `Hello, I'm ${this.name}!`;
  }
};
 
console.log(person.greet()); // "Hello, I'm Alexander!"

Features:

  • Short syntax
  • Has its own this context
  • Can be used as constructor
  • Supports super in classes

5. Constructor Function

Function for creating objects.

function Person(name, age) {
  this.name = name;
  this.age = age;
  
  this.greet = function() {
    return `Hello, I'm ${this.name}!`;
  };
}
 
// Creating object
const person = new Person("Alexander", 30);
console.log(person.greet()); // "Hello, I'm Alexander!"
 
// Type checking
console.log(person instanceof Person); // true

Features:

  • Called with new operator
  • this points to the created object
  • Automatically returns created object
  • Sets prototype

Comparison of Declaration Methods

MethodHoistingthisConstructorSyntax
Function Declaration✅ YesDynamic✅ Yesfunction name() {}
Function Expression❌ NoDynamic✅ Yesconst name = function() {}
Arrow Function❌ NoLexical❌ Noconst name = () => {}
Method Definition❌ NoDynamic✅ YesmethodName() {}
Constructor Function✅ YesNew object✅ Yesfunction Name() {}

Context this in Functions

Regular Functions

function regularFunction() {
  console.log(this); // depends on&nbsp;call method
}
 
// Global call
regularFunction(); // window (browser) or&nbsp;global (Node.js)
 
// Call as&nbsp;method
const obj = { method: regularFunction };
obj.method(); // obj
 
// Explicit binding
regularFunction.call({ name: "test" }); // { name: "test" }

Arrow Functions

const arrowFunction = () => {
  console.log(this); // always lexical context
};
 
const obj = {
  name: "Alexander",
  
  regularMethod() {
    console.log(this.name); // "Alexander"
    
    const arrow = () => {
      console.log(this.name); // "Alexander" (inherits from regularMethod)
    };
    
    arrow();
  }
};

Practice Tasks

Task 1

console.log(typeof foo);
console.log(typeof bar);
 
function foo() {}
var bar = function() {};
Answer "function" and "undefined" — function declaration is hoisted completely, while var hoists only the declaration.

Task 2

const obj = {
  name: "Alexander",
  
  regular: function() {
    return this.name;
  },
  
  arrow: () => {
    return this.name;
  }
};
 
console.log(obj.regular());
console.log(obj.arrow());
Answer "Alexander" and undefined — arrow function doesn't have its own this and inherits it from the global context.

Task 3

function Person(name) {
  this.name = name;
}
 
const person1 = new Person("Alexander");
const person2 = Person("Maria");
 
console.log(person1);
console.log(person2);
console.log(window.name); // in&nbsp;browser
Answer person1 — Person object with name: "Alexander", person2 — undefined, window.name — "Maria". Without new the function executes in global context.

Task 4

const calculator = {
  value: 0,
  
  add: function(num) {
    this.value += num;
    return this;
  },
  
  multiply: (num) => {
    this.value *= num;
    return this;
  }
};
 
calculator.add(5).multiply(2);
console.log(calculator.value);
Answer Code executes partially with error — method `add(5)` works and increases `value` to 5, but calling `multiply(2)` causes an error because arrow function `multiply` doesn't have access to `this` of calculator object. As a result, `this.value` will be `undefined`, operation `undefined *= 2` gives `NaN`, and method chaining breaks.

Task 5

function createCounter() {
  let count = 0;
  
  return {
    increment: function() {
      count++;
      return count;
    },
    
    decrement: () => {
      count--;
      return count;
    }
  };
}
 
const counter = createCounter();
console.log(counter.increment()); // ?
console.log(counter.decrement()); // ?
Answer 1 and 0 — both functions have access to count variable through closure, function type doesn't affect access to external variables.

Practical Tips

1. Choosing Declaration Method

// For&nbsp;regular functions
function calculateSum(a, b) {
  return a + b;
}
 
// For&nbsp;short functions and&nbsp;callbacks
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
 
// For&nbsp;object methods
const user = {
  name: "Alexander",
  
  greet() {
    return `Hello, ${this.name}!`;
  }
};
 
// For&nbsp;constructors (better to&nbsp;use classes)
class Person {
  constructor(name) {
    this.name = name;
  }
  
  greet() {
    return `Hello, I'm ${this.name}!`;
  }
}

2. When to Use Arrow Functions

// ✅ Good: callbacks and&nbsp;short functions
const users = ['Alexander', 'Maria', 'Ivan'];
const greetings = users.map(name => `Hello, ${name}!`);
 
// ✅ Good: preserving this context
class Timer {
  constructor() {
    this.seconds = 0;
  }
  
  start() {
    setInterval(() => {
      this.seconds++; // this points to&nbsp;Timer instance
    }, 1000);
  }
}
 
// ❌ Bad: object methods
const obj = {
  name: "Alexander",
  greet: () => {
    return `Hello, ${this.name}!`; // this doesn't point to&nbsp;obj
  }
};

3. Avoid Common Mistakes

// ❌ Bad: losing context
const person = {
  name: "Alexander",
  greet() {
    return `Hello, ${this.name}!`;
  }
};
 
const greetFunc = person.greet;
console.log(greetFunc()); // "Hello, undefined!"
 
// ✅ Good: binding context
const boundGreet = person.greet.bind(person);
console.log(boundGreet()); // "Hello, Alexander!"
 
// ✅ Or&nbsp;using arrow function
const arrowGreet = () => person.greet();
console.log(arrowGreet()); // "Hello, Alexander!"

Summary

  • Function Declaration — classic method, hoisted, has dynamic this
  • Function Expression — function as value, not hoisted
  • Arrow Function — short syntax, lexical this, cannot be used as constructor
  • Method Definition — short syntax for object methods
  • Constructor Function — for creating objects (better to use classes)

Key differences:

  • Hoisting affects function availability
  • Context this determines function behavior
  • Syntax affects code readability

Understanding differences between function declaration methods is the foundation for writing quality JavaScript code!


Want more articles on interview preparation? Subscribe to EasyAdvice, bookmark the site and improve yourself every day 💪