Difference between function expressions, arrow functions, and function declarations

I am having difficulty determining the difference between the following function expressions, arrow functions, and function declarations. Could some one please explain?

3 Likes

Nice question! Here, try this:
https://javascript.info/function-expressions-arrows

I hope this helps =)

2 Likes

To get a grasp on functions in general we need to understand scope as it relates to hoisting. When JS first loads, it makes one pass through the script to find all declared objects.

var a, b, c;

function foo() {

}

The above are declarations. These objects are hoisted to the top of their scope (their containers, as it were). Objects declared inside a function are scoped to that function, so the top of scope for them is local to the function.

Hoisted objects can appear anywhere in the source listing, above or below their first point of reference. In other words, we can write functions at the bottom of the source and call them at the top with no issues.

The same does not apply to expressions. They depend on either a variable assignment or an argument instance in another function. Recall that expressions are values, and values do not get hoisted so function expressions cannot appear after they are first called. They must be above that point.

Function expressions have the same properties as declared functions; that is, they both have a this and an arguments object, and a return. This does not apply to arrow functions, however, which have neither this nor arguments and have relaxed syntax rules in certain cases.

var bar = "BAR";
console.log(foo('bar'));    // <- ["BAR", "bar"]
function foo(bar) {
    return [this.bar, bar];
}

Notice that the call to the function appears before it in the listing yet it still gives a return that can be logged. The this object is window, which is why it also got logged since the varable also exists in global scope.

It’s important to note that the two bar variables are not the same variable. They are in two different scopes, and the local one shadows the global one, hence we need to reach out to the window to access that one.

var bar = "BAR";
console.log(foo('bar'));    // <- ["BAR", "bar"]
function foo(bar) {
    return [window.bar, bar];
}

This may not hit home until the unit on objects, but it bears mention, just the same. Let’s try the same pattern with a function expression…

var bar = "BAR";
console.log(foo('bar'));    // <- Uncaught TypeError: foo is not a function
var foo = function (bar) {
    return [this.bar, bar];
}

and now,

var bar = "BAR";
var foo = function (bar) {
    return [this.bar, bar];
}
console.log(foo('bar'));    // <- ["BAR", "bar"]

Now to try the same code as an arrow function…

var bar = "BAR";
const foo = (bar) => {
    return [this.bar, bar];
}
console.log(foo('bar'));    // <- ["BAR", "bar"]

Of particular note is the this object. It is not in the context of the function, but of the window, and it is that this being accessed, as though it were window.

When you reach objects and DOM events, this will become more clear, and one should wait until then to explore the point further. Focus on syntax, scope and hoisting and keep moving forward with your lessons.


The above in relaxed syntax form…

var bar = "BAR";
const foo = bar => [this.bar, bar];
console.log(foo('bar'));    // <- ["BAR", "bar"]
4 Likes