2

I'm trying to decide what style to use for module-level function definitions.

Here are the options I've considered:

// function expression using an arrow
const foo = (arg)=> {
    // ...
};


// function expression with the `function` keyword
const bar = function(arg){
    // ...
};


// function declaration
function baz(arg){
    // ...
}

I prefer the foo style, but it seems to be non-standard. Are there considerations against it that I haven't considered? For example, are there significant performance penalties to using function expressions, const, or arrows, either natively or when transpiling?

Here's what I have so far:

Advantages of using const with a function expression instead of using a function declaration:

  • Nothing is ever hoisted if you only use const and let: it makes the language simpler to work with.
  • Using const makes the interpreter throw an error if you try to define two functions with the same name in the same scope (this has been surprisingly helpful).
  • Using const lets you say what you mean: most of the time, one wants to define a function, not assign to a variable.
  • Using const instead of a function declaration makes it clearer that functions are values in JS.

Disadvantages of function expressions:

  • A function declaration causes both the variable declaration and function body to be hoisted to the top of the current function body (I think). This may actually be helpful if you like to lay your JS files out with function-using code on top and function definitions at the bottom.

I couldn't find any cases where function expressions are harder to debug or where it was harder to use recursion with function expressions.

Advantages of using arrows instead of the function keyword:

  • The fat arrow has simpler semantics in this sense. It's probably better to not ask for new values of this and arguments unless they are really needed.
Max Heiber
  • 14,346
  • 12
  • 59
  • 97
  • Why do you think `foo` is non-standard? Also, are you sure that hoisting is relevant if you are worrying about "module-level function definitions"? –  Dec 23 '15 at 06:20
  • Don't forget that both of those `const` function declarations are anonymous, so they won't have a name in stack traces (personally I don't care about that, because I have a *debugger* ;)) but a lot of people do. – CodingIntrigue Dec 23 '15 at 08:27
  • @RGraham: The ES6 spec says that a function expression's name should be set to the variable name if the function is assigned to a variable. – Felix Kling Dec 23 '15 at 10:27
  • @FelixKling I thought that was just something Babel did. I see it in the spec now, thanks (again!) – CodingIntrigue Dec 23 '15 at 10:37
  • 1
    How does function hoisting make the language harder to work with??? – Bergi Dec 23 '15 at 11:11
  • @torazaburo, I just haven't seen the first style too often. Glad to hear it's probably not non-standard. I think hoisting is relevant, and not necessarily a bad thing in this case. If you use a function declaration, the function is available even to code defined before the function. – Max Heiber Dec 24 '15 at 03:40
  • @Bergi, I guess hoisting isn't a negative in this case. `var` can definitely be confusing, but function declarations aren't. – Max Heiber Dec 24 '15 at 03:52
  • Your question is inconsistent. In the first line, you refer to "module-level functions". Then later, you you refer to "hoisted to the top of the current function body". Which is it--module-level functions, or functions within other functions? The hoisting behavior is different in these two cases. –  Dec 24 '15 at 05:17
  • @torazaburo I usually use Browserify, which wraps modules in functions. But I guess I should have said "hoisted to the top of the current scope." – Max Heiber Dec 24 '15 at 21:13
  • See also https://stackoverflow.com/questions/38479859/what-are-the-advantages-disadvantages-for-creating-a-top-level-function-in-es6 – Bergi Jan 02 '22 at 19:00

0 Answers0