Function declarations precedence/overwriting variable declarations? Hoisting? Why?

416 views Asked by At

Snippet 1:

var a; // undefined variable named 'a'
function a(foo) { // a function named 'a'
  var foo = "Hello World";
  console.log(foo);
}
console.log(a); // output is: [Function: a], but why not undefined?

Snippet 2:

function a(foo) { // a function named 'a'
    var foo = "Hello World";
    console.log(foo);
}
var a; // undefined variable named 'a'
console.log(a); // output is: [Function: a], but why not undefined?

I could have just shown Snippet 1 to ask this question - however I showed both just for completeness purposes. I have wrote some brief comments in them as well.

My question is, in both cases, why is the function declaration ‘overwriting’/’shadowing’ or taking ‘precedence’ over the variable declaration? Can someone please explain this behaviour?

I understand that these arguably are the same (from the perspective of the interpreter) in terms of end-result, due to the ‘hoisting’ phenomenon, but why does the function declaration or the variable declaration have precedence over the other when it’s interpreted/parsed by the Javascript engine (during the creation phase)? i.e. which one gets hoisted above the other? I have read it is that the function declaration has precedence over the variable declaration - but why is this the case?

Also, kindly refer to the first code snippet (but this applies to both cases), is the memory location/address of ‘a’ where it’s declared in line 1, and line 6, EXACTLY the same? And since ‘a’, in both places of the code, represents the function declaration, what would be the value of ‘a’ at its memory location/address after parsing line 1 and line 6 during the creation phase? Since function declarations are 'hoisted' above the variable declaration, does that mean that by line 1, 'a's memory address is pointing to the function object 'a', by the end of the creation phase of the execution context?

In both code snippets, ‘var a’ is undefined, so why isnt ‘a’ the value of undefined by the time we reach the execution phase (which has its execution point starting on line 6?) Does the Javascript engine simply say, “Ah, if we allow ‘var a’ to ‘overwrite’ ‘function a() {…}’, it would continue to be undefined and thus be unusable. Whereas, if we allow ‘a’ to represent said function, then at least the user can invoke said function (even prior to its declaration, without getting a reference error)". This is very unlikely to be the case but sounds logical/ideal, maybe?

So, my questions are:

  1. What’s the reason behind why the function declaration is overwriting or having precedence over the variable declaration? Is it something we just accept prima-facie because it's an implementation of the ECMAScript specifications or can we explain this behaviour?

And

  1. If possible, could someone please answer what is happening in memory when this occurs every step of the way?

I have been trying to use my intuition for the last 8 hours (where I ended up spiraling into another dimension of the other peculiarities of JavaScript, but that’s another issue in itself) but I would to know if there is a simple or concrete explanation or answer to this behaviour.

Any help in understanding all of this would be much appreciated.

2

There are 2 answers

11
JLRishe On BEST ANSWER

My question is, in both cases, why is the function declaration ‘overwriting’/’shadowing’ or taking ‘precedence’ over the variable declaration? Can someone please explain this behaviour?

There is only one place in either snippet where the variable a is given a value, and that's the function declaration. The statement var a; means "I announce that a variable named a exists". Since the function declaration is taking care of announcing that it exists and giving it a value, the var a; statement doesn't really have any effect.

In fact, if we refer to Section 10.5.8 of the JavaScript spec, we can see that the end result of this var a; is literally to do nothing because the a variable is already declared by the time the var a; declaration is processed.

I understand that these arguably are the same (from the perspective of the interpreter) in terms of end-result, due to the ‘hoisting’ phenomenon, but why does the function declaration or the variable declaration have precedence over the other when it’s interpreted/parsed by the Javascript engine during the creation phase?

Nothing is taking "precedence" here. There is only one variable named a. var a; does not give a a value, so it has no effect on a's value.

Also, kindly refer to the first code snippet (but this applies to both cases), is the memory location/address of ‘a’ where it’s declared in line 1, and line 6, EXACTLY the same?

There is only one a variable and it only takes on one value, so this question is mostly nonsensical, but in rough terms, the a variable itself would only exist in one place and it would only refer to one value (memory location), which would be the definition of that function.

Since function declarations are 'hoisted' above the variable declaration, does that mean that by line 1, 'a's memory address is pointing to the function object 'a', by the end of the creation phase of the execution context?

My knowledge of the creation phase isn't that great, but in the course of this code's execution, a only ever refers to one value, as I said above.

In both code snippets, ‘var a’ is undefined, so why isn’t ‘a’ the value of undefined by the time we reach the execution phase (which has its execution point starting on line 6?)

See my first and second answers.

What’s the reason behind why the function declaration is overwriting or having precedence over the variable declaration? And

As I've said, it's not taking "precedence", but the reason JavaScript has function hoisting is in order to allow people to call functions from a line in the code before the function's actual definition, similar to how other major languages like C# and Java do.

If possible, could someone please answer what is happening in memory when this occurs every step of the way?

The JavaScript spec doesn't define what happens in memory. It defines the code's external behavior. So this would be an implementation detail and would be engine-specific.

Here is a rough blow by blow of what happens when your code is executed (in both cases):

  1. Create a variable called a and assign it the value of that function you have there.
  2. Check whether there is a variable called a. There already is one, so do nothing.
  3. Execute console.log and pass it the value of a (which is that function)
16
Nina Scholz On

The function declaration gets hoisted before the variable hoisting.

console.log(a);

var a = 42; // assignment

console.log(a);

function a(foo) { // a function named 'a'
  var foo = "Hello World";
  console.log(foo);
}

console.log(a);