11

I'm having a bit of trouble understanding why my code works. I'm expecting a reference error, but everything works fine.

My code:

const functionA = () => {
  let bResult = functionB();

  console.log("Function A " + bResult);
};

const functionB = () => {
  return "Function B";
};

functionA();

I get this output (no errors);

λ node test.js
Function A Function B

As I understand it, only function declarations are hoisted (not function expressions) http://adripofjavascript.com/blog/drips/variable-and-function-hoisting.html.

Thus, shouldn't I expect an error as FunctionB isn't defined before it's called in FunctionA? Am I missing somewhere here?

EDIT: Thanks for the answers everyone, I think I figured it out. It's indeed not getting hoisted because if I call functionA at the beginning, it gives me an error.

functionA(); // ReferenceError: functionA is not defined

const functionA = () => {
  let bResult = functionB();

  console.log("Function A " + bResult);
};

const functionB = () => {
  return "Function B";
};

So it's not a question of hoisting. Rather, by the time functionA is called at the end of the file, both functionA and functionB have been defined.

Jason
  • 412
  • 1
  • 6
  • 13
  • 8
    by the time `functionA` is actually executed, `functionB` will be set. So this works just fine. It would be terribly annoying if you had to define all of your functions "in order". Not to mention, [mutual recursion](https://en.wikipedia.org/wiki/Mutual_recursion) depends on this behavior. – Mulan Feb 28 '19 at 20:27
  • @user633183 `functionB` is set, but it's referred to in `functionA` before it's defined. Why doesn't it need to be defined in advance given that it isn't hoisted – m0meni Feb 28 '19 at 20:29
  • Try doing: `const functionA = () => {..}; functionA(); const functionB = () => {..}` – adiga Feb 28 '19 at 20:29
  • @m0meni when a function is defined, the code inside isn't run until it's called – adiga Feb 28 '19 at 20:31
  • That article is specific to `var`, so this might be more useful [var vs. let](https://stackoverflow.com/questions/762011/whats-the-difference-between-using-let-and-var-to-declare-a-variable-in-jav) – crashmstr Feb 28 '19 at 20:31
  • 2
    @m0meni because `functionB` is hoisted and the _identifier_ is available immediately. However, the _value_ for `functionB` is not ready to use until `functionB` is actually defined. Adiga's comment about running `functionA()` before the `functionB = ...` will show the "problematic" behavior. – Mulan Feb 28 '19 at 20:32
  • So the right answer is that the base assumption of the post is wrong, and that arrow functions are hoisted – m0meni Feb 28 '19 at 20:33
  • 1
    @m0meni precisely – Mulan Feb 28 '19 at 20:33
  • @Bergi that question seems totally unrelated. This person was asking about whether arrow functions and functions behave differently or not, not whether let and var hoist differently. – Marie Feb 28 '19 at 20:38
  • @m0meni No, arrow functions are expressions and have nothing to do with hoisting. Variable declarations, on the other hand, are hoisted (as is even explained in the blog post, which is surprisingly good), only without their initialisation. – Bergi Feb 28 '19 at 20:39
  • @Marie It seems the OP is confused that the `const` declaration is hoisted as well, since the article (pre-ES6) only talks about `var` being hoisted. – Bergi Feb 28 '19 at 20:40
  • They are definitely confused about hoisting but that question does not help them at all – Marie Feb 28 '19 at 20:41
  • @Marie Feel free to vote to reopen. I'll retract my closure vote if the OP himself comments that he found it not helpful – Bergi Feb 28 '19 at 20:44
  • This has little to do with hoisting tbh. A variable called `functionA` which is a function is created. The contents of it are irrelevant because they are not actually run until it's called. Then another variable called `functionB` is created. Then `functionA` is executed. Inside it, a function called `functionB` is sought and it is actually available in the scope. So, it's executed. – adiga Feb 28 '19 at 20:44

1 Answers1

5

As someone else pointed out, by the time functionA is called, functionB is now loaded into memory.

Compare the following:

const functionA = functionB;

const functionB = () => {
  return "Function B";
};

functionA();

This will throw 'Uncaught ReferenceError: functionB is not defined'

Compare that behavior to this:

const functionA = functionB

function functionB(){
  return "Function B";
};

functionA();

The second one actually works, because functionB is hoisted above your constant declaration.

Brenn
  • 1,364
  • 1
  • 12
  • 22
  • I hope you don't mind the edit. I was writing it as a separate answer but the question was closed before I could finish it. – Mulan Feb 28 '19 at 20:41
  • 1
    @user633183 I've rolled back the edit as it was incorrect about how hoisting works. – Brenn Mar 01 '19 at 01:34