Defining Functions in JavaScript

Here I take a look at the not-so-subtle difference between how functions can be defined in JavaScript.

Declarations & Expressions

There are two primary ways of defining functions in JavaScript: function declarations and function expressions. A function expression looks like this:

const sum = function(a, b) {  
  return a + b;
};

It creates a function (function (a, b) { return a + b; }) and uses a lexical declaration to bind it to an identifier (sum).

This is similar to how we define an object (or any other expression):

const object = { a: 1, b: 2 };  

It creates an object ({a: 1, b: 2}) and uses a lexical declaration to bind it to an identifier (object).

In contrast, a function declaration looks like this:

function sum(a, b) {  
  return a + b;
}

What does it do? Like the function expression, it creates a function (function (a, b) { return a + b; }) and binds it to an identifier (sum).

What's the difference? Defining a function using an expression uses the same syntax and semantics that we use for defining all other expressions. It's easy to understand and predictable. In contrast, a function declaration is a special case. It can be used only for declaring functions and comes with its own special syntax. Are you starting to notice a bad smell? Good, let's look at the problems it creates.

No const for You!

Let's say you want to declare a number, string, and object as const:

const number = 42;  
const string = "string";  
const object = { a: 1, b: 2 };  

Now, using a function declaration, you want to declare a function as const:

const function sum(a, b) {  
  return a + b;
}

SyntaxError: Unexpected token function  

Sorry, you can't do that. Cognitive dissonance.

What can you do? Oh yeah, define a function using an expression like you did with the previous three expressions:

const sum = function(a, b) {  
  return a + b;
};

Sorry, Did You Want to Use a Higher-Order Function?

Have you ever defined something using a function? How about defining an escaped string?

const escaped = _.escape(`"<" & other characters will be escaped.`);  

Isn't that easier to read that than defining it like this?

const escaped = '&quot;&lt;&quot; &amp; other characters will be escaped.'  

Of course it is. But now what if similarly you want to use a function while defining a function? If you're using a function expression it's no problem:

const fibonacci = _.memoize(  
  n => (n === 0 || n === 1 ? n : fibonacci(n - 1) + fibonacci(n - 2))
);

Want to do that with a function declaration? Sorry, you're out of luck again. (Don't use _.memoize all that often? What if you're creating a whole library of exported functions for which you want to enable currying with _.curry? Oh, feel the pain!)

this isn't One of the Better Parts

Unlike an arrow function, a function declaration necessarily comes along with the baggage of the this pointer. Douglas Crockford no longer uses this and I don't either.

Hoist Away, Matey!

Functions defined with function declarations are hoisted which means that while sporging you can use them before they're defined.

Oh sorry, did I not define sporging yet? It's OK, I'll define it later but assume that you know what it means for now.

The keywords const and let were introduced in ES 6 to reduce the madness that comes from hoisting with var, which I no longer use at all (and neither should you). Using function declarations allows you to continue the madness.

Warts and All

How did we get into this mess? Function declarations in JavaScript are one of many warts caused by trying to make the language feel more familiar to C++ and Java programmers. Java didn't support first class functions until its 8th version and so required special syntax for declaring functions. JavaScript supported first class functions from its inception.

Using two different syntaxes to define functions creates more cognitive overhead for readers of code, especially when one of the methods is the same used for defining all other expressions. It's also bad because it discourages functional programming at a time when functional programming should be encouraged.

What to Do?

Be kind when you see function declarations because many programmers were trained in languages without first class functions but define your functions with expressions so that it's easier for future programmers to tweak them with compose, pipe, curry, etc.

BTW, sporging is the hobby of attempting to discover the technical reasons behind why hoisting exists in JavaScript and failing.

View or Post Comments