JavaScript has 5 main methods for declaring functions:
Key differences:
thisClassic way of declaring a function.
function greet(name) {
return `Hello, ${name}!`;
}
console.log(greet("Alexander")); // "Hello, Alexander!"Features:
this context// Works thanks to hoisting!
console.log(sayHello("World")); // "Hello, World!"
function sayHello(name) {
return `Hello, ${name}!`;
}Function as a variable value.
const greet = function(name) {
return `Hello, ${name}!`;
};
console.log(greet("Alexander")); // "Hello, Alexander!"Features:
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);
};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 parameters
const sayHello = () => "Hello!";
// Multiple parameters
const add = (a, b) => a + b;
console.log(greet("Alexander")); // "Hello, Alexander!"
console.log(add(5, 3)); // 8Features:
this — inherits contextargumentsconst 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();
}
};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:
this contextsuper in classesFunction 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); // trueFeatures:
new operatorthis points to the created object| Method | Hoisting | this | Constructor | Syntax |
|---|---|---|---|---|
| Function Declaration | ✅ Yes | Dynamic | ✅ Yes | function name() {} |
| Function Expression | ❌ No | Dynamic | ✅ Yes | const name = function() {} |
| Arrow Function | ❌ No | Lexical | ❌ No | const name = () => {} |
| Method Definition | ❌ No | Dynamic | ✅ Yes | methodName() {} |
| Constructor Function | ✅ Yes | New object | ✅ Yes | function Name() {} |
this in Functionsfunction regularFunction() {
console.log(this); // depends on call method
}
// Global call
regularFunction(); // window (browser) or global (Node.js)
// Call as method
const obj = { method: regularFunction };
obj.method(); // obj
// Explicit binding
regularFunction.call({ name: "test" }); // { name: "test" }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();
}
};console.log(typeof foo);
console.log(typeof bar);
function foo() {}
var bar = function() {};const obj = {
name: "Alexander",
regular: function() {
return this.name;
},
arrow: () => {
return this.name;
}
};
console.log(obj.regular());
console.log(obj.arrow());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 browserconst 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);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()); // ?// For regular functions
function calculateSum(a, b) {
return a + b;
}
// For short functions and callbacks
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
// For object methods
const user = {
name: "Alexander",
greet() {
return `Hello, ${this.name}!`;
}
};
// For constructors (better to use classes)
class Person {
constructor(name) {
this.name = name;
}
greet() {
return `Hello, I'm ${this.name}!`;
}
}// ✅ Good: callbacks and 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 Timer instance
}, 1000);
}
}
// ❌ Bad: object methods
const obj = {
name: "Alexander",
greet: () => {
return `Hello, ${this.name}!`; // this doesn't point to obj
}
};// ❌ 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 using arrow function
const arrowGreet = () => person.greet();
console.log(arrowGreet()); // "Hello, Alexander!"thisthis, cannot be used as constructorKey differences:
this determines function behaviorUnderstanding 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 💪