Reasons for Creating a Function Without the Name and Assigning It to a Constant Variable

Recently, one of my readers asked me a very interesting question:

Is there any advantage to declaring an unnamed function definition to a const over simply declaring a function?

The first one is called a function expression, and the other is called a function declaration. There's no one-size-fits-all answer; it's all about what you want to achieve with your code.

So, let's discuss how they differ, allowing you to choose the right one based on your needs.

1. Preventing Variable Re-declaration

Using the const keyword when declaring a function in JavaScript helps prevent accidental mistakes. If you declare a function with const and later try to declare another variable with the same name, it will result in an error, alerting you to the issue.

const changeText = () => {
  /* original */
};
// ...
const changeText = () => {
  /* different version */
}; // SyntaxError!

On the other hand, if you use function to declare a function and later declare another function with the same name, it will simply replace the original function without any error.

function changeText() {
  /* original */
}
// ...
function changeText() {
  /* different version */
} // No error, this is your function now

2. Avoiding Global Property Creation

When you use function to declare a function globally, it also creates a global property of the same name. This can lead to conflicts and unexpected behavior.

function changeText() {
  /* ... */
}
console.log(window.changeText); // function changeText

Using const (or let) prevents the creation of these global properties.

const changeText = () => {
  /* ... */
};
console.log(window.changeText); // undefined

Why Avoid Global Variables?

Creating global variables comes with risks. If you have a global variable and later create another variable or function with the same name, they can interfere with each other. This isn't just a concern for your variables but could also impact variables from other scripts or frameworks you're using.

Imagine you create a variable called name that holds information about a person:

var name = { first: "John", last: "Doe" };

Now, if you try to log this variable:

console.log(name); // What do you expect to see?

You might think it would show the person's details, but surprise! It actually shows the string "[object Object]". Why? Well, the variable name becomes a global property, and it can only store string values. So, when you assigned an object to it, JavaScript converted the object to a string and stored it in the global window object.

console.log(typeof name); // Outputs: string

Now, here's where it gets tricky. If you attempt to create a function with the same name name, it doesn't coexist peacefully with the variable. Instead, it completely replaces the global name property. Now, name is a function, not a string.

function name() {}
console.log(name); // Outputs: function name
console.log(typeof name); // Outputs: function

What if you want to create a global function named top? Nope, that won't work because there's already a global top in place.

function top() {} // SyntaxError!

So, the lesson here is to steer clear of working in the global playground.

3. Hoisting:

Function declarations are hoisted, which means they are moved to the top of the code during the compilation phase. This allows you to call the function before it's declared in the code.

// Function Declaration
greet(); // Works
function greet() {
  console.log("Hello!");
}

Unlike function declarations, function expressions are not hoisted to the top of the scope during the compilation phase. This means that you cannot call a function expression before it is declared in your code.

// Function Expression
// greet(); // Error - not yet defined
const greet = () => {
  console.log("Hello!");
};

4. "this" Binding:

In a simple function declaration defined using the function keyword, the this keyword is always set to the global object (e.g., Window in a browser) when the function is invoked without any explicit binding.

// Function Declaration
function greet() {
  console.log(`Function Declaration: Hello, ${this.name}!`);
}

// this refers to the global object (e.g., Window in a browser)
greet(); // Outputs: Function Declaration: Hello, undefined!

The same behavior applies to function expressions defined using the function keyword.

// Function Expression
const greetExpression = function () {
  console.log(`Function Expression: Hello, ${this.name}!`);
};

// this refers to the global object (e.g., Window in a browser)
greetExpression(); // Outputs: Function Expression: Hello, undefined!

If a named function or function expression with the function keyword has been defined in the global scope and is then used as a method of an object, this refers to the object it is contained within.

const obj = {
  name: "Alice",
  greetMethod: greet,
  greetExpressionMethod: greetExpression,
};

// this refers to the object (obj)
obj.greetMethod(); // Outputs: Function Declaration: Hello, Alice!

// this refers to the object (obj)
obj.greetExpressionMethod(); // Outputs: Function Expression: Hello, Alice!

Arrow functions, on the other hand, inherit this from their immediate lexical scope. This means that when arrow functions are used within an object method, the this context remains bound to the object itself, rather than the global object (Window in a browser).

const obj = {
  name: "Alice",

  arrowMethod: () => {
    console.log(`Arrow Function: Hello, ${this.name}!`);
  },
};

// this refers to the object (obj)
obj.arrowMethod(); // Outputs: Arrow Function: Hello, Alice!

Conclusion

Normally, you can use function declarations and function expressions interchangeably. However, there are times when you can select one based on your specific needs.

Choose between function declarations and function expressions with arrow function based on how you want the value of this to behave.

Opt for function declarations when you want the function to be hoisted or function expressions when you want to control hoisting.

Use function declarations if you want to create a function on the global scope, making it available throughout your code. Use function expressions to restrict where the function is available, keep your global scope light, and maintain clean syntax.

Learn Higher-Order Functions

Write code that is easier to understand and maintain.

You've heard about higher-order functions, but every explanation you've come across is either too technical or too vague. You're searching for something clear and practical, with examples that will help you practice and truly master the concept.

Higher-order functions are key to writing better code, essential for your projects, and expected in interviews. But getting started can be tough.

But what if you could? What if you had access to easy-to-understand content that not only explains higher-order functions but also provides hands-on practice? You’d finally feel confident using them in your projects, knowing exactly what they do and how to leverage them effectively.

It’s true, finding the right resources to learn higher-order functions can be challenging… but it doesn’t have to be.

Get my guide, where you’ll:

  • Understand why higher-order functions are worth learning and how they can transform your approach to writing JavaScript.
  • Gain clarity as I break down higher-order functions into simple, everyday language.
  • Master three important higher-order functions: map, filter, and reduce, with plenty of examples to solidify your understanding.
  • Apply your knowledge with real-world examples that demonstrate how these concepts work together, so you can use them easily in your projects or write better code in your interviews.

Get the Guide