DEV Community

Cover image for [Vue 3] Function Expression Vs Function Declaration inside Script Setup
Fotis Adamakis
Fotis Adamakis

Posted on • Edited on • Originally published at fadamakis.com

[Vue 3] Function Expression Vs Function Declaration inside Script Setup

JavaScript is weird. If you’ve spent more than 5 minutes with the language, you already know that. One of the hardest topics to explain to a non front-end engineer is a function expression and the whole idea of functions being first-class citizens.

In Vue, until recently, all the functions were declared inside the methods option, which made this debate irrelevant. But with the introduction of the Composition API in Vue 3, declaring a function is now possible in both ways.

Let’s explore the differences and which one should be used.

tl;dr Same thing, Use Function Declarations for Readability

Function Declarations

A Function Declaration is the traditional or “normal” way of declaring a function in non-functional programming languages. It begins with the function keyword, followed by the name of the function, a pair of parentheses, and finally, a pair of curly braces that enclose the function body.

Here's an example:

    function greet(name) {
      console.log(`Hello, ${name}!`);
    }
Enter fullscreen mode Exit fullscreen mode

One important characteristic of Function Declarations is that they are hoisted to the top of their scope. This means that regardless of where the Function Declaration is written in the code, it will be available to be called anywhere within the same scope.

For example:

    greet("stranger"); // prints "Hello, stranger!"

    function greet(name) {
      console.log(`Hello, ${name}!`);
    }
Enter fullscreen mode Exit fullscreen mode

Even though the greet() function is called before it is defined in the code, the Function Declaration is hoisted to the top of the scope, so the call is valid, and the greeting is logged to the console.

Function Expressions

On the other hand, a Function Expression is an expression that results in a function. It also uses the function keyword, which is assigned to a variable or a property of an object.

Here's an example:

    const greet = function() {
      console.log("Hello!");
    };
Enter fullscreen mode Exit fullscreen mode

or the same example using an arrow function:

    const greet = () => {
      console.log("Hello!");
    };
Enter fullscreen mode Exit fullscreen mode

One key difference between the two is that Function Expressions are not hoisted. They can only be called after they have been defined.

    greet("stranger"); /* "ReferenceError: 
                           Cannot access 'greet' before 
                           initialization  */

    const greet = function(name) {
      console.log(`Hello, ${name}!`);
    }
Enter fullscreen mode Exit fullscreen mode

Function Expressions are also more flexible than Function Declarations, as they can be used in more contexts, such as being passed as arguments to other functions or used as a method of an object.

    <button id="myButton">Click me!</button>

    <script>
      const myButton = document.querySelector('#myButton');

      myButton.addEventListener('click', function() {
        console.log('Button clicked!');
      });
    </script>
Enter fullscreen mode Exit fullscreen mode

There was a time not long ago that Function Expressions were considered superior because they were not polluting the global scope. But thankfully, ES modules are nowadays widely adopted, and this problem is no longer valid.

So are they the same thing? Actually,** YES**! Nowadays, it is actually down to personal preference on which one to choose. And my strong preference is using Function Declarations. To demonstrate why let's review a Vue component using both approaches.

Function declaration:

    <script setup>
    import { debounce } from "debounce";
    import { ref, watch } from "vue";

    const searchTerm = ref("");
    const products = ref([]);

    watch(searchTerm, debounce(performSearch, 600));

    async function performSearch() {
      if (searchTerm.value === "") {
        products.value = [];
            return;
      }
      if (searchTerm.value.length < 2) {
        return;
      }
      const searchUrl = getSearchUrl();
      const response = await (await fetch(searchUrl)).json();
      products.value = response.products;
    }

    function getSearchUrl() {
      const url = "https://dummyjson.com/products/search";
        const params = {
        q: searchTerm.value,
            limit: "5"
      };
      const searchParams = new URLSearchParams(params);
      return `${url}?${searchParams}`;
    };

    function clearSearch() {
      searchTerm.value = "";
      products.value = [];
    }

    </script>
Enter fullscreen mode Exit fullscreen mode

Function expression:

    <script setup>
    import { debounce } from "debounce";
    import { ref, watch } from "vue";

    const searchTerm = ref("");
    const products = ref([]);

    const performSearch = async () => {
      if (searchTerm.value === "") {
        products.value = [];
            return;
      }
      if (searchTerm.value.length < 2) {
        return;
      }

      const searchUrl = getSearchUrl();
      const response = await (await fetch(searchUrl)).json();

      products.value = response.products;
    }

    watch(searchTerm, debounce(performSearch, 600));

    const getSearchUrl = () => {
      const url = "https://dummyjson.com/products/search";
        const params = {
        q: searchTerm.value,
            limit: "5"
      };

      const searchParams = new URLSearchParams(params);
      return `${url}?${searchParams}`;
    };

    const clearSearch = () => {
      searchTerm.value = "";
      products.value = [];
    }

    </script>
Enter fullscreen mode Exit fullscreen mode

As you already know, everything declared inside the script setup is automatically available in the template. And being able to identify methods from the data or computed variables is much easier when using Function Declarations since they all start with the function keyword. The difference is subtle, but after all, the best code is what other people can easily understand.

What is your preference? Leave a comment below.

Top comments (2)

Collapse
 
intermundos profile image
intermundos

Declaration all the way 🚀

Collapse
 
ayii profile image
阿億

I share the same thoughts as you.
However, if we are to use FP currying to define functions, using arrow functions would be even better.
As for addressing readability issues, I later thought that by using the editor's folding feature, we can fold the functions to enhance readability. This way, the visual load difference between using function declarations and arrow function definitions would be much smaller.
But it's undeniable that starting with function is indeed quite recognizable.