5

I'm learning JavaScript, and I feel like I understand hoisting decently enough, so I'm not asking what it is or how to do it or anything like that.

Is it good to hoist? If I can, should I be declaring my variables using

var foo = function() {};

Or should I be using this instead?

function foo() {}

When should I hoist and when should I not? Or does it even matter at all?

Senichi
  • 53
  • 3
  • This question has been asked many times before. I will attempt to find a duplicate. – jfriend00 Apr 21 '15 at 09:19
  • Both of those options hoist the variable/function. – JJJ Apr 21 '15 at 09:19
  • possible duplicate of [var functionName = function() {} vs function functionName() {}](http://stackoverflow.com/questions/336859/var-functionname-function-vs-function-functionname) – JJJ Apr 21 '15 at 09:22

3 Answers3

6

Hoisting is not something you can do or not do, it just happens in JavaScript.

Hoisting is the fact that all variable declarations get 'moved' to the top of the containing scope.

What you are talking about is using function expressions versus function declarations. Both styles are fine, just remember that they have a small difference in what gets hoisted:

var foo = function() {} // foo gets hoisted, but not the function itself

function foo(){}        // the variable and the function get hoisted

For more information you can check out an article I write about hoisting in JavaScript: http://www.kenneth-truyers.net/2013/04/20/javascript-hoisting-explained/

Kenneth
  • 28,294
  • 6
  • 61
  • 84
  • The referenced article claims “If we look at Javascript however, there’s only two scopes: global and function scope.” This is false. Function declarations are block-scoped, as are lexical bindings (i.e. `const` and `let`). A better resource is http://www.2ality.com/2015/02/es6-scoping.html. – Mathias Bynens Apr 21 '15 at 09:40
  • 1
    That is the case for ES6, the article was written for ES5. I have updated the article. – Kenneth Apr 21 '15 at 09:50
  • Thanks! This not only answers my question, but it also clears up a misconception that I had about hoisting. Very helpful – Senichi Apr 21 '15 at 09:54
  • @MathiasBynens do you have any reference on that? AFAIK, block scope does not exist in ES5 – Kenneth Apr 21 '15 at 09:58
  • @Kenneth You’re right, it’s [new in ES6](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-block-level-function-declarations-web-legacy-compatibility-semantics) (even for function declarations). Given that, I stand by [my earlier answer](http://stackoverflow.com/a/29767976/96656): avoid function hoisting whenever possible. – Mathias Bynens Apr 21 '15 at 10:20
  • So, just to be clear, for function expression vs function declaration, should I be using one over the other whenever I can? For example, if I have a completely blank page, and I want a new function, which one should I default to, if any? `var foo = function()` or `function foo()`, or are each weighed equally with their own uses? @Mathias, you're saying avoid function hoisting whenever possible, does that mean I should default to `var foo = function()`? – Senichi Apr 21 '15 at 10:22
  • @Senichi That is my personal preference, yes, and my answer explains why. But to each his own. – Mathias Bynens Apr 21 '15 at 10:27
3

There is no objective answer to this question. It comes down to personal preference.

In my own code, I prefer var foo = function() {};. IMHO, avoiding function hoisting makes the code easier to understand, since the source code order matters.

Update: The ES6/ES2015 spec has the same recommendation for specific cases:

Prior to ECMAScript 2015, the ECMAScript specification did not define the occurrence of a FunctionDeclaration as an element of a Block statement’s StatementList. However, support for that form of FunctionDeclaration was an allowable extension and most browser-hosted ECMAScript implementations permitted them. Unfortunately, the semantics of such declarations differ among those implementations. Because of these semantic differences, existing web ECMAScript code that uses Block level function declarations is only portable among browser implementation if the usage only depends upon the semantic intersection of all of the browser implementations for such declarations.

For example, the behavior of the following code was undefined in ES5 and differs between browsers/engines/implementations:

if (true) {
  function foo() { return 1; }
} else {
  function foo() { return 2; }
}
console.log(foo()); // `1` or `2`?

However, the following code has perfectly well-defined and interoperable behavior:

var foo;
if (true) {
  foo = function() { return 1; }
} else {
  foo = function() { return 2; }
}
console.log(foo()); // `1`

TL;DR Avoid function hoisting whenever you can.

Mathias Bynens
  • 144,855
  • 52
  • 216
  • 248
  • You can't avoid "hoisting", it happens always, you can only change what gets hoisted (only variable or entire function) – Kenneth Apr 21 '15 at 09:23
  • 1
    @Kenneth That is true, but it seems like the OP is already well aware of that, given the examples in his question. In my answer I called out function hoisting specifically, which can definitely be avoided. – Mathias Bynens Apr 21 '15 at 09:24
  • 1
    IMO, the OP did not really understand the concept of hoisting. That's why I explained what hoisting is and how function declarations and expressions influence it. – Kenneth Apr 21 '15 at 09:26
  • Thanks @MathiasBynens, this answered my question. I also thought the question meant more like "should I hoist when I don't need to hoist (yet)?", which is why I came here. – Max Aug 15 '17 at 12:59
0

It is a good practice, to declare all variables at the top of a function, because of hoisting.... (not in ES6).

var foo = function() {}; and function foo() {} are two different things. the first one creates a variable and passes an anonymous function, the second one is 'just' a function.

You can't say, what definitly is the better one. It is depended of the context.

marcel
  • 2,967
  • 1
  • 16
  • 25
  • Could you explain a bit more what you mean by "(not in ES6)"? – JJJ Apr 21 '15 at 09:24
  • in ES6, `let` and `const` are block-scoped. So you should declare them first, when you need them (like in other languages, e.g. Java, C#) – marcel Apr 21 '15 at 09:25